[tag_edit] separate responsibility for tags, source, owner, and lock
This commit is contained in:
parent
3d905b1055
commit
9c4e306b58
26 changed files with 545 additions and 322 deletions
|
@ -38,8 +38,8 @@ class Artists extends Extension
|
||||||
public function onImageInfoSet(ImageInfoSetEvent $event): void
|
public function onImageInfoSet(ImageInfoSetEvent $event): void
|
||||||
{
|
{
|
||||||
global $user;
|
global $user;
|
||||||
if ($user->can(Permissions::EDIT_IMAGE_ARTIST) && isset($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["tag_edit__author"]));
|
send_event(new AuthorSetEvent($event->image, $user, $event->params["author"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ArtistsTheme extends Themelet
|
||||||
return SHM_POST_INFO(
|
return SHM_POST_INFO(
|
||||||
"Author",
|
"Author",
|
||||||
$author,
|
$author,
|
||||||
INPUT(["type" => "text", "name" => "tag_edit__author", "value" => $author])
|
INPUT(["type" => "text", "name" => "author", "value" => $author])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,12 @@ class MetadataInput
|
||||||
public static function update_post_metadata(int $post_id, MetadataInput $metadata): Image
|
public static function update_post_metadata(int $post_id, MetadataInput $metadata): Image
|
||||||
{
|
{
|
||||||
global $user;
|
global $user;
|
||||||
$_POST['tag_edit__tags'] = $metadata->tags;
|
|
||||||
$_POST['tag_edit__source'] = $metadata->source;
|
|
||||||
$image = Image::by_id($post_id);
|
$image = Image::by_id($post_id);
|
||||||
if (!$image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK)) {
|
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);
|
return Image::by_id($post_id);
|
||||||
}
|
}
|
||||||
|
|
18
ext/post_lock/info.php
Normal file
18
ext/post_lock/info.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
class PostLockInfo extends ExtensionInfo
|
||||||
|
{
|
||||||
|
public const KEY = "post_lock";
|
||||||
|
|
||||||
|
public string $key = self::KEY;
|
||||||
|
public string $name = "Lock Editor";
|
||||||
|
public bool $core = true;
|
||||||
|
public string $url = self::SHIMMIE_URL;
|
||||||
|
public array $authors = self::SHISH_AUTHOR;
|
||||||
|
public ExtensionCategory $category = ExtensionCategory::METADATA;
|
||||||
|
public string $description = "Allow images to have metadata locked";
|
||||||
|
}
|
56
ext/post_lock/main.php
Normal file
56
ext/post_lock/main.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
37
ext/post_lock/test.php
Normal file
37
ext/post_lock/test.php
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
class PostLockTest extends ShimmiePHPUnitTestCase
|
||||||
|
{
|
||||||
|
public function testLockEdit(): void
|
||||||
|
{
|
||||||
|
// user can post
|
||||||
|
$this->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"]));
|
||||||
|
}
|
||||||
|
}
|
22
ext/post_lock/theme.php
Normal file
22
ext/post_lock/theme.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
use MicroHTML\HTMLElement;
|
||||||
|
|
||||||
|
use function MicroHTML\{INPUT};
|
||||||
|
|
||||||
|
class PostLockTheme extends Themelet
|
||||||
|
{
|
||||||
|
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" => "locked", "checked" => $image->is_locked()]) : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
18
ext/post_owner/info.php
Normal file
18
ext/post_owner/info.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
class PostOwnerInfo extends ExtensionInfo
|
||||||
|
{
|
||||||
|
public const KEY = "post_owner";
|
||||||
|
|
||||||
|
public string $key = self::KEY;
|
||||||
|
public string $name = "Owner Editor";
|
||||||
|
public bool $core = true;
|
||||||
|
public string $url = self::SHIMMIE_URL;
|
||||||
|
public array $authors = self::SHISH_AUTHOR;
|
||||||
|
public ExtensionCategory $category = ExtensionCategory::METADATA;
|
||||||
|
public string $description = "Allow images to have owners assigned to them";
|
||||||
|
}
|
55
ext/post_owner/main.php
Normal file
55
ext/post_owner/main.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
}
|
22
ext/post_owner/test.php
Normal file
22
ext/post_owner/test.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
class PostOwnerTest extends ShimmiePHPUnitTestCase
|
||||||
|
{
|
||||||
|
public function testOwnerEdit(): void
|
||||||
|
{
|
||||||
|
$this->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);
|
||||||
|
}
|
||||||
|
}
|
34
ext/post_owner/theme.php
Normal file
34
ext/post_owner/theme.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
use MicroHTML\HTMLElement;
|
||||||
|
|
||||||
|
use function MicroHTML\{TR, TH, TD, emptyHTML, rawHTML, joinHTML, DIV, INPUT, A, TEXTAREA};
|
||||||
|
|
||||||
|
class PostOwnerTheme extends Themelet
|
||||||
|
{
|
||||||
|
public function get_owner_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" => "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;
|
||||||
|
}
|
||||||
|
}
|
18
ext/post_source/info.php
Normal file
18
ext/post_source/info.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
class PostSourceInfo extends ExtensionInfo
|
||||||
|
{
|
||||||
|
public const KEY = "post_source";
|
||||||
|
|
||||||
|
public string $key = self::KEY;
|
||||||
|
public string $name = "Source Editor";
|
||||||
|
public bool $core = true;
|
||||||
|
public string $url = self::SHIMMIE_URL;
|
||||||
|
public array $authors = self::SHISH_AUTHOR;
|
||||||
|
public ExtensionCategory $category = ExtensionCategory::METADATA;
|
||||||
|
public string $description = "Allow images to have sources assigned to them";
|
||||||
|
}
|
105
ext/post_source/main.php
Normal file
105
ext/post_source/main.php
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
ext/post_source/test.php
Normal file
21
ext/post_source/test.php
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
class PostSourceTest extends ShimmiePHPUnitTestCase
|
||||||
|
{
|
||||||
|
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 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");
|
||||||
|
}
|
||||||
|
}
|
54
ext/post_source/theme.php
Normal file
54
ext/post_source/theme.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
use MicroHTML\HTMLElement;
|
||||||
|
|
||||||
|
use function MicroHTML\{TR, TH, TD, emptyHTML, rawHTML, joinHTML, DIV, INPUT, A, TEXTAREA};
|
||||||
|
|
||||||
|
class PostSourceTheme extends Themelet
|
||||||
|
{
|
||||||
|
public function mss_html(string $terms): string
|
||||||
|
{
|
||||||
|
$h_terms = html_escape($terms);
|
||||||
|
$html = make_form(make_link("tag_edit/mass_source_set")) . "
|
||||||
|
<input type='hidden' name='tags' value='$h_terms'>
|
||||||
|
<input type='text' name='source' value=''>
|
||||||
|
<input type='submit' value='Set Source For All' onclick='return confirm(\"This will mass-edit all sources on the page.\\nAre you sure you want to do this?\")'>
|
||||||
|
</form>
|
||||||
|
";
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,9 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Shimmie2;
|
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 $key = self::KEY;
|
||||||
public string $name = "Tag Editor";
|
public string $name = "Tag Editor";
|
|
@ -8,40 +8,6 @@ use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\{InputInterface,InputArgument};
|
use Symfony\Component\Console\Input\{InputInterface,InputArgument};
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
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
|
class TagSetException extends UserError
|
||||||
{
|
{
|
||||||
public ?string $redirect;
|
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
|
* 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;
|
protected Themelet $theme;
|
||||||
|
|
||||||
public function onPageRequest(PageRequestEvent $event): void
|
public function onPageRequest(PageRequestEvent $event): void
|
||||||
|
@ -151,11 +104,6 @@ class TagEdit extends Extension
|
||||||
$page->set_mode(PageMode::REDIRECT);
|
$page->set_mode(PageMode::REDIRECT);
|
||||||
$page->set_redirect(make_link("admin"));
|
$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
|
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
|
public function onImageAddition(ImageAdditionEvent $event): void
|
||||||
{
|
{
|
||||||
if(!empty($event->metadata['tags'])) {
|
if(!empty($event->metadata['tags'])) {
|
||||||
send_event(new TagSetEvent($event->image, $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
|
public function onImageInfoSet(ImageInfoSetEvent $event): void
|
||||||
{
|
{
|
||||||
global $page, $user;
|
global $page, $user;
|
||||||
if ($user->can(Permissions::EDIT_IMAGE_OWNER) && isset($event->params['tag_edit__owner'])) {
|
if ($user->can(Permissions::EDIT_IMAGE_TAG) && isset($event->params['tags'])) {
|
||||||
$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'])) {
|
|
||||||
try {
|
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) {
|
} catch (TagSetException $e) {
|
||||||
if ($e->redirect) {
|
if ($e->redirect) {
|
||||||
$page->flash("{$e->getMessage()}, please see {$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
|
public function onTagSet(TagSetEvent $event): void
|
||||||
|
@ -245,23 +154,6 @@ class TagEdit extends Extension
|
||||||
send_event(new TagTermParseEvent($tag, $event->image->id));
|
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
|
public function onImageDeletion(ImageDeletionEvent $event): void
|
||||||
{
|
{
|
||||||
$event->image->delete_tags_from_image();
|
$event->image->delete_tags_from_image();
|
||||||
|
@ -289,25 +181,7 @@ class TagEdit extends Extension
|
||||||
|
|
||||||
public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event): void
|
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_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
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Shimmie2;
|
namespace Shimmie2;
|
||||||
|
|
||||||
class TagEditTest extends ShimmiePHPUnitTestCase
|
class PostTagsTest extends ShimmiePHPUnitTestCase
|
||||||
{
|
{
|
||||||
public function testValidChange(): void
|
public function testValidChange(): void
|
||||||
{
|
{
|
||||||
|
@ -46,17 +46,4 @@ class TagEditTest extends ShimmiePHPUnitTestCase
|
||||||
$this->get_page("post/view/$image_id");
|
$this->get_page("post/view/$image_id");
|
||||||
$this->assert_title("Post $image_id: tagme");
|
$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");
|
|
||||||
}
|
|
||||||
}
|
}
|
56
ext/post_tags/theme.php
Normal file
56
ext/post_tags/theme.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shimmie2;
|
||||||
|
|
||||||
|
use MicroHTML\HTMLElement;
|
||||||
|
|
||||||
|
use function MicroHTML\{joinHTML, A, TEXTAREA};
|
||||||
|
|
||||||
|
class PostTagsTheme extends Themelet
|
||||||
|
{
|
||||||
|
public function display_mass_editor(): void
|
||||||
|
{
|
||||||
|
global $page;
|
||||||
|
$html = "
|
||||||
|
" . make_form(make_link("tag_edit/replace")) . "
|
||||||
|
<table class='form'>
|
||||||
|
<tr><th>Search</th><td><input type='text' name='search' class='autocomplete_tags'></tr>
|
||||||
|
<tr><th>Replace</th><td><input type='text' name='replace' class='autocomplete_tags'></td></tr>
|
||||||
|
<tr><td colspan='2'><input type='submit' value='Replace'></td></tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
";
|
||||||
|
$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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -56,8 +56,8 @@ class PostTitles extends Extension
|
||||||
{
|
{
|
||||||
global $user;
|
global $user;
|
||||||
|
|
||||||
if ($user->can(Permissions::EDIT_IMAGE_TITLE) && isset($event->params["post_title"])) {
|
if ($user->can(Permissions::EDIT_IMAGE_TITLE) && isset($event->params["title"])) {
|
||||||
send_event(new PostTitleSetEvent($event->image, $event->params["post_title"]));
|
send_event(new PostTitleSetEvent($event->image, $event->params["title"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class PostTitlesTheme extends Themelet
|
||||||
return SHM_POST_INFO(
|
return SHM_POST_INFO(
|
||||||
"Title",
|
"Title",
|
||||||
$title,
|
$title,
|
||||||
$can_set ? INPUT(["type" => "text", "name" => "post_title", "value" => $title]) : null
|
$can_set ? INPUT(["type" => "text", "name" => "title", "value" => $title]) : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,9 +56,9 @@ class Relationships extends Extension
|
||||||
{
|
{
|
||||||
global $user;
|
global $user;
|
||||||
if ($user->can(Permissions::EDIT_IMAGE_RELATIONSHIPS)) {
|
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['tags']) ? !preg_match('/parent[=|:]/', $event->params["tags"]) : true) { //Ignore parent if tags contain parent metatag
|
||||||
if (isset($event->params["tag_edit__parent"]) ? ctype_digit($event->params["tag_edit__parent"]) : false) {
|
if (isset($event->params["parent"]) ? ctype_digit($event->params["parent"]) : false) {
|
||||||
send_event(new ImageRelationshipSetEvent($event->image->id, (int) $event->params["tag_edit__parent"]));
|
send_event(new ImageRelationshipSetEvent($event->image->id, (int) $event->params["parent"]));
|
||||||
} else {
|
} else {
|
||||||
$this->remove_parent($event->image->id);
|
$this->remove_parent($event->image->id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ class RelationshipsTheme extends Themelet
|
||||||
return SHM_POST_INFO(
|
return SHM_POST_INFO(
|
||||||
"Parent",
|
"Parent",
|
||||||
strval($image['parent_id']) ?: "None",
|
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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Shimmie2;
|
|
||||||
|
|
||||||
use MicroHTML\HTMLElement;
|
|
||||||
|
|
||||||
use function MicroHTML\{TR, TH, TD, emptyHTML, rawHTML, joinHTML, DIV, INPUT, A, TEXTAREA};
|
|
||||||
|
|
||||||
class TagEditTheme extends Themelet
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Display a form which links to tag_edit/replace with POST[search]
|
|
||||||
* and POST[replace] set appropriately
|
|
||||||
*/
|
|
||||||
public function display_mass_editor(): void
|
|
||||||
{
|
|
||||||
global $page;
|
|
||||||
$html = "
|
|
||||||
" . make_form(make_link("tag_edit/replace")) . "
|
|
||||||
<table class='form'>
|
|
||||||
<tr><th>Search</th><td><input type='text' name='search' class='autocomplete_tags'></tr>
|
|
||||||
<tr><th>Replace</th><td><input type='text' name='replace' class='autocomplete_tags'></td></tr>
|
|
||||||
<tr><td colspan='2'><input type='submit' value='Replace'></td></tr>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
";
|
|
||||||
$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")) . "
|
|
||||||
<input type='hidden' name='tags' value='$h_terms'>
|
|
||||||
<input type='text' name='source' value=''>
|
|
||||||
<input type='submit' value='Set Source For All' onclick='return confirm(\"This will mass-edit all sources on the page.\\nAre you sure you want to do this?\")'>
|
|
||||||
</form>
|
|
||||||
";
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,11 +7,11 @@ namespace Shimmie2;
|
||||||
class ImageInfoSetEvent extends Event
|
class ImageInfoSetEvent extends Event
|
||||||
{
|
{
|
||||||
public Image $image;
|
public Image $image;
|
||||||
/** @var array<string, mixed> */
|
/** @var array<string, string> */
|
||||||
public array $params;
|
public array $params;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string, mixed> $params
|
* @param array<string, string> $params
|
||||||
*/
|
*/
|
||||||
public function __construct(Image $image, array $params)
|
public function __construct(Image $image, array $params)
|
||||||
{
|
{
|
||||||
|
|
|
@ -75,7 +75,12 @@ class ViewPost extends Extension
|
||||||
$image_id = int_escape($event->req_POST('image_id'));
|
$image_id = int_escape($event->req_POST('image_id'));
|
||||||
$image = Image::by_id($image_id);
|
$image = Image::by_id($image_id);
|
||||||
if (!$image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK)) {
|
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<string, string> */
|
||||||
|
$kvs = array_filter($event->POST, 'is_string', ARRAY_FILTER_USE_KEY);
|
||||||
|
send_event(new ImageInfoSetEvent($image, $kvs));
|
||||||
$page->set_mode(PageMode::REDIRECT);
|
$page->set_mode(PageMode::REDIRECT);
|
||||||
|
|
||||||
if ($event->get_GET('search')) {
|
if ($event->get_GET('search')) {
|
||||||
|
|
Reference in a new issue