From 9c4e306b58637d145e56b9fb7951a1e5642291ef Mon Sep 17 00:00:00 2001 From: Shish Date: Mon, 12 Feb 2024 17:39:10 +0000 Subject: [PATCH] [tag_edit] separate responsibility for tags, source, owner, and lock --- ext/artists/main.php | 4 +- ext/artists/theme.php | 2 +- ext/graphql/main.php | 7 +- ext/post_lock/info.php | 18 +++ ext/post_lock/main.php | 56 ++++++++ ext/post_lock/test.php | 37 ++++++ ext/post_lock/theme.php | 22 ++++ ext/post_owner/info.php | 18 +++ ext/post_owner/main.php | 55 ++++++++ ext/post_owner/test.php | 22 ++++ ext/post_owner/theme.php | 34 +++++ ext/post_source/info.php | 18 +++ ext/post_source/main.php | 105 +++++++++++++++ ext/post_source/test.php | 21 +++ ext/post_source/theme.php | 54 ++++++++ ext/{tag_edit => post_tags}/info.php | 4 +- ext/{tag_edit => post_tags}/main.php | 160 +---------------------- ext/{tag_edit => post_tags}/test.php | 15 +-- ext/post_tags/theme.php | 56 ++++++++ ext/post_titles/main.php | 4 +- ext/post_titles/theme.php | 2 +- ext/relationships/main.php | 6 +- ext/relationships/theme.php | 2 +- ext/tag_edit/theme.php | 134 ------------------- ext/view/events/image_info_set_event.php | 4 +- ext/view/main.php | 7 +- 26 files changed, 545 insertions(+), 322 deletions(-) create mode 100644 ext/post_lock/info.php create mode 100644 ext/post_lock/main.php create mode 100644 ext/post_lock/test.php create mode 100644 ext/post_lock/theme.php create mode 100644 ext/post_owner/info.php create mode 100644 ext/post_owner/main.php create mode 100644 ext/post_owner/test.php create mode 100644 ext/post_owner/theme.php create mode 100644 ext/post_source/info.php create mode 100644 ext/post_source/main.php create mode 100644 ext/post_source/test.php create mode 100644 ext/post_source/theme.php rename ext/{tag_edit => post_tags}/info.php (96%) rename ext/{tag_edit => post_tags}/main.php (60%) rename ext/{tag_edit => post_tags}/test.php (76%) create mode 100644 ext/post_tags/theme.php delete mode 100644 ext/tag_edit/theme.php diff --git a/ext/artists/main.php b/ext/artists/main.php index cb94e0a0..dcb28021 100644 --- a/ext/artists/main.php +++ b/ext/artists/main.php @@ -38,8 +38,8 @@ class Artists extends Extension public function onImageInfoSet(ImageInfoSetEvent $event): void { global $user; - if ($user->can(Permissions::EDIT_IMAGE_ARTIST) && isset($event->params["tag_edit__author"])) { - send_event(new AuthorSetEvent($event->image, $user, $event->params["tag_edit__author"])); + if ($user->can(Permissions::EDIT_IMAGE_ARTIST) && isset($event->params["author"])) { + send_event(new AuthorSetEvent($event->image, $user, $event->params["author"])); } } diff --git a/ext/artists/theme.php b/ext/artists/theme.php index bf9947dc..8f52ef11 100644 --- a/ext/artists/theme.php +++ b/ext/artists/theme.php @@ -22,7 +22,7 @@ class ArtistsTheme extends Themelet return SHM_POST_INFO( "Author", $author, - INPUT(["type" => "text", "name" => "tag_edit__author", "value" => $author]) + INPUT(["type" => "text", "name" => "author", "value" => $author]) ); } diff --git a/ext/graphql/main.php b/ext/graphql/main.php index c42162db..1db6ab1a 100644 --- a/ext/graphql/main.php +++ b/ext/graphql/main.php @@ -29,11 +29,12 @@ class MetadataInput public static function update_post_metadata(int $post_id, MetadataInput $metadata): Image { global $user; - $_POST['tag_edit__tags'] = $metadata->tags; - $_POST['tag_edit__source'] = $metadata->source; $image = Image::by_id($post_id); if (!$image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK)) { - send_event(new ImageInfoSetEvent($image, $_POST)); + send_event(new ImageInfoSetEvent($image, [ + 'tags' => $metadata->tags, + 'source' => $metadata->source, + ])); } return Image::by_id($post_id); } diff --git a/ext/post_lock/info.php b/ext/post_lock/info.php new file mode 100644 index 00000000..fba20f56 --- /dev/null +++ b/ext/post_lock/info.php @@ -0,0 +1,18 @@ +image = $image; + $this->locked = $locked; + } +} + +class PostLock extends Extension +{ + /** @var PostLockTheme */ + protected Themelet $theme; + + public function onImageAddition(ImageAdditionEvent $event): void + { + if (!empty($event->metadata['locked'])) { + send_event(new LockSetEvent($event->image, $event->metadata['locked'])); + } + } + + public function onImageInfoSet(ImageInfoSetEvent $event): void + { + global $page, $user; + if ($event->image->is_locked() && !$user->can(Permissions::EDIT_IMAGE_LOCK)) { + throw new PermissionDenied("Error: This image is locked and cannot be edited."); + } + if ($user->can(Permissions::EDIT_IMAGE_LOCK)) { + $locked = isset($event->params['locked']) && $event->params['locked'] == "on"; + send_event(new LockSetEvent($event->image, $locked)); + } + } + + public function onLockSet(LockSetEvent $event): void + { + global $user; + if ($user->can(Permissions::EDIT_IMAGE_LOCK)) { + $event->image->set_locked($event->locked); + } + } + + public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event): void + { + $event->add_part($this->theme->get_lock_editor_html($event->image), 42); + } +} diff --git a/ext/post_lock/test.php b/ext/post_lock/test.php new file mode 100644 index 00000000..ba0eb2ee --- /dev/null +++ b/ext/post_lock/test.php @@ -0,0 +1,37 @@ +log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); + + // admin can lock + $this->log_in_as_admin(); + send_event(new ImageInfoSetEvent(Image::by_id($image_id), ["locked" => "on"])); + + // user can't edit locked post + $this->log_in_as_user(); + $this->assertException(PermissionDenied::class, function () use ($image_id) { + send_event(new ImageInfoSetEvent(Image::by_id($image_id), ["source" => "http://example.com"])); + }); + + // admin can edit locked post + $this->log_in_as_admin(); + send_event(new ImageInfoSetEvent(Image::by_id($image_id), ["source" => "http://example.com"])); + + // admin can unlock + $this->log_in_as_admin(); + send_event(new ImageInfoSetEvent(Image::by_id($image_id), [])); // "locked" is not set + + // user can edit un-locked post + $this->log_in_as_user(); + send_event(new ImageInfoSetEvent(Image::by_id($image_id), ["source" => "http://example.com"])); + } +} diff --git a/ext/post_lock/theme.php b/ext/post_lock/theme.php new file mode 100644 index 00000000..4d64d989 --- /dev/null +++ b/ext/post_lock/theme.php @@ -0,0 +1,22 @@ +is_locked() ? "Yes (Only admins may edit these details)" : "No", + $user->can(Permissions::EDIT_IMAGE_LOCK) ? INPUT(["type" => "checkbox", "name" => "locked", "checked" => $image->is_locked()]) : null + ); + } +} diff --git a/ext/post_owner/info.php b/ext/post_owner/info.php new file mode 100644 index 00000000..42b37e1f --- /dev/null +++ b/ext/post_owner/info.php @@ -0,0 +1,18 @@ +image = $image; + $this->owner = $owner; + } +} + +class PostOwner extends Extension +{ + /** @var PostOwnerTheme */ + protected Themelet $theme; + + public function onImageAddition(ImageAdditionEvent $event): void + { + // FIXME: send an event instead of implicit default owner? + } + + public function onImageInfoSet(ImageInfoSetEvent $event): void + { + global $page, $user; + if ($user->can(Permissions::EDIT_IMAGE_OWNER) && isset($event->params['owner'])) { + $owner = User::by_name($event->params['owner']); + if ($owner instanceof User) { + send_event(new OwnerSetEvent($event->image, $owner)); + } else { + throw new UserNotFound("Error: No user with that name was found."); + } + } + } + + public function onOwnerSet(OwnerSetEvent $event): void + { + global $user; + if ($user->can(Permissions::EDIT_IMAGE_OWNER)) { + $event->image->set_owner($event->owner); + } + } + + public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event): void + { + $event->add_part($this->theme->get_owner_editor_html($event->image), 39); + } +} diff --git a/ext/post_owner/test.php b/ext/post_owner/test.php new file mode 100644 index 00000000..741d08b0 --- /dev/null +++ b/ext/post_owner/test.php @@ -0,0 +1,22 @@ +log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); + $image = Image::by_id($image_id); + + $this->log_in_as_admin(); + send_event(new ImageInfoSetEvent($image, ["owner" => self::$admin_name])); + + $this->log_in_as_user(); + $this->get_page("post/view/$image_id"); + $this->assert_text(self::$admin_name); + } +} diff --git a/ext/post_owner/theme.php b/ext/post_owner/theme.php new file mode 100644 index 00000000..23350aca --- /dev/null +++ b/ext/post_owner/theme.php @@ -0,0 +1,34 @@ +get_owner()->name; + $date = rawHTML(autodate($image->posted)); + $ip = $user->can(Permissions::VIEW_IP) ? rawHTML(" (" . show_ip($image->owner_ip, "Post posted {$image->posted}") . ")") : ""; + $info = SHM_POST_INFO( + "Uploader", + emptyHTML(A(["class" => "username", "href" => make_link("user/$owner")], $owner), $ip, ", ", $date), + $user->can(Permissions::EDIT_IMAGE_OWNER) ? INPUT(["type" => "text", "name" => "owner", "value" => $owner]) : null + ); + // SHM_POST_INFO returns a TR, let's sneakily append + // a TD with the avatar in it + $info->appendChild( + TD( + ["width" => "80px", "rowspan" => "4"], + rawHTML($image->get_owner()->get_avatar_html()) + ) + ); + return $info; + } +} diff --git a/ext/post_source/info.php b/ext/post_source/info.php new file mode 100644 index 00000000..99c171f9 --- /dev/null +++ b/ext/post_source/info.php @@ -0,0 +1,18 @@ +image = $image; + $this->source = trim($source); + } +} + +class PostSource extends Extension +{ + /** @var PostSourceTheme */ + protected Themelet $theme; + + public function onPageRequest(PageRequestEvent $event): void + { + global $user, $page; + if ($event->page_matches("tag_edit/mass_source_set", method: "POST", permission: Permissions::MASS_TAG_EDIT)) { + $this->mass_source_edit($event->req_POST('tags'), $event->req_POST('source')); + $page->set_mode(PageMode::REDIRECT); + $page->set_redirect(search_link()); + } + } + + public function onImageAddition(ImageAdditionEvent $event): void + { + if(!empty($event->metadata['source'])) { + send_event(new SourceSetEvent($event->image, $event->metadata['source'])); + } + } + + public function onImageInfoSet(ImageInfoSetEvent $event): void + { + global $page, $user; + if ($user->can(Permissions::EDIT_IMAGE_SOURCE) && isset($event->params['source'])) { + if (isset($event->params['tags']) ? !preg_match('/source[=|:]/', $event->params["tags"]) : true) { + send_event(new SourceSetEvent($event->image, $event->params['source'])); + } + } + } + + public function onSourceSet(SourceSetEvent $event): void + { + global $user; + if ($user->can(Permissions::EDIT_IMAGE_SOURCE)) { + $event->image->set_source($event->source); + } + } + + public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event): void + { + $event->add_part($this->theme->get_source_editor_html($event->image), 41); + } + + public function onTagTermCheck(TagTermCheckEvent $event): void + { + if (preg_match("/^source[=|:](.*)$/i", $event->term)) { + $event->metatag = true; + } + } + + public function onTagTermParse(TagTermParseEvent $event): void + { + if (preg_match("/^source[=|:](.*)$/i", $event->term, $matches)) { + $source = ($matches[1] !== "none" ? $matches[1] : null); + send_event(new SourceSetEvent(Image::by_id($event->image_id), $source)); + } + } + + private function mass_source_edit(string $tags, string $source): void + { + $tags = Tag::explode($tags); + + $last_id = -1; + while (true) { + // make sure we don't look at the same images twice. + // search returns high-ids first, so we want to look + // at images with lower IDs than the previous. + $search_forward = $tags; + if ($last_id >= 0) { + $search_forward[] = "id<$last_id"; + } + + $images = Search::find_images(limit: 100, tags: $search_forward); + if (count($images) == 0) { + break; + } + + foreach ($images as $image) { + send_event(new SourceSetEvent($image, $source)); + $last_id = $image->id; + } + } + } +} diff --git a/ext/post_source/test.php b/ext/post_source/test.php new file mode 100644 index 00000000..8622d738 --- /dev/null +++ b/ext/post_source/test.php @@ -0,0 +1,21 @@ +log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); + $image = Image::by_id($image_id); + + send_event(new ImageInfoSetEvent($image, ["source" => "example.com"])); + send_event(new ImageInfoSetEvent($image, ["source" => "http://example.com"])); + + $this->get_page("post/view/$image_id"); + $this->assert_text("example.com"); + } +} diff --git a/ext/post_source/theme.php b/ext/post_source/theme.php new file mode 100644 index 00000000..40ef2ea5 --- /dev/null +++ b/ext/post_source/theme.php @@ -0,0 +1,54 @@ + + + + + "; + return $html; + } + + public function get_source_editor_html(Image $image): HTMLElement + { + global $user; + return SHM_POST_INFO( + "Source Link", + DIV( + ["style" => "overflow: hidden; white-space: nowrap; max-width: 350px; text-overflow: ellipsis;"], + $this->format_source($image->get_source()) + ), + $user->can(Permissions::EDIT_IMAGE_SOURCE) ? INPUT(["type" => "text", "name" => "source", "value" => $image->get_source()]) : null, + link: Extension::is_enabled(SourceHistoryInfo::KEY) ? make_link("source_history/{$image->id}") : null, + ); + } + + protected function format_source(string $source = null): HTMLElement + { + if (!empty($source)) { + if (!str_contains($source, "://")) { + $source = "https://" . $source; + } + $proto_domain = explode("://", $source); + $h_source = $proto_domain[1]; + if (str_ends_with($h_source, "/")) { + $h_source = substr($h_source, 0, -1); + } + return A(["href" => $source], $h_source); + } + return rawHTML("Unknown"); + } +} diff --git a/ext/tag_edit/info.php b/ext/post_tags/info.php similarity index 96% rename from ext/tag_edit/info.php rename to ext/post_tags/info.php index 30c1280e..6845b06a 100644 --- a/ext/tag_edit/info.php +++ b/ext/post_tags/info.php @@ -4,9 +4,9 @@ declare(strict_types=1); namespace Shimmie2; -class TagEditInfo extends ExtensionInfo +class PostTagsInfo extends ExtensionInfo { - public const KEY = "tag_edit"; + public const KEY = "post_tags"; public string $key = self::KEY; public string $name = "Tag Editor"; diff --git a/ext/tag_edit/main.php b/ext/post_tags/main.php similarity index 60% rename from ext/tag_edit/main.php rename to ext/post_tags/main.php index 687634ee..86486663 100644 --- a/ext/tag_edit/main.php +++ b/ext/post_tags/main.php @@ -8,40 +8,6 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\{InputInterface,InputArgument}; use Symfony\Component\Console\Output\OutputInterface; -/* - * OwnerSetEvent: - * $image_id - * $source - * - */ -class OwnerSetEvent extends Event -{ - public Image $image; - public User $owner; - - public function __construct(Image $image, User $owner) - { - parent::__construct(); - $this->image = $image; - $this->owner = $owner; - } -} - - -class SourceSetEvent extends Event -{ - public Image $image; - public ?string $source; - - public function __construct(Image $image, string $source = null) - { - parent::__construct(); - $this->image = $image; - $this->source = trim($source); - } -} - - class TagSetException extends UserError { public ?string $redirect; @@ -94,19 +60,6 @@ class TagSetEvent extends Event } } -class LockSetEvent extends Event -{ - public Image $image; - public bool $locked; - - public function __construct(Image $image, bool $locked) - { - parent::__construct(); - $this->image = $image; - $this->locked = $locked; - } -} - /** * Check whether or not a tag is a meta-tag */ @@ -138,9 +91,9 @@ class TagTermParseEvent extends Event } } -class TagEdit extends Extension +class PostTags extends Extension { - /** @var TagEditTheme */ + /** @var PostTagsTheme */ protected Themelet $theme; public function onPageRequest(PageRequestEvent $event): void @@ -151,11 +104,6 @@ class TagEdit extends Extension $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("admin")); } - if ($event->page_matches("tag_edit/mass_source_set", method: "POST", permission: Permissions::MASS_TAG_EDIT)) { - $this->mass_source_edit($event->req_POST('tags'), $event->req_POST('source')); - $page->set_mode(PageMode::REDIRECT); - $page->set_redirect(search_link()); - } } public function onCliGen(CliGenEvent $event): void @@ -173,41 +121,19 @@ class TagEdit extends Extension }); } - // public function onPostListBuilding(PostListBuildingEvent $event): void - // { - // global $user; - // if ($user->can(UserAbilities::BULK_EDIT_IMAGE_SOURCE) && !empty($event->search_terms)) { - // $event->add_control($this->theme->mss_html(Tag::implode($event->search_terms))); - // } - // } - public function onImageAddition(ImageAdditionEvent $event): void { if(!empty($event->metadata['tags'])) { send_event(new TagSetEvent($event->image, $event->metadata['tags'])); } - if(!empty($event->metadata['source'])) { - send_event(new SourceSetEvent($event->image, $event->metadata['source'])); - } - if (!empty($event->metadata['locked'])) { - send_event(new LockSetEvent($event->image, $event->metadata['locked'])); - } } public function onImageInfoSet(ImageInfoSetEvent $event): void { global $page, $user; - if ($user->can(Permissions::EDIT_IMAGE_OWNER) && isset($event->params['tag_edit__owner'])) { - $owner = User::by_name($event->params['tag_edit__owner']); - if ($owner instanceof User) { - send_event(new OwnerSetEvent($event->image, $owner)); - } else { - throw new UserNotFound("Error: No user with that name was found."); - } - } - if ($user->can(Permissions::EDIT_IMAGE_TAG) && isset($event->params['tag_edit__tags'])) { + if ($user->can(Permissions::EDIT_IMAGE_TAG) && isset($event->params['tags'])) { try { - send_event(new TagSetEvent($event->image, Tag::explode($event->params['tag_edit__tags']))); + send_event(new TagSetEvent($event->image, Tag::explode($event->params['tags']))); } catch (TagSetException $e) { if ($e->redirect) { $page->flash("{$e->getMessage()}, please see {$e->redirect}"); @@ -216,23 +142,6 @@ class TagEdit extends Extension } } } - if ($user->can(Permissions::EDIT_IMAGE_SOURCE) && isset($event->params['tag_edit__source'])) { - if (isset($event->params['tag_edit__tags']) ? !preg_match('/source[=|:]/', $event->params["tag_edit__tags"]) : true) { - send_event(new SourceSetEvent($event->image, $event->params['tag_edit__source'])); - } - } - if ($user->can(Permissions::EDIT_IMAGE_LOCK)) { - $locked = isset($event->params['tag_edit__locked']) && $event->params['tag_edit__locked'] == "on"; - send_event(new LockSetEvent($event->image, $locked)); - } - } - - public function onOwnerSet(OwnerSetEvent $event): void - { - global $user; - if ($user->can(Permissions::EDIT_IMAGE_OWNER) && (!$event->image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK))) { - $event->image->set_owner($event->owner); - } } public function onTagSet(TagSetEvent $event): void @@ -245,23 +154,6 @@ class TagEdit extends Extension send_event(new TagTermParseEvent($tag, $event->image->id)); } } - - public function onSourceSet(SourceSetEvent $event): void - { - global $user; - if ($user->can(Permissions::EDIT_IMAGE_SOURCE) && (!$event->image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK))) { - $event->image->set_source($event->source); - } - } - - public function onLockSet(LockSetEvent $event): void - { - global $user; - if ($user->can(Permissions::EDIT_IMAGE_LOCK)) { - $event->image->set_locked($event->locked); - } - } - public function onImageDeletion(ImageDeletionEvent $event): void { $event->image->delete_tags_from_image(); @@ -289,25 +181,7 @@ class TagEdit extends Extension public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event): void { - $event->add_part($this->theme->get_user_editor_html($event->image), 39); $event->add_part($this->theme->get_tag_editor_html($event->image), 40); - $event->add_part($this->theme->get_source_editor_html($event->image), 41); - $event->add_part($this->theme->get_lock_editor_html($event->image), 42); - } - - public function onTagTermCheck(TagTermCheckEvent $event): void - { - if (preg_match("/^source[=|:](.*)$/i", $event->term)) { - $event->metatag = true; - } - } - - public function onTagTermParse(TagTermParseEvent $event): void - { - if (preg_match("/^source[=|:](.*)$/i", $event->term, $matches)) { - $source = ($matches[1] !== "none" ? $matches[1] : null); - send_event(new SourceSetEvent(Image::by_id($event->image_id), $source)); - } } public function onParseLinkTemplate(ParseLinkTemplateEvent $event): void @@ -380,30 +254,4 @@ class TagEdit extends Extension } } } - - private function mass_source_edit(string $tags, string $source): void - { - $tags = Tag::explode($tags); - - $last_id = -1; - while (true) { - // make sure we don't look at the same images twice. - // search returns high-ids first, so we want to look - // at images with lower IDs than the previous. - $search_forward = $tags; - if ($last_id >= 0) { - $search_forward[] = "id<$last_id"; - } - - $images = Search::find_images(limit: 100, tags: $search_forward); - if (count($images) == 0) { - break; - } - - foreach ($images as $image) { - send_event(new SourceSetEvent($image, $source)); - $last_id = $image->id; - } - } - } } diff --git a/ext/tag_edit/test.php b/ext/post_tags/test.php similarity index 76% rename from ext/tag_edit/test.php rename to ext/post_tags/test.php index 8a1034dd..1ffb8eea 100644 --- a/ext/tag_edit/test.php +++ b/ext/post_tags/test.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace Shimmie2; -class TagEditTest extends ShimmiePHPUnitTestCase +class PostTagsTest extends ShimmiePHPUnitTestCase { public function testValidChange(): void { @@ -46,17 +46,4 @@ class TagEditTest extends ShimmiePHPUnitTestCase $this->get_page("post/view/$image_id"); $this->assert_title("Post $image_id: tagme"); } - - public function testSourceEdit(): void - { - $this->log_in_as_user(); - $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); - $image = Image::by_id($image_id); - - send_event(new SourceSetEvent($image, "example.com")); - send_event(new SourceSetEvent($image, "http://example.com")); - - $this->get_page("post/view/$image_id"); - $this->assert_text("example.com"); - } } diff --git a/ext/post_tags/theme.php b/ext/post_tags/theme.php new file mode 100644 index 00000000..4a3a932f --- /dev/null +++ b/ext/post_tags/theme.php @@ -0,0 +1,56 @@ + + Search + Replace + + + + "; + $page->add_block(new Block("Mass Tag Edit", $html)); + } + + public function get_tag_editor_html(Image $image): HTMLElement + { + global $user; + + $tag_links = []; + foreach ($image->get_tag_array() as $tag) { + $tag_links[] = A([ + "href" => search_link([$tag]), + "class" => "tag", + "title" => "View all posts tagged $tag" + ], $tag); + } + + return SHM_POST_INFO( + "Tags", + joinHTML(", ", $tag_links), + $user->can(Permissions::EDIT_IMAGE_TAG) ? TEXTAREA([ + "class" => "autocomplete_tags", + "type" => "text", + "name" => "tags", + "id" => "tag_editor", + "spellcheck" => "off", + ], $image->get_tag_list()) : null, + link: Extension::is_enabled(TagHistoryInfo::KEY) ? + make_link("tag_history/{$image->id}") : + null, + ); + } +} diff --git a/ext/post_titles/main.php b/ext/post_titles/main.php index ca84b401..54bf8ade 100644 --- a/ext/post_titles/main.php +++ b/ext/post_titles/main.php @@ -56,8 +56,8 @@ class PostTitles extends Extension { global $user; - if ($user->can(Permissions::EDIT_IMAGE_TITLE) && isset($event->params["post_title"])) { - send_event(new PostTitleSetEvent($event->image, $event->params["post_title"])); + if ($user->can(Permissions::EDIT_IMAGE_TITLE) && isset($event->params["title"])) { + send_event(new PostTitleSetEvent($event->image, $event->params["title"])); } } diff --git a/ext/post_titles/theme.php b/ext/post_titles/theme.php index f468fea2..792f4d00 100644 --- a/ext/post_titles/theme.php +++ b/ext/post_titles/theme.php @@ -15,7 +15,7 @@ class PostTitlesTheme extends Themelet return SHM_POST_INFO( "Title", $title, - $can_set ? INPUT(["type" => "text", "name" => "post_title", "value" => $title]) : null + $can_set ? INPUT(["type" => "text", "name" => "title", "value" => $title]) : null ); } } diff --git a/ext/relationships/main.php b/ext/relationships/main.php index eec11679..97103449 100644 --- a/ext/relationships/main.php +++ b/ext/relationships/main.php @@ -56,9 +56,9 @@ class Relationships extends Extension { global $user; if ($user->can(Permissions::EDIT_IMAGE_RELATIONSHIPS)) { - if (isset($event->params['tag_edit__tags']) ? !preg_match('/parent[=|:]/', $event->params["tag_edit__tags"]) : true) { //Ignore tag_edit__parent if tags contain parent metatag - if (isset($event->params["tag_edit__parent"]) ? ctype_digit($event->params["tag_edit__parent"]) : false) { - send_event(new ImageRelationshipSetEvent($event->image->id, (int) $event->params["tag_edit__parent"])); + if (isset($event->params['tags']) ? !preg_match('/parent[=|:]/', $event->params["tags"]) : true) { //Ignore parent if tags contain parent metatag + if (isset($event->params["parent"]) ? ctype_digit($event->params["parent"]) : false) { + send_event(new ImageRelationshipSetEvent($event->image->id, (int) $event->params["parent"])); } else { $this->remove_parent($event->image->id); } diff --git a/ext/relationships/theme.php b/ext/relationships/theme.php index d2a61a1b..10ed598e 100644 --- a/ext/relationships/theme.php +++ b/ext/relationships/theme.php @@ -40,7 +40,7 @@ class RelationshipsTheme extends Themelet return SHM_POST_INFO( "Parent", strval($image['parent_id']) ?: "None", - !$user->is_anonymous() ? INPUT(["type" => "number", "name" => "tag_edit__parent", "value" => $image['parent_id']]) : null + !$user->is_anonymous() ? INPUT(["type" => "number", "name" => "parent", "value" => $image['parent_id']]) : null ); } diff --git a/ext/tag_edit/theme.php b/ext/tag_edit/theme.php deleted file mode 100644 index 4fc40111..00000000 --- a/ext/tag_edit/theme.php +++ /dev/null @@ -1,134 +0,0 @@ - - Search - Replace - - - - "; - $page->add_block(new Block("Mass Tag Edit", $html)); - } - - public function mss_html(string $terms): string - { - $h_terms = html_escape($terms); - $html = make_form(make_link("tag_edit/mass_source_set")) . " - - - - - "; - return $html; - } - - public function get_tag_editor_html(Image $image): HTMLElement - { - global $user; - - $tag_links = []; - foreach ($image->get_tag_array() as $tag) { - $tag_links[] = A([ - "href" => search_link([$tag]), - "class" => "tag", - "title" => "View all posts tagged $tag" - ], $tag); - } - - return SHM_POST_INFO( - "Tags", - joinHTML(", ", $tag_links), - $user->can(Permissions::EDIT_IMAGE_TAG) ? TEXTAREA([ - "class" => "autocomplete_tags", - "type" => "text", - "name" => "tag_edit__tags", - "id" => "tag_editor", - "spellcheck" => "off", - ], $image->get_tag_list()) : null, - link: Extension::is_enabled(TagHistoryInfo::KEY) ? - make_link("tag_history/{$image->id}") : - null, - ); - } - - public function get_user_editor_html(Image $image): HTMLElement - { - global $user; - $owner = $image->get_owner()->name; - $date = rawHTML(autodate($image->posted)); - $ip = $user->can(Permissions::VIEW_IP) ? rawHTML(" (" . show_ip($image->owner_ip, "Post posted {$image->posted}") . ")") : ""; - $info = SHM_POST_INFO( - "Uploader", - emptyHTML(A(["class" => "username", "href" => make_link("user/$owner")], $owner), $ip, ", ", $date), - $user->can(Permissions::EDIT_IMAGE_OWNER) ? INPUT(["type" => "text", "name" => "tag_edit__owner", "value" => $owner]) : null - ); - // SHM_POST_INFO returns a TR, let's sneakily append - // a TD with the avatar in it - $info->appendChild( - TD( - ["width" => "80px", "rowspan" => "4"], - rawHTML($image->get_owner()->get_avatar_html()) - ) - ); - return $info; - } - - public function get_source_editor_html(Image $image): HTMLElement - { - global $user; - return SHM_POST_INFO( - "Source Link", - DIV( - ["style" => "overflow: hidden; white-space: nowrap; max-width: 350px; text-overflow: ellipsis;"], - $this->format_source($image->get_source()) - ), - $user->can(Permissions::EDIT_IMAGE_SOURCE) ? INPUT(["type" => "text", "name" => "tag_edit__source", "value" => $image->get_source()]) : null, - link: Extension::is_enabled(SourceHistoryInfo::KEY) ? make_link("source_history/{$image->id}") : null, - ); - } - - protected function format_source(string $source = null): HTMLElement - { - if (!empty($source)) { - if (!str_contains($source, "://")) { - $source = "https://" . $source; - } - $proto_domain = explode("://", $source); - $h_source = $proto_domain[1]; - if (str_ends_with($h_source, "/")) { - $h_source = substr($h_source, 0, -1); - } - return A(["href" => $source], $h_source); - } - return rawHTML("Unknown"); - } - - public function get_lock_editor_html(Image $image): HTMLElement - { - global $user; - return SHM_POST_INFO( - "Locked", - $image->is_locked() ? "Yes (Only admins may edit these details)" : "No", - $user->can(Permissions::EDIT_IMAGE_LOCK) ? INPUT(["type" => "checkbox", "name" => "tag_edit__locked", "checked" => $image->is_locked()]) : null - ); - } -} diff --git a/ext/view/events/image_info_set_event.php b/ext/view/events/image_info_set_event.php index d90982af..e5d982c5 100644 --- a/ext/view/events/image_info_set_event.php +++ b/ext/view/events/image_info_set_event.php @@ -7,11 +7,11 @@ namespace Shimmie2; class ImageInfoSetEvent extends Event { public Image $image; - /** @var array */ + /** @var array */ public array $params; /** - * @param array $params + * @param array $params */ public function __construct(Image $image, array $params) { diff --git a/ext/view/main.php b/ext/view/main.php index 2a5a80da..ba8c4983 100644 --- a/ext/view/main.php +++ b/ext/view/main.php @@ -75,7 +75,12 @@ class ViewPost extends Extension $image_id = int_escape($event->req_POST('image_id')); $image = Image::by_id($image_id); if (!$image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK)) { - send_event(new ImageInfoSetEvent($image, $event->POST)); + // currently all post metadata is string => string - in the future + // we might want to have a more complex type system, but for now + // we just filter out non-string keys + /** @var array */ + $kvs = array_filter($event->POST, 'is_string', ARRAY_FILTER_USE_KEY); + send_event(new ImageInfoSetEvent($image, $kvs)); $page->set_mode(PageMode::REDIRECT); if ($event->get_GET('search')) {