[ 'mod_only' => ['only' => ['mass_edit', 'edit_preview']], 'member_only' => ['only' => ['update', 'edit']] ] ]; } public function cloud() { $this->tags = Tag::where("post_count > 0")->order("post_count DESC")->limit(100)->take()->sort(function ($a, $b) { $a_name = strlen($a->name); $b_name = strlen($b->name); if ($a_name == $b_name) return 0; return ($a_name < $b_name) ? -1 : 1; }); } # Generates list of tag names matching parameter term. # Used by jquery.ui.autocomplete. public function autocompleteName() { $this->tags = Tag::where('name LIKE ?', '%' . $this->params()->term . '%')->pluck('name'); # MI: RoR can respond to requests by reading the "Accept" request header. So even though # the request URL doesn't have the .json extension, it will respond JSON if the request accepts # it. But this is not the case here, so this action will always respond JSON. $this->render(['json' => $this->tags]); } public function summary() { if ($this->params()->version) { # HTTP caching is unreliable for XHR. If a version is supplied, and the version # hasn't changed since then, return; an empty response. $version = Tag::get_summary_version(); if ((int)$this->params()->version == $version) { $this->render(array('json' => array('version' => $version, 'unchanged' => true))); return; } } # This string is already JSON-encoded, so don't call toJson. $this->render(array('json' => Tag::get_json_summary())); } public function index() { $this->set_title('Tags'); if ($this->params()->limit === "0") $limit = null; elseif (!$this->params()->limit) $limit = 50; else $limit = (int)$this->params()->limit; switch ($this->params()->order) { case "name": $order = "name"; break; case "count": $order = "post_count desc"; break; case "date": $order = "id desc"; break; default: $order = "name"; break; } $query = Tag::where("true"); // $cond_params = array(); if ($this->params()->name) { // $conds[] = "name LIKE ?"; if (is_int(strpos($this->params()->name, '*'))) $query->where('name LIKE ?', str_replace('*', '%', $this->params()->name)); else $query->where('name LIKE ?', '%' . str_replace('*', '%', $this->params()->name) . '%'); } if (ctype_digit($this->params()->type)) { $this->params()->type = (int)$this->params()->type; $query->where('tag_type = ?', $this->params()->type); } if (!empty($this->params()->after_id)) { $query->where('id >= ?', $this->params()->after_id); } if (!empty($this->params()->id)) { $query->where('id = ?', $this->params()->id); } $query->order($order); $this->respondTo(array( 'html' => function () use ($order, $query) { $this->can_delete_tags = CONFIG()->enable_tag_deletion && current_user()->is_mod_or_higher(); $this->tags = $query->paginate($this->page_number(), 50); }, 'xml' => function () use ($order, $limit, $query) { // $conds = implode(" AND ", $conds); // if ($conds == "true" && CONFIG()->web_server == "nginx" && file_exists(Rails::publicPath()."/tags.xml")) { // # Special case: instead of rebuilding a list of every tag every time, cache it locally and tell the web // # server to stream it directly. This only works on Nginx. // $this->response()->headers()->add("X-Accel-Redirect", Rails::publicPath() . "/tags.xml"); // $this->render(array('nothing' => true)); // } else { $this->render(array('xml' => $query->limit($limit)->take(), 'root' => "tags")); // } }, 'json' => function () use ($order, $limit, $query) { $tags = $query->limit($limit)->take(); $this->render(array('json' => $tags)); } )); } public function massEdit() { $this->set_title('Mass Edit Tags'); if ($this->request()->isPost()) { if (!$this->params()->start) { $this->respond_to_error("Start tag missing", ['#mass_edit'], ['status' => 424]); return; } if (CONFIG()->is_job_task_active('mass_tag_edit')) { $task = JobTask::create(['task_type' => "mass_tag_edit", 'status' => "pending", 'data' => ["start_tags" => $this->params()->start, "result_tags" => $this->params()->result, "updater_id" => $this->current_user->id, "updater_ip_addr" => $this->request()->remoteIp()]]); $this->respond_to_success("Mass tag edit job created", 'job_task#index'); } else { Tag::mass_edit($this->params()->start, $this->params()->result, current_user()->id, $this->request()->remoteIp()); } } } public function editPreview() { list($sql, $params) = Post::generate_sql($this->params()->tags, ['order' => "p.id DESC", 'limit' => 500]); $this->posts = Post::findBySql($sql, $params); $this->setLayout(false); } public function edit() { if ($this->params()->id) { $this->tag = Tag::where(['id' => $this->params()->id])->first() ?: new Tag(); } else { $this->tag = Tag::where(['name' => $this->params()->name])->first() ?: new Tag(); } } public function update() { $tag = Tag::where(['name' => $this->params()->tag['name']])->first(); if ($tag) $tag->updateAttributes($this->params()->tag); $this->respond_to_success("Tag updated", '#index'); } public function related() { if ($this->params()->type) { $this->tags = Tag::scan_tags($this->params()->tags); $this->tags = TagAlias::to_aliased($this->tags); $all = []; $tag_type = CONFIG()->tag_types[$this->params()->type]; foreach ($this->tags as $x) { $all[$x] = array_map(function($y) use ($x) { return [$y["name"], $y["post_count"]]; }, Tag::calculate_related_by_type($x, $tag_type)); } $this->tags = $all; } else { $tags = Tag::scan_tags($this->params()->tags); $this->patterns = $this->tags = []; foreach ($tags as $tag) { if (is_int(strpos($tag, "*"))) $this->patterns[] = $tag; else $this->tags[] = $tag; } unset($tags, $tag); $this->tags = TagAlias::to_aliased($this->tags); $all = []; foreach ($this->tags as $x) { $all[$x] = array_map(function($y) { return [$y[0], $y[1]]; }, Tag::find_related($x)); } $this->tags = $all; foreach ($this->patterns as $x) { $this->tags[$x] = array_map(function($y) { return [$y->name, $y->post_count]; }, Tag::where("name LIKE ?", '%' . $x . '%')->first()); } } $this->respondTo([ // fmt.xml do // # We basically have to do this by hand. // builder = Builder::XmlMarkup.new('indent' => 2) // builder.instruct! // xml = builder.tag!("tags") do // $this->tags.each do |parent, related| // builder.tag!("tag", 'name' => parent) do // related.each do |tag, count| // builder.tag!("tag", 'name' => tag, 'count' => count) // end // end // end // end // $this->render(array('xml' => xml) // end 'json' => function() { $this->render(['json' => json_encode($this->tags)]); } ]); } public function popularByDay() { if (!$this->params()->year || !$this->params()->month || !$this->params()->day || !($this->day = @strtotime($this->params()->year . '-' . $this->params()->month . '-' . $this->params()->day))) { $this->day = strtotime('this day'); } $this->tags = Tag::count_by_period(date('Y-m-d', $this->day), date('Y-m-d', strtotime('+1 day', $this->day))); } public function popularByWeek() { if (!$this->params()->year || !$this->params()->month || !$this->params()->day || !($this->start = strtotime('this week', @strtotime($this->params()->year . '-' . $this->params()->month . '-' . $this->params()->day)))) { $this->start = strtotime('this week'); } $this->end = strtotime('next week', $this->start); $this->tags = Tag::count_by_period(date('Y-m-d', $this->start), date('Y-m-d', $this->end)); } public function popularByMonth() { if (!$this->params()->year || !$this->params()->month || !($this->start = @strtotime($this->params()->year . '-' . $this->params()->month . '-01'))) { $this->start = strtotime('first day of this month'); } $this->end = strtotime('+1 month', $this->start); $this->tags = Tag::count_by_period(date('Y-m-d', $this->start), date('Y-m-d', $this->end)); } // public function show() // { // begin // name = Tag.find($this->params()->id, 'select' => :name).name // rescue // raise ActionController::RoutingError.new('Not Found') } // redirectTo 'controller' => :wiki, 'action' => :show, 'title' => name // } public function delete() { if (!CONFIG()->enable_tag_deletion) { $this->respond_to_error('Access denied', '#index'); return; } $tag = Tag::find($this->params()->id); if ($tag) $tag->destroy(); $opts = $this->params()->get(); unset($opts['id']); array_unshift($opts, '#index'); $this->respond_to_success('Tag deleted', $opts); } }