From 32d37254f744389a05f828e6c7462147cda52ebf Mon Sep 17 00:00:00 2001 From: Matthew Barbour Date: Tue, 25 Jun 2019 18:47:06 -0500 Subject: [PATCH] New trash extension. For undelete-type stuff. --- core/event.php | 2 + core/send_event.php | 4 ++ ext/pools/main.php | 52 +++++++------- ext/trash/main.php | 164 ++++++++++++++++++++++++++++++++++++++++++++ ext/trash/theme.php | 14 ++++ 5 files changed, 207 insertions(+), 29 deletions(-) create mode 100644 ext/trash/main.php create mode 100644 ext/trash/theme.php diff --git a/core/event.php b/core/event.php index 292da5bf..349a6ce0 100644 --- a/core/event.php +++ b/core/event.php @@ -6,6 +6,8 @@ */ abstract class Event { + public $stop_processing = false; + public function __construct() { } diff --git a/core/send_event.php b/core/send_event.php index 6903a03c..3420df05 100644 --- a/core/send_event.php +++ b/core/send_event.php @@ -121,6 +121,7 @@ function send_event(Event $event): void // SHIT: http://bugs.php.net/bug.php?id=35106 $my_event_listeners = $_shm_event_listeners[get_class($event)]; ksort($my_event_listeners); + foreach ($my_event_listeners as $listener) { if ($ctx_enabled) { $_shm_ctx->log_start(get_class($listener)); @@ -131,6 +132,9 @@ function send_event(Event $event): void if ($ctx_enabled) { $_shm_ctx->log_endok(); } + if($event->stop_processing===true) { + break; + } } $_shm_event_count++; if ($ctx_enabled) { diff --git a/ext/pools/main.php b/ext/pools/main.php index 42220e6b..8cb464c1 100644 --- a/ext/pools/main.php +++ b/ext/pools/main.php @@ -768,44 +768,38 @@ class Pools extends Extension $imagesPerPage = $config->get_int(PoolsConfig::IMAGES_PER_PAGE); + + $query = " + INNER JOIN images AS i ON i.id = p.image_id + WHERE p.pool_id = :pid + "; + + // WE CHECK IF THE EXTENSION RATING IS INSTALLED, WHICH VERSION AND IF IT // WORKS TO SHOW/HIDE SAFE, QUESTIONABLE, EXPLICIT AND UNRATED IMAGES FROM USER if (ext_is_live("Ratings")) { - $rating = Ratings::privs_to_sql(Ratings::get_user_privs($user)); + $query .= "AND i.rating IN (".Ratings::privs_to_sql(Ratings::get_user_privs($user)).")"; } - if (isset($rating) && !empty($rating)) { - $result = $database->get_all( - " - SELECT p.image_id - FROM pool_images AS p - INNER JOIN images AS i ON i.id = p.image_id - WHERE p.pool_id = :pid AND i.rating IN ($rating) + if(ext_is_live("trash")) { + $query .= $database->scoreql_to_sql(" AND trash = SCORE_BOOL_N "); + } + + $result = $database->get_all( + " + SELECT p.image_id FROM pool_images p + $query ORDER BY p.image_order ASC LIMIT :l OFFSET :o", - ["pid" => $poolID, "l" => $imagesPerPage, "o" => $pageNumber * $imagesPerPage] - ); + ["pid" => $poolID, "l" => $imagesPerPage, "o" => $pageNumber * $imagesPerPage] + ); - $totalPages = ceil($database->get_one( - " - SELECT COUNT(*) - FROM pool_images AS p - INNER JOIN images AS i ON i.id = p.image_id - WHERE pool_id=:pid AND i.rating IN ($rating)", - ["pid" => $poolID] - ) / $imagesPerPage); - } else { - $result = $database->get_all( + $totalPages = ceil($database->get_one( " - SELECT image_id - FROM pool_images - WHERE pool_id=:pid - ORDER BY image_order ASC - LIMIT :l OFFSET :o", - ["pid" => $poolID, "l" => $imagesPerPage, "o" => $pageNumber * $imagesPerPage] - ); + SELECT COUNT(*) FROM pool_images p + $query", + ["pid" => $poolID] + ) / $imagesPerPage); - $totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pool_images WHERE pool_id=:pid", ["pid" => $poolID]) / $imagesPerPage); - } $images = []; diff --git a/ext/trash/main.php b/ext/trash/main.php new file mode 100644 index 00000000..dc32000f --- /dev/null +++ b/ext/trash/main.php @@ -0,0 +1,164 @@ + + * License: MIT + * Description: Provides "Trash" or "Recycle Bin"-type functionality, storing delete images for later recovery + * Documentation: + */ + +abstract class TrashConfig +{ + const VERSION = "ext_trash_version"; +} + +class Trash extends Extension +{ + + protected $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL]; + + public function get_priority(): int + { + // Needs to be early to intercept delete events + return 10; + } + + public function onInitExt(InitExtEvent $event) + { + global $config; + + if ($config->get_int(TrashConfig::VERSION) < 1) { + $this->install(); + } + } + + + public function onPageRequest(PageRequestEvent $event) + { + global $page, $user; + + if ($event->page_matches("trash_restore") && $user->can("view_trash")) { + // Try to get the image ID + $image_id = int_escape($event->get_arg(0)); + if (empty($image_id)) { + $image_id = isset($_POST['image_id']) ? $_POST['image_id'] : null; + } + if (empty($image_id)) { + throw new SCoreException("Can not restore image: No valid Image ID given."); + } + + self::set_trash($image_id, false); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("post/view/".$image_id)); + } + } + + + + public function onDisplayingImage(DisplayingImageEvent $event) + { + global $user, $page; + + if(!$user->can("view_trash")) { + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(make_link("post/list")); + } + } + + public function onImageDeletion(ImageDeletionEvent $event) + { + if($event->image->trash===false) { + self::set_trash($event->image->id, true); + $event->stop_processing = true; + } + } + + + const SEARCH_REGEXP = "/^in:trash$/"; + public function onSearchTermParse(SearchTermParseEvent $event) + { + global $user, $database; + + $matches = []; + + if (is_null($event->term) && $this->no_trash_query($event->context)) { + $event->add_querylet(new Querylet($database->scoreql_to_sql("trash = SCORE_BOOL_N "))); + } + + + if (preg_match(self::SEARCH_REGEXP, strtolower($event->term), $matches)) { + if($user->can("view_trash")) { + $event->add_querylet(new Querylet($database->scoreql_to_sql("trash = SCORE_BOOL_Y "))); + } + } + } + + private function no_trash_query(array $context): bool + { + foreach ($context as $term) { + if (preg_match(self::SEARCH_REGEXP, $term)) { + return false; + } + } + return true; + } + + public static function set_trash($image_id, $trash) { + global $database; + + $database->execute("UPDATE images SET trash = :trash WHERE id = :id", + ["trash"=>$database->scoresql_value_prepare($trash),"id"=>$image_id]); + + + } + public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) + { + global $config, $database, $user; + if($event->image->trash===true && $user->can("view_trash")) { + $event->add_part($this->theme->get_image_admin_html($event->image->id)); + } + } + + public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event) + { + global $user; + + if ($user->can("view_trash")&&in_array("in:trash", $event->search_terms)) { + $event->add_action("bulk_trash_restore","Restore From Trash"); + } + } + + public function onBulkAction(BulkActionEvent $event) + { + global $user; + + switch ($event->action) { + case "bulk_trash_restore": + if ($user->can("view_trash")) { + $total = 0; + foreach ($event->items as $id) { + self::set_trash($id, false); + $total++; + } + flash_message("Restored $total items from trash"); + } + break; + } + } + + + private function install() + { + global $database, $config; + + if ($config->get_int(TrashConfig::VERSION) < 1) { + $database->Execute($database->scoreql_to_sql( + "ALTER TABLE images ADD COLUMN trash SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N" + )); + $database->Execute("CREATE INDEX images_trash_idx ON images(trash)"); + $config->set_int(TrashConfig::VERSION, 1); + } + + } + +} diff --git a/ext/trash/theme.php b/ext/trash/theme.php new file mode 100644 index 00000000..5e4e2e15 --- /dev/null +++ b/ext/trash/theme.php @@ -0,0 +1,14 @@ + + + + "; + + return $html; } +}