504 lines
16 KiB
PHP
504 lines
16 KiB
PHP
|
<?php
|
||
|
require_once "model".DIR."Category.php";
|
||
|
|
||
|
class Categorize extends Modules {
|
||
|
# Array: $caches
|
||
|
# Query caches for methods.
|
||
|
private $caches = array();
|
||
|
|
||
|
public static function __install(): void {
|
||
|
Category::install();
|
||
|
|
||
|
Group::add_permission("manage_categorize", "Manage Categories");
|
||
|
Route::current()->add("category/(name)/", "category");
|
||
|
}
|
||
|
|
||
|
public static function __uninstall($confirm): void {
|
||
|
if ($confirm)
|
||
|
Category::uninstall();
|
||
|
|
||
|
Group::remove_permission("manage_categorize");
|
||
|
Route::current()->remove("category/(name)/");
|
||
|
}
|
||
|
|
||
|
public function list_permissions($names = array()): array {
|
||
|
$names["manage_categorize"] = __("Manage Categories", "categorize");
|
||
|
return $names;
|
||
|
}
|
||
|
|
||
|
public function feed_item($post, $feed): void {
|
||
|
if (!empty($post->category))
|
||
|
$feed->category(
|
||
|
$post->category->clean,
|
||
|
url("category", MainController::current()),
|
||
|
$post->category->name
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function related_posts($ids, $post, $limit): array {
|
||
|
if (empty($post->category_id))
|
||
|
return $ids;
|
||
|
|
||
|
$results = SQL::current()->select(
|
||
|
tables:"post_attributes",
|
||
|
fields:array("post_id"),
|
||
|
conds:array(
|
||
|
"name" => "category_id",
|
||
|
"value" => $post->category_id,
|
||
|
"post_id !=" => $post->id
|
||
|
),
|
||
|
order:array("post_id DESC"),
|
||
|
limit:$limit
|
||
|
)->fetchAll();
|
||
|
|
||
|
foreach ($results as $result)
|
||
|
$ids[] = $result["post_id"];
|
||
|
|
||
|
return $ids;
|
||
|
}
|
||
|
|
||
|
public function parse_urls($urls): array {
|
||
|
$urls['|/category/([^/]+)/|'] = '/?action=category&name=$1';
|
||
|
return $urls;
|
||
|
}
|
||
|
|
||
|
public function manage_posts_column_header(): string {
|
||
|
return '<th class="post_category value">'.
|
||
|
__("Category", "categorize").'</th>';
|
||
|
}
|
||
|
|
||
|
public function manage_posts_column($post): string {
|
||
|
$td = '<td class="post_category value">';
|
||
|
|
||
|
if (isset($post->category->name))
|
||
|
$td.= '<a href="'.
|
||
|
url("manage_category/query/".urlencode("id:".$post->category->id)).
|
||
|
'">'.
|
||
|
$post->category->name.
|
||
|
'</a>';
|
||
|
|
||
|
$td.= '</td>';
|
||
|
|
||
|
return $td;
|
||
|
}
|
||
|
|
||
|
public function post_options($fields, $post = null): array {
|
||
|
$options[0]["value"] = "0";
|
||
|
$options[0]["name"] = __("[None]", "categorize");
|
||
|
$options[0]["selected"] = empty($post->category_id);
|
||
|
|
||
|
foreach (Category::find() as $category) {
|
||
|
$name = oneof($category->name, __("[Untitled]"));
|
||
|
$selected = (isset($post) and ($post->category_id == $category->id));
|
||
|
|
||
|
$options[$category->id]["value"] = $category->id;
|
||
|
$options[$category->id]["name"] = $name;
|
||
|
$options[$category->id]["selected"] = $selected;
|
||
|
}
|
||
|
|
||
|
$fields[] = array(
|
||
|
"attr" => "option[category_id]",
|
||
|
"label" => __("Category", "categorize"),
|
||
|
"help" => "categorizing_posts",
|
||
|
"type" => "select",
|
||
|
"options" => $options
|
||
|
);
|
||
|
|
||
|
return $fields;
|
||
|
}
|
||
|
|
||
|
public function post($post): void {
|
||
|
if (!empty($post->category_id)) {
|
||
|
$category = new Category($post->category_id);
|
||
|
|
||
|
if (!$category->no_results)
|
||
|
$post->category = $category;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private function get_category_post_count($category_id): int {
|
||
|
if (!isset($this->caches["category_post_counts"])) {
|
||
|
$counts = SQL::current()->select(
|
||
|
tables:"post_attributes",
|
||
|
fields:array("COUNT(value) AS total", "value AS category_id"),
|
||
|
conds:array("name" => "category_id"),
|
||
|
group:"value"
|
||
|
)->fetchAll();
|
||
|
|
||
|
$this->caches["category_post_counts"] = array();
|
||
|
|
||
|
foreach ($counts as $count) {
|
||
|
$id = $count["category_id"];
|
||
|
$total = (int) $count["total"];
|
||
|
$this->caches["category_post_counts"][$id] = $total;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fallback($this->caches["category_post_counts"][$category_id], 0);
|
||
|
}
|
||
|
|
||
|
public function category_post_count_attr($attr, $category): int {
|
||
|
if ($category->no_results)
|
||
|
return 0;
|
||
|
|
||
|
return $this->get_category_post_count($category->id);
|
||
|
}
|
||
|
|
||
|
public function twig_context_main($context): array {
|
||
|
$context["categorize"] = array();
|
||
|
|
||
|
foreach (Category::find() as $category) {
|
||
|
if ($category->show_on_home)
|
||
|
$context["categorize"][] = $category;
|
||
|
}
|
||
|
|
||
|
return $context;
|
||
|
}
|
||
|
|
||
|
public function main_category($main): bool {
|
||
|
if (!isset($_GET['name'])) {
|
||
|
$reason = __("You did not specify a category.", "categorize");
|
||
|
|
||
|
$main->display(
|
||
|
array("pages".DIR."category","pages".DIR."index"),
|
||
|
array("reason" => $reason),
|
||
|
__("Invalid Category", "categorize")
|
||
|
);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
$category = new Category(
|
||
|
array("clean" => $_GET['name'])
|
||
|
);
|
||
|
|
||
|
if ($category->no_results) {
|
||
|
$reason = __("The category you specified was not found.", "categorize");
|
||
|
|
||
|
$main->display(
|
||
|
array("pages".DIR."category","pages".DIR."index"),
|
||
|
array("reason" => $reason),
|
||
|
__("Invalid Category", "categorize")
|
||
|
);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
$results = SQL::current()->select(
|
||
|
tables:"post_attributes",
|
||
|
fields:array("post_id"),
|
||
|
conds:array(
|
||
|
"name" => "category_id",
|
||
|
"value" => $category->id
|
||
|
)
|
||
|
)->fetchAll();
|
||
|
|
||
|
$ids = array();
|
||
|
|
||
|
foreach ($results as $result)
|
||
|
$ids[] = $result["post_id"];
|
||
|
|
||
|
if (empty($ids)) {
|
||
|
$reason = __("There are no posts in the category you specified.", "categorize");
|
||
|
|
||
|
$main->display(
|
||
|
array("pages".DIR."category", "pages".DIR."index"),
|
||
|
array("reason" => $reason),
|
||
|
__("Invalid Category", "categorize")
|
||
|
);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
$posts = new Paginator(
|
||
|
Post::find(
|
||
|
array(
|
||
|
"placeholders" => true,
|
||
|
"where" => array("id" => $ids)
|
||
|
)
|
||
|
),
|
||
|
$main->post_limit
|
||
|
);
|
||
|
|
||
|
if (empty($posts))
|
||
|
return false;
|
||
|
|
||
|
$main->display(
|
||
|
array("pages".DIR."category", "pages".DIR."index"),
|
||
|
array(
|
||
|
"posts" => $posts,
|
||
|
"category" => $category->name
|
||
|
),
|
||
|
_f("Posts in category “%s”", fix($category->name), "categorize")
|
||
|
);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public function manage_nav($navs): array {
|
||
|
if (Visitor::current()->group->can("manage_categorize"))
|
||
|
$navs["manage_category"] = array(
|
||
|
"title" => __("Categories", "categorize"),
|
||
|
"selected" => array(
|
||
|
"new_category",
|
||
|
"delete_category",
|
||
|
"edit_category"
|
||
|
)
|
||
|
);
|
||
|
|
||
|
return $navs;
|
||
|
}
|
||
|
|
||
|
public function admin_determine_action($action): ?string {
|
||
|
$visitor = Visitor::current();
|
||
|
|
||
|
if ($action == "manage" and $visitor->group->can("manage_categorize"))
|
||
|
return "manage_category";
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public function admin_manage_category($admin): void {
|
||
|
if (!Visitor::current()->group->can("manage_categorize"))
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("You do not have sufficient privileges to manage categories.", "categorize")
|
||
|
);
|
||
|
|
||
|
# Redirect searches to a clean URL or dirty GET depending on configuration.
|
||
|
if (isset($_POST['query']))
|
||
|
redirect(
|
||
|
"manage_category/query/".
|
||
|
str_ireplace("%2F", "", urlencode($_POST['query'])).
|
||
|
"/"
|
||
|
);
|
||
|
|
||
|
fallback($_GET['query'], "");
|
||
|
list($where, $params, $order) = keywords(
|
||
|
$_GET['query'],
|
||
|
"name LIKE :query",
|
||
|
"categorize"
|
||
|
);
|
||
|
|
||
|
$categorize = Category::find(
|
||
|
array(
|
||
|
"where" => $where,
|
||
|
"params" => $params,
|
||
|
"order" => $order
|
||
|
)
|
||
|
);
|
||
|
|
||
|
$admin->display(
|
||
|
"pages".DIR."manage_category",
|
||
|
array("categorize" => $categorize)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function admin_new_category($admin): void {
|
||
|
if (!Visitor::current()->group->can("manage_categorize"))
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("You do not have sufficient privileges to add categories.", "categorize")
|
||
|
);
|
||
|
|
||
|
$admin->display("pages".DIR."new_category");
|
||
|
}
|
||
|
|
||
|
public function admin_add_category($admin)/*: never */ {
|
||
|
if (!Visitor::current()->group->can("manage_categorize"))
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("You do not have sufficient privileges to add categories.", "categorize")
|
||
|
);
|
||
|
|
||
|
if (!isset($_POST['hash']) or !Session::check_token($_POST['hash']))
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("Invalid authentication token.")
|
||
|
);
|
||
|
|
||
|
if (empty($_POST['name']))
|
||
|
error(
|
||
|
__("No Name Specified", "categorize"),
|
||
|
__("A name is required to add a category.", "categorize"),
|
||
|
code:400
|
||
|
);
|
||
|
|
||
|
$clean = empty($_POST['clean']) ?
|
||
|
$_POST['name'] :
|
||
|
$_POST['clean'] ;
|
||
|
|
||
|
$clean = sanitize($clean, true, true);
|
||
|
|
||
|
if (!preg_match("/[^\-0-9]+/", $clean))
|
||
|
$clean = md5($clean);
|
||
|
|
||
|
$clean = Category::check_clean($clean);
|
||
|
|
||
|
Category::add(
|
||
|
name:$_POST['name'],
|
||
|
clean:$clean,
|
||
|
show_on_home:!empty($_POST['show_on_home'])
|
||
|
);
|
||
|
|
||
|
Flash::notice(
|
||
|
__("Category added.", "categorize"),
|
||
|
"manage_category"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function admin_edit_category($admin): void {
|
||
|
if (empty($_GET['id']) or !is_numeric($_GET['id']))
|
||
|
error(
|
||
|
__("No ID Specified"),
|
||
|
__("An ID is required to edit a category.", "categorize"),
|
||
|
code:400
|
||
|
);
|
||
|
|
||
|
$category = new Category($_GET['id']);
|
||
|
|
||
|
if ($category->no_results)
|
||
|
Flash::warning(
|
||
|
__("Category not found.", "categorize"),
|
||
|
"manage_category"
|
||
|
);
|
||
|
|
||
|
if (!$category->editable())
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("You do not have sufficient privileges to edit this category.", "categorize")
|
||
|
);
|
||
|
|
||
|
$admin->display(
|
||
|
"pages".DIR."edit_category",
|
||
|
array("category" => $category)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function admin_update_category($admin)/*: never */ {
|
||
|
if (!isset($_POST['hash']) or !Session::check_token($_POST['hash']))
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("Invalid authentication token.")
|
||
|
);
|
||
|
|
||
|
if (empty($_POST['id']) or !is_numeric($_POST['id']))
|
||
|
error(
|
||
|
__("No ID Specified"),
|
||
|
__("An ID is required to update a category.", "categorize"),
|
||
|
code:400
|
||
|
);
|
||
|
|
||
|
if (empty($_POST['name']))
|
||
|
error(
|
||
|
__("No Name Specified", "categorize"),
|
||
|
__("A name is required to update a category.", "categorize"),
|
||
|
code:400
|
||
|
);
|
||
|
|
||
|
$category = new Category($_POST['id']);
|
||
|
|
||
|
if ($category->no_results)
|
||
|
show_404(
|
||
|
__("Not Found"),
|
||
|
__("Category not found.", "categorize")
|
||
|
);
|
||
|
|
||
|
if (!$category->editable())
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("You do not have sufficient privileges to edit this category.", "categorize")
|
||
|
);
|
||
|
|
||
|
$clean = empty($_POST['clean']) ?
|
||
|
$_POST['name'] :
|
||
|
$_POST['clean'] ;
|
||
|
|
||
|
if ($clean != $category->clean) {
|
||
|
$clean = sanitize($clean, true, true);
|
||
|
|
||
|
if (!preg_match("/[^\-0-9]+/", $clean))
|
||
|
$clean = md5($clean);
|
||
|
|
||
|
$clean = Category::check_clean($clean);
|
||
|
}
|
||
|
|
||
|
$category = $category->update(
|
||
|
name:$_POST['name'],
|
||
|
clean:$clean,
|
||
|
show_on_home:!empty($_POST['show_on_home'])
|
||
|
);
|
||
|
|
||
|
Flash::notice(
|
||
|
__("Category updated.", "categorize"),
|
||
|
"manage_category"
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function admin_delete_category($admin): void {
|
||
|
if (empty($_GET['id']) or !is_numeric($_GET['id']))
|
||
|
error(
|
||
|
__("No ID Specified"),
|
||
|
__("An ID is required to delete a category.", "categorize"),
|
||
|
code:400
|
||
|
);
|
||
|
|
||
|
$category = new Category($_GET['id']);
|
||
|
|
||
|
if ($category->no_results)
|
||
|
Flash::warning(
|
||
|
__("Category not found.", "categorize"),
|
||
|
"manage_category"
|
||
|
);
|
||
|
|
||
|
if (!$category->deletable())
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("You do not have sufficient privileges to delete this category.", "categorize")
|
||
|
);
|
||
|
|
||
|
$admin->display(
|
||
|
"pages".DIR."delete_category",
|
||
|
array("category" => $category)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
public function admin_destroy_category()/*: never */ {
|
||
|
if (!isset($_POST['hash']) or !Session::check_token($_POST['hash']))
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("Invalid authentication token.")
|
||
|
);
|
||
|
|
||
|
if (empty($_POST['id']) or !is_numeric($_POST['id']))
|
||
|
error(
|
||
|
__("No ID Specified"),
|
||
|
__("An ID is required to delete a category.", "categorize"),
|
||
|
code:400
|
||
|
);
|
||
|
|
||
|
if (!isset($_POST['destroy']) or $_POST['destroy'] != "indubitably")
|
||
|
redirect("manage_category");
|
||
|
|
||
|
$category = new Category($_POST['id']);
|
||
|
|
||
|
if ($category->no_results)
|
||
|
show_404(
|
||
|
__("Not Found"),
|
||
|
__("Category not found.", "categorize")
|
||
|
);
|
||
|
|
||
|
if (!$category->deletable())
|
||
|
show_403(
|
||
|
__("Access Denied"),
|
||
|
__("You do not have sufficient privileges to delete this category.", "categorize")
|
||
|
);
|
||
|
|
||
|
Category::delete($category->id);
|
||
|
Flash::notice(
|
||
|
__("Category deleted.", "categorize"),
|
||
|
"manage_category"
|
||
|
);
|
||
|
}
|
||
|
}
|