diff --git a/core/extension.php b/core/extension.php index d19ececb..158b338b 100644 --- a/core/extension.php +++ b/core/extension.php @@ -375,10 +375,14 @@ abstract class DataHandlerExtension extends Extension // even more hax.. $event->metadata['tags'] = $existing->get_tag_list(); $image = $this->create_image_from_data(warehouse_path(Image::IMAGE_DIR, $event->metadata['hash']), $event->metadata); - if (is_null($image)) { throw new UploadException("Data handler failed to create image object from data"); } + try { + send_event(new MediaCheckPropertiesEvent($image)); + } catch (MediaException $e) { + throw new UploadException("Unable to scan media properties: ".$e->getMessage()); + } $ire = send_event(new ImageReplaceEvent($image_id, $image)); $event->image_id = $image_id; @@ -387,6 +391,12 @@ abstract class DataHandlerExtension extends Extension if (is_null($image)) { throw new UploadException("Data handler failed to create image object from data"); } + try { + send_event(new MediaCheckPropertiesEvent($image)); + } catch (MediaException $e) { + throw new UploadException("Unable to scan media properties: ".$e->getMessage()); + } + $iae = send_event(new ImageAdditionEvent($image)); $event->image_id = $iae->image->id; $event->merged = $iae->merged; @@ -404,6 +414,7 @@ abstract class DataHandlerExtension extends Extension } } } elseif ($supported_ext && !$check_contents) { + // We DO support this extension - but the file looks corrupt throw new UploadException("Invalid or corrupted file"); } } @@ -435,15 +446,6 @@ abstract class DataHandlerExtension extends Extension } } - /* - public function onSetupBuilding(SetupBuildingEvent $event) { - $sb = $this->setup(); - if($sb) $event->panel->add_block($sb); - } - - protected function setup() {} - */ - abstract protected function supported_ext(string $ext): bool; abstract protected function check_contents(string $tmpname): bool; abstract protected function create_image_from_data(string $filename, array $metadata); diff --git a/core/imageboard/image.php b/core/imageboard/image.php index 99c23146..7b9f3854 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -60,12 +60,18 @@ class Image /** @var boolean */ public $video = null; + /** @var boolean */ + public $image = null; + /** @var boolean */ public $audio = null; /** @var int */ public $length = null; + public static $bool_props = ["locked", "lossless", "video", "audio"]; + public static $int_props = ["id", "owner_id", "height", "width", "filesize", "length"]; + /** * One will very rarely construct an image directly, more common * would be to use Image::by_id, Image::by_hash, etc. @@ -78,9 +84,11 @@ class Image $name = str_replace("images.", "", $name); // hax, this is likely the cause of much scrutinizer-ci complaints. - if (in_array($name, ["locked", "lossless", "video", "audio"])) { + if (is_null($value)) { + $this->$name = null; + } elseif (in_array($name, self::$bool_props)) { $this->$name = bool_escape((string)$value); - } elseif (in_array($name, ["id", "owner_id", "height", "width", "filesize", "length"])) { + } elseif (in_array($name, self::$int_props)) { $this->$name = int_escape((string)$value); } else { $this->$name = $value; @@ -356,6 +364,70 @@ class Image } } + public function save_to_db() + { + global $database, $user; + $cut_name = substr($this->filename, 0, 255); + + if (is_null($this->id)) { + $database->execute( + "INSERT INTO images( + owner_id, owner_ip, + filename, filesize, + hash, ext, + width, height, + posted, source + ) + VALUES ( + :owner_id, :owner_ip, + :filename, :filesize, + :hash, :ext, + 0, 0, + now(), :source + )", + [ + "owner_id" => $user->id, "owner_ip" => $_SERVER['REMOTE_ADDR'], + "filename" => $cut_name, "filesize" => $this->filesize, + "hash" => $this->hash, "ext" => strtolower($this->ext), + "source" => $this->source + ] + ); + $this->id = $database->get_last_insert_id('images_id_seq'); + } else { + $database->execute( + "UPDATE images SET ". + "filename = :filename, filesize = :filesize, hash = :hash, ". + "ext = :ext, width = 0, height = 0, source = :source ". + "WHERE id = :id", + [ + "filename" => $cut_name, + "filesize" => $this->filesize, + "hash" => $this->hash, + "ext" => strtolower($this->ext), + "source" => $this->source, + "id" => $this->id, + ] + ); + } + + $database->execute( + "UPDATE images SET ". + "lossless = :lossless, ". + "video = :video, audio = :audio,image = :image, ". + "height = :height, width = :width, ". + "length = :length WHERE id = :id", + [ + "id" => $this->id, + "width" => $this->width ?? 0, + "height" => $this->height ?? 0, + "lossless" => $database->scoresql_value_prepare($this->lossless), + "video" => $database->scoresql_value_prepare($this->video), + "image" => $database->scoresql_value_prepare($this->image), + "audio" => $database->scoresql_value_prepare($this->audio), + "length" => $this->length + ] + ); + } /** * Get this image's tags as an array. * diff --git a/ext/admin/test.php b/ext/admin/test.php index 3b86ef6b..0e4852bf 100644 --- a/ext/admin/test.php +++ b/ext/admin/test.php @@ -3,17 +3,17 @@ class AdminPageTest extends ShimmiePHPUnitTestCase { public function testAuth() { - send_event(new UserLoginEvent(User::by_name($this->anon_name))); + send_event(new UserLoginEvent(User::by_name(self::$anon_name))); $page = $this->get_page('admin'); $this->assertEquals(403, $page->code); $this->assertEquals("Permission Denied", $page->title); - send_event(new UserLoginEvent(User::by_name($this->user_name))); + send_event(new UserLoginEvent(User::by_name(self::$user_name))); $page = $this->get_page('admin'); $this->assertEquals(403, $page->code); $this->assertEquals("Permission Denied", $page->title); - send_event(new UserLoginEvent(User::by_name($this->admin_name))); + send_event(new UserLoginEvent(User::by_name(self::$admin_name))); $page = $this->get_page('admin'); $this->assertEquals(200, $page->code); $this->assertEquals("Admin Tools", $page->title); @@ -23,7 +23,7 @@ class AdminPageTest extends ShimmiePHPUnitTestCase { // Create a problem $ts = time(); // we need a tag that hasn't been used before - send_event(new UserLoginEvent(User::by_name($this->admin_name))); + send_event(new UserLoginEvent(User::by_name(self::$admin_name))); $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "TeStCase$ts"); // Validate problem @@ -53,7 +53,7 @@ class AdminPageTest extends ShimmiePHPUnitTestCase // Create a problem $ts = time(); // we need a tag that hasn't been used before - send_event(new UserLoginEvent(User::by_name($this->admin_name))); + send_event(new UserLoginEvent(User::by_name(self::$admin_name))); $database->execute( "INSERT INTO tags(tag, count) VALUES(:tag, :count)", ["tag"=>"tes$ts", "count"=>42] @@ -74,7 +74,7 @@ class AdminPageTest extends ShimmiePHPUnitTestCase public function testCommands() { - send_event(new UserLoginEvent(User::by_name($this->admin_name))); + send_event(new UserLoginEvent(User::by_name(self::$admin_name))); ob_start(); send_event(new CommandEvent(["index.php", "help"])); send_event(new CommandEvent(["index.php", "get-page", "post/list"])); @@ -82,5 +82,8 @@ class AdminPageTest extends ShimmiePHPUnitTestCase send_event(new CommandEvent(["index.php", "get-token"])); send_event(new CommandEvent(["index.php", "regen-thumb", "42"])); ob_end_clean(); + + // don't crash + $this->assertTrue(true); } } diff --git a/ext/artists/main.php b/ext/artists/main.php index ac5b6c66..81f99399 100644 --- a/ext/artists/main.php +++ b/ext/artists/main.php @@ -48,8 +48,8 @@ class Artists extends Extension $matches = []; if (preg_match("/^(author|artist)[=|:](.*)$/i", $event->term, $matches)) { - $char = $matches[1]; - $event->add_querylet(new Querylet("Author = :author_char", ["author_char"=>$char])); + $char = $matches[2]; + $event->add_querylet(new Querylet("author = :author_char", ["author_char"=>$char])); } } @@ -63,7 +63,6 @@ class Artists extends Extension } } - public function onDatabaseUpgrade(DatabaseUpgradeEvent $event) { global $config, $database; diff --git a/ext/artists/test.php b/ext/artists/test.php index 2fa2cdd8..cedde48e 100644 --- a/ext/artists/test.php +++ b/ext/artists/test.php @@ -3,8 +3,13 @@ class ArtistsTest extends ShimmiePHPUnitTestCase { public function testSearch() { - # FIXME: check that the results are there - $this->get_page("post/list/author=bob/1"); - #$this->assert_response(200); + global $user; + $this->log_in_as_user(); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + $image = Image::by_id($image_id); + + send_event(new AuthorSetEvent($image, $user, "bob")); + + $this->assert_search_results(["author=bob"], [$image_id]); } } diff --git a/ext/autocomplete/test.php b/ext/autocomplete/test.php index 4df7675c..40c6b4c9 100644 --- a/ext/autocomplete/test.php +++ b/ext/autocomplete/test.php @@ -5,7 +5,7 @@ class AutoCompleteTest extends ShimmiePHPUnitTestCase { public function testAuth() { - send_event(new UserLoginEvent(User::by_name($this->anon_name))); + send_event(new UserLoginEvent(User::by_name(self::$anon_name))); $page = $this->get_page('api/internal/autocomplete', ["s"=>"not-a-tag"]); $this->assertEquals(200, $page->code); $this->assertEquals(PageMode::DATA, $page->mode); diff --git a/ext/blotter/test.php b/ext/blotter/test.php index a7bd9b9d..b512f2b0 100644 --- a/ext/blotter/test.php +++ b/ext/blotter/test.php @@ -1,14 +1,6 @@ log_in_as_admin(); - //$this->assert_text("Blotter Editor"); - //$this->click("Blotter Editor"); - //$this->log_out(); - } - public function testDenial() { $this->get_page("blotter/editor"); @@ -23,7 +15,8 @@ class BlotterTest extends ShimmiePHPUnitTestCase { $this->log_in_as_admin(); - $this->get_page("blotter/editor"); + $page = $this->get_page("blotter/editor"); + $this->assertEquals(200, $page->code); //$this->set_field("entry_text", "blotter testing"); //$this->click("Add"); //$this->assert_text("blotter testing"); diff --git a/ext/browser_search/test.php b/ext/browser_search/test.php index a41421d1..03e80a93 100644 --- a/ext/browser_search/test.php +++ b/ext/browser_search/test.php @@ -3,7 +3,10 @@ class BrowserSearchTest extends ShimmiePHPUnitTestCase { public function testBasic() { - $this->get_page("browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml"); - $this->get_page("browser_search/test"); + $page = $this->get_page("browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml"); + $this->assertEquals(200, $page->code); + + $page = $this->get_page("browser_search/test"); + $this->assertEquals(200, $page->code); } } diff --git a/ext/bulk_add/test.php b/ext/bulk_add/test.php index 7a19755c..48dad449 100644 --- a/ext/bulk_add/test.php +++ b/ext/bulk_add/test.php @@ -4,7 +4,7 @@ class BulkAddTest extends ShimmiePHPUnitTestCase { public function testInvalidDir() { - send_event(new UserLoginEvent(User::by_name($this->admin_name))); + send_event(new UserLoginEvent(User::by_name(self::$admin_name))); $bae = send_event(new BulkAddEvent('asdf')); $this->assertContains( "Error, asdf is not a readable directory", @@ -15,7 +15,7 @@ class BulkAddTest extends ShimmiePHPUnitTestCase public function testValidDir() { - send_event(new UserLoginEvent(User::by_name($this->admin_name))); + send_event(new UserLoginEvent(User::by_name(self::$admin_name))); send_event(new BulkAddEvent('tests')); $page = $this->get_page("post/list/hash=17fc89f372ed3636e28bd25cc7f3bac1/1"); $this->assertEquals(302, $page->code); diff --git a/ext/danbooru_api/test.php b/ext/danbooru_api/test.php index d085db82..f2a82e0a 100644 --- a/ext/danbooru_api/test.php +++ b/ext/danbooru_api/test.php @@ -15,8 +15,8 @@ class DanbooruApiTest extends ShimmiePHPUnitTestCase $this->get_page("api/danbooru/find_tags?id=1"); $this->get_page("api/danbooru/find_tags?name=data"); - $this->get_page("api/danbooru/post/show/$image_id"); - //$this->assert_response(302); // FIXME + $page = $this->get_page("api/danbooru/post/show/$image_id"); + $this->assertEquals(302, $page->code); $this->get_page("post/list/md5:17fc89f372ed3636e28bd25cc7f3bac1/1"); //$this->assert_title(new PatternExpectation("/^Image \d+: data/")); diff --git a/ext/handle_flash/main.php b/ext/handle_flash/main.php index 3d52a89c..7520cfbf 100644 --- a/ext/handle_flash/main.php +++ b/ext/handle_flash/main.php @@ -6,17 +6,17 @@ class FlashFileHandler extends DataHandlerExtension { switch ($event->ext) { case "swf": - $event->lossless = true; - $event->video = true; + $event->image->lossless = true; + $event->image->video = true; $info = getimagesize($event->file_name); if (!$info) { return null; } - $event->image = false; + $event->image->image = false; - $event->width = $info[0]; - $event->height = $info[1]; + $event->image->width = $info[0]; + $event->image->height = $info[1]; break; } diff --git a/ext/handle_ico/main.php b/ext/handle_ico/main.php index 3920e8ff..28599302 100644 --- a/ext/handle_ico/main.php +++ b/ext/handle_ico/main.php @@ -4,15 +4,13 @@ class IcoFileHandler extends DataHandlerExtension { const SUPPORTED_EXTENSIONS = ["ico", "ani", "cur"]; - public function onMediaCheckProperties(MediaCheckPropertiesEvent $event) { if (in_array($event->ext, self::SUPPORTED_EXTENSIONS)) { - $event->lossless = true; - $event->video = false; - $event->audio = false; - $event->image = ($event->ext!="ani"); - + $event->image->lossless = true; + $event->image->video = false; + $event->image->audio = false; + $event->image->image = ($event->ext!="ani"); $fp = fopen($event->file_name, "r"); try { @@ -24,12 +22,11 @@ class IcoFileHandler extends DataHandlerExtension $width = $subheader['width']; $height = $subheader['height']; - $event->width = $width == 0 ? 256 : $width; - $event->height = $height == 0 ? 256 : $height; + $event->image->width = $width == 0 ? 256 : $width; + $event->image->height = $height == 0 ? 256 : $height; } } - protected function supported_ext(string $ext): bool { return in_array(strtolower($ext), self::SUPPORTED_EXTENSIONS); diff --git a/ext/handle_ico/test.php b/ext/handle_ico/test.php index 39cf1123..2c3b9b93 100644 --- a/ext/handle_ico/test.php +++ b/ext/handle_ico/test.php @@ -5,7 +5,9 @@ class IcoFileHandlerTest extends ShimmiePHPUnitTestCase { $this->log_in_as_user(); $image_id = $this->post_image("ext/handle_static/static/favicon.ico", "shimmie favicon"); - $this->get_page("post/view/$image_id"); // test for no crash + + $page = $this->get_page("post/view/$image_id"); + $this->assertEquals(200, $page->code); # FIXME: test that the thumb works # FIXME: test that it gets displayed properly diff --git a/ext/handle_mp3/main.php b/ext/handle_mp3/main.php index 21c656cc..f36b05ca 100644 --- a/ext/handle_mp3/main.php +++ b/ext/handle_mp3/main.php @@ -6,10 +6,10 @@ class MP3FileHandler extends DataHandlerExtension { switch ($event->ext) { case "mp3": - $event->audio = true; - $event->video = false; - $event->lossless = false; - $event->image = false; + $event->image->audio = true; + $event->image->video = false; + $event->image->lossless = false; + $event->image->image = false; break; } // TODO: Buff out audio format support, length scanning diff --git a/ext/handle_pixel/main.php b/ext/handle_pixel/main.php index 41aff1cc..79b42e12 100644 --- a/ext/handle_pixel/main.php +++ b/ext/handle_pixel/main.php @@ -4,45 +4,42 @@ class PixelFileHandler extends DataHandlerExtension { const SUPPORTED_EXTENSIONS = ["jpg", "jpeg", "gif", "png", "webp"]; - public function onMediaCheckProperties(MediaCheckPropertiesEvent $event) { if (in_array($event->ext, Media::LOSSLESS_FORMATS)) { - $event->lossless = true; + $event->image->lossless = true; } elseif ($event->ext=="webp") { - $event->lossless = Media::is_lossless_webp($event->file_name); + $event->image->lossless = Media::is_lossless_webp($event->file_name); } if (in_array($event->ext, self::SUPPORTED_EXTENSIONS)) { - if ($event->lossless==null) { - $event->lossless = false; + if ($event->image->lossless==null) { + $event->image->lossless = false; } - $event->audio = false; + $event->image->audio = false; switch ($event->ext) { case "gif": - $event->video = Media::is_animated_gif($event->file_name); + $event->image->video = Media::is_animated_gif($event->file_name); break; case "webp": - $event->video = Media::is_animated_webp($event->file_name); + $event->image->video = Media::is_animated_webp($event->file_name); break; default: - $event->video = false; + $event->image->video = false; break; } - $event->image = !$event->video; + $event->image->image = !$event->image->video; $info = getimagesize($event->file_name); if (!$info) { return null; } - $event->width = $info[0]; - $event->height = $info[1]; + $event->image->width = $info[0]; + $event->image->height = $info[1]; } } - - protected function supported_ext(string $ext): bool { $ext = (($pos = strpos($ext, '?')) !== false) ? substr($ext, 0, $pos) : $ext; diff --git a/ext/handle_pixel/test.php b/ext/handle_pixel/test.php index c0766156..f71c2229 100644 --- a/ext/handle_pixel/test.php +++ b/ext/handle_pixel/test.php @@ -5,6 +5,8 @@ class PixelFileHandlerTest extends ShimmiePHPUnitTestCase { $this->log_in_as_user(); $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + $page = $this->get_page("post/view/$image_id"); + $this->assertEquals(200, $page->code); //$this->assert_response(302); # FIXME: test that the thumb works diff --git a/ext/handle_svg/main.php b/ext/handle_svg/main.php index f67daf91..2419e3ba 100644 --- a/ext/handle_svg/main.php +++ b/ext/handle_svg/main.php @@ -7,20 +7,19 @@ class SVGFileHandler extends DataHandlerExtension { switch ($event->ext) { case "svg": - $event->lossless = true; - $event->video = false; - $event->audio = false; - $event->image = true; + $event->image->lossless = true; + $event->image->video = false; + $event->image->audio = false; + $event->image->image = true; $msp = new MiniSVGParser($event->file_name); - $event->width = $msp->width; - $event->height = $msp->height; + $event->image->width = $msp->width; + $event->image->height = $msp->height; break; } } - public function onDataUpload(DataUploadEvent $event) { if ($this->supported_ext($event->type) && $this->check_contents($event->tmpname)) { diff --git a/ext/handle_video/main.php b/ext/handle_video/main.php index a77f7444..5871325b 100644 --- a/ext/handle_video/main.php +++ b/ext/handle_video/main.php @@ -31,8 +31,8 @@ class VideoFileHandler extends DataHandlerExtension public function onMediaCheckProperties(MediaCheckPropertiesEvent $event) { if (in_array($event->ext, self::SUPPORTED_EXT)) { - $event->video = true; - $event->image = false; + $event->image->video = true; + $event->image->image = false; try { $data = Media::get_ffprobe_data($event->file_name); @@ -57,22 +57,22 @@ class VideoFileHandler extends DataHandlerExtension } if (array_key_exists("width", $stream) && !empty($stream["width"]) && is_numeric($stream["width"]) && intval($stream["width"]) > ($event->width) ?? 0) { - $event->width = intval($stream["width"]); + $event->image->width = intval($stream["width"]); } if (array_key_exists("height", $stream) && !empty($stream["height"]) && is_numeric($stream["height"]) && intval($stream["height"]) > ($event->height) ?? 0) { - $event->height = intval($stream["height"]); + $event->image->height = intval($stream["height"]); } } } - $event->video = $video; - $event->audio = $audio; + $event->image->video = $video; + $event->image->audio = $audio; } } if (array_key_exists("format", $data)&& is_array($data["format"])) { $format = $data["format"]; if (array_key_exists("duration", $format) && is_numeric($format["duration"])) { - $event->length = floor(floatval($format["duration"]) * 1000); + $event->image->length = floor(floatval($format["duration"]) * 1000); } } } diff --git a/ext/home/test.php b/ext/home/test.php index 9ae69d3c..8d4b0eec 100644 --- a/ext/home/test.php +++ b/ext/home/test.php @@ -3,12 +3,7 @@ class HomeTest extends ShimmiePHPUnitTestCase { public function testHomePage() { - $this->get_page('home'); - - // FIXME: this page doesn't use blocks; need assert_data_contains - //$this->assert_title('Shimmie'); - //$this->assert_text('Shimmie'); - - # FIXME: test search box + $page = $this->get_page('home'); + $this->assertStringContainsString("Posts", $page->data); } } diff --git a/ext/image/main.php b/ext/image/main.php index d1034d5d..e6ef995b 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -93,8 +93,60 @@ class ImageIO extends Extension public function onImageAddition(ImageAdditionEvent $event) { + global $config; + try { - $this->add_image($event); + $image = $event->image; + + /* + * Validate things + */ + if (strlen(trim($image->source ?? '')) == 0) { + $image->source = null; + } + + /* + * Check for an existing image + */ + $existing = Image::by_hash($image->hash); + if (!is_null($existing)) { + $handler = $config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER); + if ($handler == ImageConfig::COLLISION_MERGE || isset($_GET['update'])) { + $merged = array_merge($image->get_tag_array(), $existing->get_tag_array()); + send_event(new TagSetEvent($existing, $merged)); + if (isset($_GET['rating']) && isset($_GET['update']) && Extension::is_enabled(RatingsInfo::KEY)) { + send_event(new RatingSetEvent($existing, $_GET['rating'])); + } + if (isset($_GET['source']) && isset($_GET['update'])) { + send_event(new SourceSetEvent($existing, $_GET['source'])); + } + $event->merged = true; + $event->image = Image::by_id($existing->id); + return; + } else { + $error = "Image {$existing->id} ". + "already has hash {$image->hash}:
".$this->theme->build_thumb_html($existing); + throw new ImageAdditionException($error); + } + } + + // actually insert the info + $image->save_to_db(); + + log_info("image", "Uploaded Image #{$image->id} ({$image->hash})"); + + # at this point in time, the image's tags haven't really been set, + # and so, having $image->tag_array set to something is a lie (but + # a useful one, as we want to know what the tags are /supposed/ to + # be). Here we correct the lie, by first nullifying the wrong tags + # then using the standard mechanism to set them properly. + $tags_to_set = $image->get_tag_array(); + $image->tag_array = []; + send_event(new TagSetEvent($image, $tags_to_set)); + + if ($image->source !== null) { + log_info("core-image", "Source for Image #{$image->id} set to: {$image->source}"); + } } catch (ImageAdditionException $e) { throw new UploadException($e->error); } @@ -108,7 +160,43 @@ class ImageIO extends Extension public function onImageReplace(ImageReplaceEvent $event) { try { - $this->replace_image($event->id, $event->image); + $id = $event->id; + $image = $event->image; + + /* Check to make sure the image exists. */ + $existing = Image::by_id($id); + + if (is_null($existing)) { + throw new ImageReplaceException("Image to replace does not exist!"); + } + + $duplicate = Image::by_hash($image->hash); + if (!is_null($duplicate) && $duplicate->id!=$id) { + $error = "Image {$duplicate->id} " . + "already has hash {$image->hash}:
" . $this->theme->build_thumb_html($duplicate); + throw new ImageReplaceException($error); + } + + if (strlen(trim($image->source)) == 0) { + $image->source = $existing->get_source(); + } + + // Update the data in the database. + $image->save_to_db(); + + /* + This step could be optional, ie: perhaps move the image somewhere + and have it stored in a 'replaced images' list that could be + inspected later by an admin? + */ + + log_debug("image", "Removing image with hash " . $existing->hash); + $existing->remove_image_only(); // Actually delete the old image file from disk + + /* Generate new thumbnail */ + send_event(new ThumbnailGenerationEvent($image->hash, strtolower($image->ext))); + + log_info("image", "Replaced Image #{$id} with ({$image->hash})"); } catch (ImageReplaceException $e) { throw new UploadException($e->error); } @@ -159,83 +247,6 @@ class ImageIO extends Extension $event->panel->add_block($sb); } - private function add_image(ImageAdditionEvent $event) - { - global $user, $database, $config; - - $image = $event->image; - - /* - * Validate things - */ - if (strlen(trim($image->source ?? '')) == 0) { - $image->source = null; - } - - /* - * Check for an existing image - */ - $existing = Image::by_hash($image->hash); - if (!is_null($existing)) { - $handler = $config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER); - if ($handler == ImageConfig::COLLISION_MERGE || isset($_GET['update'])) { - $merged = array_merge($image->get_tag_array(), $existing->get_tag_array()); - send_event(new TagSetEvent($existing, $merged)); - if (isset($_GET['rating']) && isset($_GET['update']) && Extension::is_enabled(RatingsInfo::KEY)) { - send_event(new RatingSetEvent($existing, $_GET['rating'])); - } - if (isset($_GET['source']) && isset($_GET['update'])) { - send_event(new SourceSetEvent($existing, $_GET['source'])); - } - $event->merged = true; - $event->image = Image::by_id($existing->id); - return; - } else { - $error = "Image {$existing->id} ". - "already has hash {$image->hash}:
".$this->theme->build_thumb_html($existing); - throw new ImageAdditionException($error); - } - } - - // actually insert the info - $database->Execute( - "INSERT INTO images( - owner_id, owner_ip, filename, filesize, - hash, ext, width, height, posted, source - ) - VALUES ( - :owner_id, :owner_ip, :filename, :filesize, - :hash, :ext, 0, 0, now(), :source - )", - [ - "owner_id" => $user->id, "owner_ip" => $_SERVER['REMOTE_ADDR'], "filename" => substr($image->filename, 0, 255), "filesize" => $image->filesize, - "hash" => $image->hash, "ext" => strtolower($image->ext), "source" => $image->source - ] - ); - $image->id = $database->get_last_insert_id('images_id_seq'); - - log_info("image", "Uploaded Image #{$image->id} ({$image->hash})"); - - # at this point in time, the image's tags haven't really been set, - # and so, having $image->tag_array set to something is a lie (but - # a useful one, as we want to know what the tags are /supposed/ to - # be). Here we correct the lie, by first nullifying the wrong tags - # then using the standard mechanism to set them properly. - $tags_to_set = $image->get_tag_array(); - $image->tag_array = []; - send_event(new TagSetEvent($image, $tags_to_set)); - - if ($image->source !== null) { - log_info("core-image", "Source for Image #{$image->id} set to: {$image->source}"); - } - - try { - Media::update_image_media_properties($image->hash, strtolower($image->ext)); - } catch (MediaException $e) { - log_warning("add_image", "Error while running update_image_media_properties: ".$e->getMessage()); - } - } - private function send_file(int $image_id, string $type) { global $config; @@ -294,66 +305,4 @@ class ImageIO extends Extension )); } } - - private function replace_image(int $id, Image $image) - { - global $database; - - /* Check to make sure the image exists. */ - $existing = Image::by_id($id); - - if (is_null($existing)) { - throw new ImageReplaceException("Image to replace does not exist!"); - } - - $duplicate = Image::by_hash($image->hash); - - if (!is_null($duplicate) && $duplicate->id!=$id) { - $error = "Image {$duplicate->id} " . - "already has hash {$image->hash}:
" . $this->theme->build_thumb_html($duplicate); - throw new ImageReplaceException($error); - } - - if (strlen(trim($image->source)) == 0) { - $image->source = $existing->get_source(); - } - - // Update the data in the database. - $database->Execute( - "UPDATE images SET - filename = :filename, filesize = :filesize, hash = :hash, - ext = :ext, width = 0, height = 0, source = :source - WHERE - id = :id - ", - [ - "filename" => substr($image->filename, 0, 255), - "filesize" => $image->filesize, - "hash" => $image->hash, - "ext" => strtolower($image->ext), - "source" => $image->source, - "id" => $id, - ] - ); - - /* - This step could be optional, ie: perhaps move the image somewhere - and have it stored in a 'replaced images' list that could be - inspected later by an admin? - */ - - log_debug("image", "Removing image with hash " . $existing->hash); - $existing->remove_image_only(); // Actually delete the old image file from disk - - try { - Media::update_image_media_properties($image->hash, $image->ext); - } catch (MediaException $e) { - log_warning("image_replace", "Error while running update_image_media_properties: ".$e->getMessage()); - } - - /* Generate new thumbnail */ - send_event(new ThumbnailGenerationEvent($image->hash, strtolower($image->ext))); - - log_info("image", "Replaced Image #{$id} with ({$image->hash})"); - } } diff --git a/ext/image/test.php b/ext/image/test.php index a8bed548..0ec87810 100644 --- a/ext/image/test.php +++ b/ext/image/test.php @@ -14,7 +14,10 @@ class ImageIOTest extends ShimmiePHPUnitTestCase //$this->assert_title("Image $image_id: test"); # test that serving manually doesn't cause errors - $this->get_page("image/$image_id/moo.jpg"); - $this->get_page("thumb/$image_id/moo.jpg"); + $page = $this->get_page("image/$image_id/moo.jpg"); + $this->assertEquals(200, $page->code); + + $page = $this->get_page("thumb/$image_id/moo.jpg"); + $this->assertEquals(200, $page->code); } } diff --git a/ext/index/test.php b/ext/index/test.php index d81c7e66..cdbb1e13 100644 --- a/ext/index/test.php +++ b/ext/index/test.php @@ -1,20 +1,6 @@ log_in_as_user(); - $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "thing computer screenshot pbx phone"); - $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "thing computer computing bedroom workshop"); - $this->log_out(); - - # make sure both uploads were ok - $this->assertTrue($image_id_1 > 0); - $this->assertTrue($image_id_2 > 0); - - return [$image_id_1, $image_id_2]; - } - public function testIndexPage() { $this->get_page('post/list'); @@ -23,6 +9,7 @@ class IndexTest extends ShimmiePHPUnitTestCase $this->log_in_as_user(); $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + $this->post_image("tests/bedroom_workshop.jpg", "thing computer computing bedroom workshop"); $this->log_out(); $this->get_page('post/list'); @@ -41,173 +28,153 @@ class IndexTest extends ShimmiePHPUnitTestCase $this->get_page('post/list/99999'); $this->assert_response(404); + + # No results: 404 + $this->get_page('post/list/maumaumau/1'); + $this->assert_response(404); + + # One result: 302 + $this->get_page("post/list/pbx/1"); + $this->assert_response(302); + + # Multiple results: 200 + $this->get_page('post/list/computer/1'); + $this->assert_response(200); + } + + // base case + public function testUpload() + { + $this->log_in_as_user(); + $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "thing computer screenshot pbx phone"); + $image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "thing computer computing bedroom workshop"); + $this->log_out(); + + # make sure both uploads were ok + $this->assertTrue($image_id_1 > 0); + $this->assertTrue($image_id_2 > 0); + + return [$image_id_1, $image_id_2]; } /* * * * * * * * * * * * Tag Search * * * * * * * * * * * */ - public function testTagSearchNoResults() + /** @depends testUpload */ + public function testTagSearchNoResults($image_ids) { - $image_ids = $this->upload(); - - $this->get_page('post/list/maumaumau/1'); - $this->assert_response(404); + $this->assert_search_results(["maumaumau"], []); } - public function testTagSearchOneResult() + /** @depends testUpload */ + public function testTagSearchOneResult($image_ids) { - $image_ids = $this->upload(); - - $this->get_page("post/list/pbx/1"); - $this->assert_response(302); + $this->assert_search_results(["pbx"], [$image_ids[0]]); } - public function testTagSearchManyResults() + /** @depends testUpload */ + public function testTagSearchManyResults($image_ids) { - $image_ids = $this->upload(); - - $this->get_page('post/list/computer/1'); - $this->assert_response(200); - $this->assert_title("computer"); + $this->assert_search_results(["computer"], [$image_ids[1], $image_ids[0]]); } /* * * * * * * * * * * * Multi-Tag Search * * * * * * * * * * * */ - public function testMultiTagSearchNoResults() + /** @depends testUpload */ + public function testMultiTagSearchNoResults($image_ids) { - $image_ids = $this->upload(); - # multiple tags, one of which doesn't exist # (test the "one tag doesn't exist = no hits" path) - $this->get_page('post/list/computer asdfasdfwaffle/1'); - $this->assert_response(404); + $this->assert_search_results(["computer", "asdfasdfwaffle"], []); } - public function testMultiTagSearchOneResult() + /** @depends testUpload */ + public function testMultiTagSearchOneResult($image_ids) { - $image_ids = $this->upload(); - - $this->get_page('post/list/computer screenshot/1'); - $this->assert_response(302); + $this->assert_search_results(["computer", "screenshot"], [$image_ids[0]]); } - public function testMultiTagSearchManyResults() + /** @depends testUpload */ + public function testMultiTagSearchManyResults($image_ids) { - $image_ids = $this->upload(); - - $this->get_page('post/list/computer thing/1'); - $this->assert_response(200); + $this->assert_search_results(["computer", "thing"], [$image_ids[1], $image_ids[0]]); } /* * * * * * * * * * * * Meta Search * * * * * * * * * * * */ - public function testMetaSearchNoResults() + /** @depends testUpload */ + public function testMetaSearchNoResults($image_ids) { - $this->get_page('post/list/hash=1234567890/1'); - $this->assert_response(404); + $this->assert_search_results(["hash=1234567890"], []); } - public function testMetaSearchOneResult() + /** @depends testUpload */ + public function testMetaSearchOneResult($image_ids) { - $image_ids = $this->upload(); - - $this->get_page("post/list/hash=feb01bab5698a11dd87416724c7a89e3/1"); - $this->assert_response(302); - - $this->get_page("post/list/md5=feb01bab5698a11dd87416724c7a89e3/1"); - $this->assert_response(302); - - $this->get_page("post/list/id={$image_ids[1]}/1"); - $this->assert_response(302); - - $this->get_page("post/list/filename=screenshot/1"); - $this->assert_response(302); + $this->assert_search_results(["hash=feb01bab5698a11dd87416724c7a89e3"], [$image_ids[0]]); + $this->assert_search_results(["md5=feb01bab5698a11dd87416724c7a89e3"], [$image_ids[0]]); + $this->assert_search_results(["id={$image_ids[1]}"], [$image_ids[1]]); + $this->assert_search_results(["filename=screenshot"], [$image_ids[0]]); } - public function testMetaSearchManyResults() + /** @depends testUpload */ + public function testMetaSearchManyResults($image_ids) { - $image_ids = $this->upload(); - - $this->get_page('post/list/size=640x480/1'); - $this->assert_response(200); - - $this->get_page("post/list/tags=5/1"); - $this->assert_response(200); - - $this->get_page("post/list/ext=jpg/1"); - $this->assert_response(200); + $this->assert_search_results(["size=640x480"], [$image_ids[1], $image_ids[0]]); + $this->assert_search_results(["tags=5"], [$image_ids[1], $image_ids[0]]); + $this->assert_search_results(["ext=jpg"], [$image_ids[1], $image_ids[0]]); } /* * * * * * * * * * * * Wildcards * * * * * * * * * * * */ - public function testWildSearchNoResults() + /** @depends testUpload */ + public function testWildSearchNoResults($image_ids) { - $image_ids = $this->upload(); - - $this->get_page("post/list/asdfasdf*/1"); - $this->assert_response(404); + $this->assert_search_results(["asdfasdf*"], []); } - public function testWildSearchOneResult() + /** @depends testUpload */ + public function testWildSearchOneResult($image_ids) { - $image_ids = $this->upload(); - // Only the first image matches both the wildcard and the tag. // This checks for https://github.com/shish/shimmie2/issues/547 - // (comp* is expanded to "computer computing", then we searched - // for images which match two or more of the tags in - // "computer computing screenshot") - $this->get_page("post/list/comp* screenshot/1"); - $this->assert_response(302); + $this->assert_search_results(["comp*", "screenshot"], [$image_ids[0]]); } - public function testWildSearchManyResults() + /** @depends testUpload */ + public function testWildSearchManyResults($image_ids) { - $image_ids = $this->upload(); - // two images match comp* - one matches it once, // one matches it twice - $this->get_page("post/list/comp*/1"); - $this->assert_response(200); + $this->assert_search_results(["comp*"], [$image_ids[1], $image_ids[0]]); } /* * * * * * * * * * * * Mixed * * * * * * * * * * * */ - public function testMixedSearchTagMeta() + /** @depends testUpload */ + public function testMixedSearchTagMeta($image_ids) { - $image_ids = $this->upload(); - - # multiple tags, many results - $this->get_page('post/list/computer size=640x480/1'); - $this->assert_response(200); + global $database; + // multiple tags, many results + $this->assert_search_results(["computer", "size=640x480"], [$image_ids[1], $image_ids[0]]); } // tag + negative // wildcards + ??? /* * * * * * * * * * * - * Other * - * - negative tags * - * - wildcards * + * Negative * * * * * * * * * * * */ - public function testOther() + /** @depends testUpload */ + public function testNegative($image_ids) { - $image_ids = $this->upload(); + // negative tag, should have one result + $this->assert_search_results(["computer", "-pbx"], [$image_ids[1]]); - # negative tag, should have one result - $this->get_page('post/list/computer -pbx/1'); - $this->assert_response(302); - - # negative tag alone, should work - # FIXME: known broken in mysql - $this->get_page('post/list/-pbx/1'); - $this->assert_response(302); - - # test various search methods - $this->get_page("post/list/bedroo*/1"); - $this->assert_response(302); + // negative tag alone, should work + $this->assert_search_results(["-pbx"], [$image_ids[1]]); } } diff --git a/ext/ipban/test.php b/ext/ipban/test.php index 1c6dbb5e..813a32ac 100644 --- a/ext/ipban/test.php +++ b/ext/ipban/test.php @@ -50,7 +50,9 @@ class IPBanTest extends ShimmiePHPUnitTestCase public function test_all() { + // just test it doesn't crash for now $this->log_in_as_admin(); - $this->get_page('ip_ban/list?r_all=on'); // just test it doesn't crash for now + $page = $this->get_page('ip_ban/list', ['r_all'=>'on']); + $this->assertEquals(200, $page->code); } } diff --git a/ext/log_db/test.php b/ext/log_db/test.php index 26a2070a..09bd7b24 100644 --- a/ext/log_db/test.php +++ b/ext/log_db/test.php @@ -5,9 +5,11 @@ class LogDatabaseTest extends ShimmiePHPUnitTestCase { $this->log_in_as_admin(); $this->get_page("log/view"); - $this->get_page("log/view?module=core-image"); - $this->get_page("log/view?time=2012-03-01"); - $this->get_page("log/view?user=demo"); - $this->get_page("log/view?priority=10"); + $this->get_page("log/view", ["r_module"=>"core-image"]); + $this->get_page("log/view", ["r_time"=>"2012-03-01"]); + $this->get_page("log/view", ["r_user"=>"demo"]); + + $page = $this->get_page("log/view", ["r_priority"=>"10"]); + $this->assertEquals(200, $page->code); } } diff --git a/ext/media/events.php b/ext/media/events.php index f94d7a7a..b8cd984a 100644 --- a/ext/media/events.php +++ b/ext/media/events.php @@ -45,20 +45,15 @@ class MediaResizeEvent extends Event class MediaCheckPropertiesEvent extends Event { + public $image; public $file_name; public $ext; - public $lossless = null; - public $audio = null; - public $video = null; - public $image = null; - public $length = null; - public $height = null; - public $width = null; - public function __construct(string $file_name, string $ext) + public function __construct(Image $image) { parent::__construct(); - $this->file_name = $file_name; - $this->ext = $ext; + $this->image = $image; + $this->file_name = warehouse_path(Image::IMAGE_DIR, $image->hash); + $this->ext = strtolower($image->ext); } } diff --git a/ext/media/main.php b/ext/media/main.php index a9c0e5ff..67d1aeee 100644 --- a/ext/media/main.php +++ b/ext/media/main.php @@ -85,7 +85,8 @@ class Media extends Extension if ($event->page_matches("media_rescan/") && $user->can(Permissions::RESCAN_MEDIA) && isset($_POST['image_id'])) { $image = Image::by_id(int_escape($_POST['image_id'])); - $this->update_image_media_properties($image->hash, $image->ext); + send_event(new MediaCheckPropertiesEvent($image)); + $image->save_to_db(); $page->set_mode(PageMode::REDIRECT); $page->set_redirect(make_link("post/view/$image->id")); @@ -163,7 +164,8 @@ class Media extends Extension $failed = 0; foreach ($event->items as $image) { try { - $this->update_image_media_properties($image->hash, $image->ext); + send_event(new MediaCheckPropertiesEvent($image)); + $image->save_media_properties(); $total++; } catch (MediaException $e) { $failed++; @@ -185,7 +187,8 @@ class Media extends Extension $uid = $event->args[0]; $image = Image::by_id_or_hash($uid); if ($image) { - $this->update_image_media_properties($image->hash, $image->ext); + send_event(new MediaCheckPropertiesEvent($image)); + $image->save_to_db(); } else { print("No post with ID '$uid'\n"); } @@ -282,69 +285,13 @@ class Media extends Extension } } - public function onTagTermParse(TagTermParseEvent $event) + public function onTagTermCheck(TagTermCheckEvent $event) { - $matches = []; - if (preg_match(self::CONTENT_SEARCH_TERM_REGEX, strtolower($event->term), $matches) && $event->parse) { + if (preg_match(self::CONTENT_SEARCH_TERM_REGEX, $event->term)) { $event->metatag = true; } } - private function media_rescan(): bool - { - $ext = ""; - if (array_key_exists("media_rescan_type", $_POST)) { - $ext = $_POST["media_rescan_type"]; - } - - $results = $this->get_images($ext); - - foreach ($results as $result) { - $this->update_image_media_properties($result["hash"], $result["ext"]); - } - return true; - } - - public static function update_image_media_properties(string $hash, string $ext) - { - global $database; - - $path = warehouse_path(Image::IMAGE_DIR, $hash); - $mcpe = new MediaCheckPropertiesEvent($path, $ext); - send_event($mcpe); - - - $database->execute( - "UPDATE images SET - lossless = :lossless, video = :video, audio = :audio,image = :image, - height = :height, width = :width, - length = :length WHERE hash = :hash", - [ - "hash" => $hash, - "width" => $mcpe->width ?? 0, - "height" => $mcpe->height ?? 0, - "lossless" => $database->scoresql_value_prepare($mcpe->lossless), - "video" => $database->scoresql_value_prepare($mcpe->video), - "image" => $database->scoresql_value_prepare($mcpe->image), - "audio" => $database->scoresql_value_prepare($mcpe->audio), - "length" => $mcpe->length - ] - ); - } - - public function get_images(String $ext = null) - { - global $database; - - $query = "SELECT id, hash, ext FROM images "; - $args = []; - if (!empty($ext)) { - $query .= " WHERE ext = :ext"; - $args["ext"] = $ext; - } - return $database->get_all($query, $args); - } - /** * Check Memory usage limits * diff --git a/ext/numeric_score/main.php b/ext/numeric_score/main.php index 878e28d1..0f9449c0 100644 --- a/ext/numeric_score/main.php +++ b/ext/numeric_score/main.php @@ -274,21 +274,24 @@ class NumericScore extends Extension } } + public function onTagTermCheck(TagTermCheckEvent $event) + { + if (preg_match("/^vote[=|:](up|down|remove)$/i", $event->term)) { + $event->metatag = true; + } + } + public function onTagTermParse(TagTermParseEvent $event) { $matches = []; - if (preg_match("/^vote[=|:](up|down|remove)$/", $event->term, $matches) && $event->parse) { + if (preg_match("/^vote[=|:](up|down|remove)$/", $event->term, $matches)) { global $user; $score = ($matches[1] == "up" ? 1 : ($matches[1] == "down" ? -1 : 0)); if (!$user->is_anonymous()) { - send_event(new NumericScoreSetEvent($event->id, $user, $score)); + send_event(new NumericScoreSetEvent($event->image_id, $user, $score)); } } - - if (!empty($matches)) { - $event->metatag = true; - } } public function onPageSubNavBuilding(PageSubNavBuildingEvent $event) diff --git a/ext/oekaki/test.php b/ext/oekaki/test.php index c97196e1..270f8797 100644 --- a/ext/oekaki/test.php +++ b/ext/oekaki/test.php @@ -4,6 +4,7 @@ class OekakiTest extends ShimmiePHPUnitTestCase public function testLog() { $this->log_in_as_user(); - $this->get_page("oekaki/create"); + $page = $this->get_page("oekaki/create"); + $this->assertEquals(200, $page->code); } } diff --git a/ext/pm/test.php b/ext/pm/test.php index 95cf6f74..60a66c66 100644 --- a/ext/pm/test.php +++ b/ext/pm/test.php @@ -6,14 +6,14 @@ class PrivMsgTest extends ShimmiePHPUnitTestCase // Send from admin to user $this->log_in_as_admin(); send_event(new SendPMEvent(new PM( - User::by_name($this->admin_name)->id, + User::by_name(self::$admin_name)->id, "0.0.0.0", - User::by_name($this->user_name)->id, + User::by_name(self::$user_name)->id, "message demo to test" ))); // Check that admin can see user's messages - $this->get_page("user/{$this->user_name}"); + $this->get_page("user/" . self::$user_name); $this->assert_text("message demo to test"); // Check that user can see own messages diff --git a/ext/pools/main.php b/ext/pools/main.php index b776310f..4f6d751f 100644 --- a/ext/pools/main.php +++ b/ext/pools/main.php @@ -404,10 +404,16 @@ class Pools extends Extension } } + public function onTagTermCheck(TagTermCheckEvent $event) + { + if (preg_match("/^pool[=|:]([^:]*|lastcreated):?([0-9]*)$/i", $event->term)) { + $event->metatag = true; + } + } + public function onTagTermParse(TagTermParseEvent $event) { $matches = []; - if (preg_match("/^pool[=|:]([^:]*|lastcreated):?([0-9]*)$/i", $event->term, $matches)) { global $user; $poolTag = (string)str_replace("_", " ", $matches[1]); @@ -421,16 +427,11 @@ class Pools extends Extension $pool = $this->get_single_pool_from_title($poolTag); } - if ($pool ? $this->have_permission($user, $pool) : false) { $image_order = ($matches[2] ?: 0); - $this->add_post($pool['id'], $event->id, true, $image_order); + $this->add_post($pool['id'], $event->image_id, true, $image_order); } } - - if (!empty($matches)) { - $event->metatag = true; - } } public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event) diff --git a/ext/rating/main.php b/ext/rating/main.php index 0eb459dc..a03314ab 100644 --- a/ext/rating/main.php +++ b/ext/rating/main.php @@ -253,12 +253,19 @@ class Ratings extends Extension } } + public function onTagTermCheck(TagTermCheckEvent $event) + { + if (preg_match($this->search_regexp, $event->term)) { + $event->metatag = true; + } + } + public function onTagTermParse(TagTermParseEvent $event) { global $user; $matches = []; - if (preg_match($this->search_regexp, strtolower($event->term), $matches) && $event->parse) { + if (preg_match($this->search_regexp, strtolower($event->term), $matches)) { $ratings = $matches[1] ? $matches[1] : $matches[2][0]; if (count($matches)>2&&in_array($matches[2], self::UNRATED_KEYWORDS)) { @@ -267,14 +274,10 @@ class Ratings extends Extension $ratings = array_intersect(str_split($ratings), Ratings::get_user_class_privs($user)); $rating = $ratings[0]; - $image = Image::by_id($event->id); + $image = Image::by_id($event->image_id); $re = new RatingSetEvent($image, $rating); send_event($re); } - - if (!empty($matches)) { - $event->metatag = true; - } } public function onAdminBuilding(AdminBuildingEvent $event) diff --git a/ext/rating/test.php b/ext/rating/test.php index 45d17c6d..e0486fe9 100644 --- a/ext/rating/test.php +++ b/ext/rating/test.php @@ -9,22 +9,15 @@ class RatingsTest extends ShimmiePHPUnitTestCase send_event(new RatingSetEvent($image, "s")); # search for it in various ways - $page = $this->get_page("post/list/rating=Safe/1"); - $this->assertEquals("/post/view/1", $page->redirect); - - $page = $this->get_page("post/list/rating=s/1"); - $this->assertEquals("/post/view/1", $page->redirect); - - $page = $this->get_page("post/list/rating=sqe/1"); - $this->assertEquals("/post/view/1", $page->redirect); + $this->assert_search_results(["rating=Safe"], [$image_id]); + $this->assert_search_results(["rating=s"], [$image_id]); + $this->assert_search_results(["rating=sqe"], [$image_id]); # test that search by tag still works - $page = $this->get_page("post/list/pbx/1"); - $this->assertEquals("/post/view/1", $page->redirect); + $this->assert_search_results(["pbx"], [$image_id]); # searching for a different rating should return nothing - $page = $this->get_page("post/list/rating=q/1"); - $this->assertEquals("No Images Found", $page->heading); + $this->assert_search_results(["rating=q"], []); } public function testRatingExplicit() @@ -38,7 +31,6 @@ class RatingsTest extends ShimmiePHPUnitTestCase # the explicit image shouldn't show up in anon's searches $this->log_out(); - $page = $this->get_page("post/list/pbx/1"); - $this->assertEquals("No Images Found", $page->heading); + $this->assert_search_results(["pbx"], []); } } diff --git a/ext/relationships/info.php b/ext/relationships/info.php index e490178e..d5969ee3 100644 --- a/ext/relationships/info.php +++ b/ext/relationships/info.php @@ -9,5 +9,5 @@ class RelationshipsInfo extends ExtensionInfo public $authors = ["Angus Johnston"=>"admin@codeanimu.net"]; public $license = self::LICENSE_GPLV2; public $description = "Allow posts to have relationships (parent/child)."; - public $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL]; + //public $db_support = [DatabaseDriver::MYSQL, DatabaseDriver::PGSQL]; } diff --git a/ext/relationships/main.php b/ext/relationships/main.php index 1cfe0f9a..2e7b70d4 100644 --- a/ext/relationships/main.php +++ b/ext/relationships/main.php @@ -5,7 +5,6 @@ class ImageRelationshipSetEvent extends Event public $child_id; public $parent_id; - public function __construct(int $child_id, int $parent_id) { parent::__construct(); @@ -19,6 +18,12 @@ class Relationships extends Extension { public const NAME = "Relationships"; + public function onInitExt(InitExtEvent $event) + { + Image::$bool_props[] = "has_children"; + Image::$int_props[] = "parent_id"; + } + public function onDatabaseUpgrade(DatabaseUpgradeEvent $event) { global $database; @@ -86,27 +91,27 @@ class Relationships extends Extension } } + public function onTagTermCheck(TagTermCheckEvent $event) + { + if (preg_match("/^(parent|child)[=|:](.*)$/i", $event->term)) { + $event->metatag = true; + } + } public function onTagTermParse(TagTermParseEvent $event) { $matches = []; - if (preg_match("/^parent[=|:]([0-9]+|none)$/", $event->term, $matches) && $event->parse) { + if (preg_match("/^parent[=|:]([0-9]+|none)$/", $event->term, $matches)) { $parentID = $matches[1]; - if ($parentID == "none" || $parentID == "0") { - $this->remove_parent($event->id); + $this->remove_parent($event->image_id); } else { - send_event(new ImageRelationshipSetEvent($event->id, $parentID)); + send_event(new ImageRelationshipSetEvent($event->image_id, (int)$parentID)); } - } elseif (preg_match("/^child[=|:]([0-9]+)$/", $event->term, $matches) && $event->parse) { + } elseif (preg_match("/^child[=|:]([0-9]+)$/", $event->term, $matches)) { $childID = $matches[1]; - - send_event(new ImageRelationshipSetEvent($childID, $event->id)); - } - - if (!empty($matches)) { - $event->metatag = true; + send_event(new ImageRelationshipSetEvent((int)$childID, $event->image_id)); } } @@ -133,23 +138,25 @@ class Relationships extends Extension global $database; $old_parent = $database->get_one("SELECT parent_id FROM images WHERE id = :cid", ["cid"=>$event->child_id]); + if (!is_null($old_parent)) { + $old_parent = (int)$old_parent; + } - if ($old_parent!=$event->parent_id) { - if ($database->get_row("SELECT 1 FROM images WHERE id = :pid", ["pid" => $event->parent_id])) { - $result = $database->execute("UPDATE images SET parent_id = :pid WHERE id = :cid", ["pid" => $event->parent_id, "cid" => $event->child_id]); + if ($old_parent == $event->parent_id) { + return; // no change + } + if (!Image::by_id($event->parent_id) || !Image::by_id($event->child_id)) { + return; // one of the images doesn't exist + } - if ($result->rowCount() > 0) { - $database->execute("UPDATE images SET has_children = TRUE WHERE id = :pid", ["pid" => $event->parent_id]); + $database->execute("UPDATE images SET parent_id = :pid WHERE id = :cid", ["pid" => $event->parent_id, "cid" => $event->child_id]); + $database->execute("UPDATE images SET has_children = TRUE WHERE id = :pid", ["pid" => $event->parent_id]); - if ($old_parent!=null) { - $this->set_has_children($old_parent); - } - } - } + if ($old_parent!=null) { + $this->set_has_children($old_parent); } } - public static function get_children(Image $image, int $omit = null): array { global $database; @@ -171,7 +178,7 @@ class Relationships extends Extension if ($parentID) { $database->execute("UPDATE images SET parent_id = NULL WHERE id = :iid", ["iid"=>$imageID]); - $this->set_has_children($parentID); + $this->set_has_children((int)$parentID); } } @@ -180,11 +187,17 @@ class Relationships extends Extension global $database; // Doesn't work on pgsql -// $database->execute("UPDATE images SET has_children = (SELECT * FROM (SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM images WHERE parent_id = :pid) AS sub) - // WHERE id = :pid", ["pid"=>$parentID]); + // $database->execute(" + // UPDATE images + // SET has_children = (SELECT * FROM (SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END FROM images WHERE parent_id = :pid) AS sub) + // WHERE id = :pid + // ", ["pid"=>$parentID]); $database->execute( - "UPDATE images SET has_children = EXISTS (SELECT 1 FROM images WHERE parent_id = :pid) WHERE id = :pid", + "UPDATE images + SET has_children = EXISTS ( + SELECT 1 FROM images WHERE parent_id = :pid + ) WHERE id = :pid", ["pid"=>$parent_id] ); } diff --git a/ext/relationships/test.php b/ext/relationships/test.php index 70f95206..3bc5edea 100644 --- a/ext/relationships/test.php +++ b/ext/relationships/test.php @@ -1,7 +1,11 @@ log_in_as_user(); @@ -20,81 +24,85 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase $this->assertFalse($image_2->has_children); $this->assertFalse($image_3->has_children); - $this->get_page("post/view/$image_id_2"); - $this->assert_title("Image $image_id_2: pbx"); - - $this->markTestIncomplete(); - - $this->set_field("tag_edit__parent", $image_id_1); - $this->click("Set"); - - - $image_1 = Image::by_id($image_id_1); - $image_2 = Image::by_id($image_id_2); - $image_3 = Image::by_id($image_id_3); - - $this->assertNull($image_1->parent_id); - $this->assertEquals($image_id_1, $image_2->parent_id); - $this->assertNull($image_3->parent_id); - $this->assertTrue($image_1->has_children); - $this->assertFalse($image_2->has_children); - $this->assertFalse($image_3->has_children); - - - // Test changing to a different parent - - $this->get_page("post/view/$image_id_2"); - $this->assert_title("Image $image_id_2: pbx"); - - $this->markTestIncomplete(); - - $this->set_field("tag_edit__parent", $image_id_3); - $this->click("Set"); - - $image_1 = Image::by_id($image_id_1); - $image_2 = Image::by_id($image_id_2); - $image_3 = Image::by_id($image_id_3); - - $this->assertNull($image_1->parent_id); - $this->assertEquals($image_id_3, $image_2->parent_id); - $this->assertNull($image_3->parent_id); - $this->assertFalse($image_2->has_children); - $this->assertFalse($image_2->has_children); - $this->assertTrue($image_3->has_children); - - - // Test setting parent to none - - $this->get_page("post/view/$image_id_2"); - $this->assert_title("Image $image_id_2: pbx"); - - $this->markTestIncomplete(); - - $this->set_field("tag_edit__parent", ""); - $this->click("Set"); - - $image_1 = Image::by_id($image_id_1); - $image_2 = Image::by_id($image_id_2); - $image_3 = Image::by_id($image_id_3); - - $this->assertNull($image_1->parent_id); - $this->assertNull($image_2->parent_id); - $this->assertNull($image_3->parent_id); - $this->assertFalse($image_2->has_children); - $this->assertFalse($image_2->has_children); - $this->assertFalse($image_3->has_children); - - - $this->log_out(); - - $this->log_in_as_admin(); - $this->delete_image($image_id_1); - $this->delete_image($image_id_2); - $this->delete_image($image_id_3); - $this->log_out(); + return [$image_1, $image_2, $image_3]; } - public function testSetParentByTag() + /** + * @depends testNoParent + */ + public function testSetParent($imgs) + { + [$image_1, $image_2, $image_3] = $imgs; + + send_event(new ImageRelationshipSetEvent($image_2->id, $image_1->id)); + + // refresh data from database + $image_1 = Image::by_id($image_1->id); + $image_2 = Image::by_id($image_2->id); + $image_3 = Image::by_id($image_3->id); + + $this->assertNull($image_1->parent_id); + $this->assertEquals($image_1->id, $image_2->parent_id); + $this->assertNull($image_3->parent_id); + $this->assertTrue($image_1->has_children); + $this->assertFalse($image_2->has_children); + $this->assertFalse($image_3->has_children); + + return [$image_1, $image_2, $image_3]; + } + + /** + * @depends testSetParent + */ + public function testChangeParent($imgs) + { + [$image_1, $image_2, $image_3] = $imgs; + send_event(new ImageRelationshipSetEvent($image_2->id, $image_3->id)); + + // refresh data from database + $image_1 = Image::by_id($image_1->id); + $image_2 = Image::by_id($image_2->id); + $image_3 = Image::by_id($image_3->id); + + $this->assertNull($image_1->parent_id); + $this->assertEquals($image_3->id, $image_2->parent_id); + $this->assertNull($image_3->parent_id); + $this->assertFalse($image_2->has_children); + $this->assertFalse($image_2->has_children); + $this->assertTrue($image_3->has_children); + + return [$image_1, $image_2, $image_3]; + } + + /** + * @depends testChangeParent + */ + public function testRemoveParent($imgs) + { + [$image_1, $image_2, $image_3] = $imgs; + + global $database; + $database->execute("UPDATE images SET parent_id=NULL, has_children=FALSE"); + // FIXME: send_event(new ImageRelationshipSetEvent($image_2->id, null)); + + // refresh data from database + $image_1 = Image::by_id($image_1->id); + $image_2 = Image::by_id($image_2->id); + $image_3 = Image::by_id($image_3->id); + + $this->assertNull($image_1->parent_id); + $this->assertNull($image_2->parent_id); + $this->assertNull($image_3->parent_id); + $this->assertFalse($image_2->has_children); + $this->assertFalse($image_2->has_children); + $this->assertFalse($image_3->has_children); + } + + //================================================================= + // Set by tag + //================================================================= + + public function testSetParentByTagBase() { $this->log_in_as_user(); $image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "pbx"); @@ -112,81 +120,77 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase $this->assertFalse($image_2->has_children); $this->assertFalse($image_3->has_children); - // Test settings parent:# + return [$image_1, $image_2, $image_3]; + } - $this->get_page("post/view/$image_id_2"); - $this->assert_title("Image $image_id_2: pbx"); + /** + * @depends testSetParentByTagBase + */ + public function testSetParentByTag($imgs) + { + [$image_1, $image_2, $image_3] = $imgs; - $this->markTestIncomplete(); + send_event(new TagSetEvent($image_2, ["pbx", "parent:{$image_1->id}"])); - $this->set_field("tag_edit__tags", "pbx parent:$image_id_1"); - $this->click("Set"); - - $this->assert_title("Image $image_id_2: pbx"); - - $image_1 = Image::by_id($image_id_1); - $image_2 = Image::by_id($image_id_2); - $image_3 = Image::by_id($image_id_3); + // refresh data from database + $image_1 = Image::by_id($image_1->id); + $image_2 = Image::by_id($image_2->id); + $image_3 = Image::by_id($image_3->id); + $this->assertEquals(["pbx"], $image_2->get_tag_array()); $this->assertNull($image_1->parent_id); - $this->assertEquals($image_id_1, $image_2->parent_id); + $this->assertEquals($image_1->id, $image_2->parent_id); $this->assertNull($image_3->parent_id); $this->assertTrue($image_1->has_children); $this->assertFalse($image_2->has_children); $this->assertFalse($image_3->has_children); - // Test settings child:# + return [$image_1, $image_2, $image_3]; + } - $this->get_page("post/view/$image_id_3"); - $this->assert_title("Image $image_id_3: pbx"); + /** + * @depends testSetParentByTag + */ + public function testSetChildByTag($imgs) + { + [$image_1, $image_2, $image_3] = $imgs; - $this->markTestIncomplete(); + send_event(new TagSetEvent($image_3, ["pbx", "child:{$image_1->id}"])); - $this->set_field("tag_edit__tags", "pbx child:$image_id_1"); - $this->click("Set"); + // refresh data from database + $image_1 = Image::by_id($image_1->id); + $image_2 = Image::by_id($image_2->id); + $image_3 = Image::by_id($image_3->id); - $this->assert_title("Image $image_id_3: pbx"); - - $image_1 = Image::by_id($image_id_1); - $image_2 = Image::by_id($image_id_2); - $image_3 = Image::by_id($image_id_3); - - $this->assertEquals($image_id_3, $image_1->parent_id); - $this->assertEquals($image_id_1, $image_2->parent_id); + $this->assertEquals(["pbx"], $image_3->get_tag_array()); + $this->assertEquals($image_3->id, $image_1->parent_id); + $this->assertEquals($image_1->id, $image_2->parent_id); $this->assertNull($image_3->parent_id); $this->assertTrue($image_1->has_children); $this->assertFalse($image_2->has_children); $this->assertTrue($image_3->has_children); - // Test settings parent:none + return [$image_1, $image_2, $image_3]; + } - $this->get_page("post/view/$image_id_1"); - $this->assert_title("Image $image_id_1: pbx"); + /** + * @depends testSetChildByTag + */ + public function testRemoveParentByTag($imgs) + { + [$image_1, $image_2, $image_3] = $imgs; - $this->markTestIncomplete(); + // check parent is set + $this->assertEquals($image_2->parent_id, $image_1->id); - $this->set_field("tag_edit__tags", "pbx parent:none"); - $this->click("Set"); + // un-set it + send_event(new TagSetEvent($image_2, ["pbx", "parent:none"])); - $this->assert_title("Image $image_id_1: pbx"); + // refresh data from database + $image_2 = Image::by_id($image_2->id); - $image_1 = Image::by_id($image_id_1); - $image_2 = Image::by_id($image_id_2); - $image_3 = Image::by_id($image_id_3); - - $this->assertNull($image_1->parent_id); - $this->assertEquals($image_id_1, $image_2->parent_id); - $this->assertNull($image_3->parent_id); - $this->assertTrue($image_1->has_children); - $this->assertFalse($image_2->has_children); - $this->assertFalse($image_3->has_children); - - $this->log_out(); - - $this->log_in_as_admin(); - $this->delete_image($image_id_1); - $this->delete_image($image_id_2); - $this->delete_image($image_id_3); - $this->log_out(); + // check it was unset + $this->assertEquals(["pbx"], $image_2->get_tag_array()); + $this->assertNull($image_2->parent_id); } } diff --git a/ext/res_limit/test.php b/ext/res_limit/test.php index d49cac4c..ecf25159 100644 --- a/ext/res_limit/test.php +++ b/ext/res_limit/test.php @@ -30,6 +30,7 @@ class ResolutionLimitTest extends ShimmiePHPUnitTestCase $this->log_in_as_user(); try { $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + $this->assertTrue(false, "Invalid-size image was allowed"); } catch (UploadException $e) { $this->assertEquals("Image too small", $e->getMessage()); } @@ -46,6 +47,7 @@ class ResolutionLimitTest extends ShimmiePHPUnitTestCase try { $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + $this->assertTrue(false, "Invalid-size image was allowed"); } catch (UploadException $e) { $this->assertEquals("Image too large", $e->getMessage()); } @@ -62,6 +64,7 @@ class ResolutionLimitTest extends ShimmiePHPUnitTestCase try { $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + $this->assertTrue(false, "Invalid-size image was allowed"); } catch (UploadException $e) { $this->assertEquals("Image needs to be in one of these ratios: 16:9", $e->getMessage()); } @@ -71,13 +74,13 @@ class ResolutionLimitTest extends ShimmiePHPUnitTestCase # other extensions' test suites public function tearDown(): void { - parent::tearDown(); - global $config; $config->set_int("upload_min_height", -1); $config->set_int("upload_min_width", -1); $config->set_int("upload_max_height", -1); $config->set_int("upload_max_width", -1); $config->set_string("upload_ratios", ""); + + parent::tearDown(); } } diff --git a/ext/shimmie_api/test.php b/ext/shimmie_api/test.php index 805968ae..d6339b2f 100644 --- a/ext/shimmie_api/test.php +++ b/ext/shimmie_api/test.php @@ -15,7 +15,10 @@ class ShimmieApiTest extends ShimmiePHPUnitTestCase $this->get_page("api/shimmie/find_images"); $this->get_page("api/shimmie/find_images/pbx"); $this->get_page("api/shimmie/find_images/pbx/1"); - $this->get_page("api/shimmie/get_user/demo"); + + $page = $this->get_page("api/shimmie/get_user/demo"); + $this->assertEquals(200, $page->code); + //$this->get_page("api/shimmie/get_user?name=demo"); //$this->get_page("api/shimmie/get_user?id=2"); diff --git a/ext/sitemap/test.php b/ext/sitemap/test.php index bf337056..a63c58ad 100644 --- a/ext/sitemap/test.php +++ b/ext/sitemap/test.php @@ -3,8 +3,7 @@ class XMLSitemapTest extends ShimmiePHPUnitTestCase { public function testBasic() { - # this will implicitly check that there are no - # PHP-level error messages - $this->get_page('sitemap.xml'); + $page = $this->get_page('sitemap.xml'); + $this->assertEquals(200, $page->code); } } diff --git a/ext/tag_edit/main.php b/ext/tag_edit/main.php index 45946218..07caf98d 100644 --- a/ext/tag_edit/main.php +++ b/ext/tag_edit/main.php @@ -64,11 +64,11 @@ class TagSetEvent extends Event continue; } - $ttpe = new TagTermParseEvent($tag, $this->image->id, false); //Only check for metatags, don't parse. Parsing is done after set_tags. + $ttpe = new TagTermCheckEvent($tag); send_event($ttpe); //seperate tags from metatags - if (!$ttpe->is_metatag()) { + if (!$ttpe->metatag) { array_push($this->tags, $tag); } else { array_push($this->metatags, $tag); @@ -92,30 +92,35 @@ class LockSetEvent extends Event } } -/* - * TagTermParseEvent: - * Signal that a tag term needs parsing +/** + * Check whether or not a tag is a meta-tag */ -class TagTermParseEvent extends Event +class TagTermCheckEvent extends Event { public $term = null; //tag - public $id = null; //image_id /** @var bool */ public $metatag = false; - /** @var bool */ - public $parse = true; //marks the tag to be parsed, and not just checked if valid metatag - public function __construct(string $term, int $id, bool $parse) + public function __construct(string $term) { parent::__construct(); $this->term = $term; - $this->id = $id; - $this->parse = $parse; } +} - public function is_metatag(): bool +/** + * If a tag is a meta-tag, parse it + */ +class TagTermParseEvent extends Event +{ + public $term = null; + public $image_id = null; + + public function __construct(string $term, int $image_id) { - return $this->metatag; + parent::__construct(); + $this->term = $term; + $this->image_id = $image_id; } } @@ -245,17 +250,18 @@ class TagEdit extends Extension $event->add_part($this->theme->get_lock_editor_html($event->image), 42); } + public function onTagTermCheck(TagTermCheckEvent $event) + { + if (preg_match("/^source[=|:](.*)$/i", $event->term)) { + $event->metatag = true; + } + } + public function onTagTermParse(TagTermParseEvent $event) { - $matches = []; - - if (preg_match("/^source[=|:](.*)$/i", $event->term, $matches) && $event->parse) { + if (preg_match("/^source[=|:](.*)$/i", $event->term, $matches)) { $source = ($matches[1] !== "none" ? $matches[1] : null); - send_event(new SourceSetEvent(Image::by_id($event->id), $source)); - } - - if (!empty($matches)) { - $event->metatag = true; + send_event(new SourceSetEvent(Image::by_id($event->image_id), $source)); } } diff --git a/ext/upload/main.php b/ext/upload/main.php index 7194a77c..0113d807 100644 --- a/ext/upload/main.php +++ b/ext/upload/main.php @@ -20,7 +20,6 @@ class DataUploadEvent extends Event /** @var bool */ public $merged = false; - /** * Some data is being uploaded. * This should be caught by a file handler. diff --git a/ext/upload/test.php b/ext/upload/test.php index 5cda4eca..af57c960 100644 --- a/ext/upload/test.php +++ b/ext/upload/test.php @@ -12,7 +12,8 @@ class UploadTest extends ShimmiePHPUnitTestCase public function testUpload() { $this->log_in_as_user(); - $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + $image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot"); + $this->assertGreaterThan(0, $image_id); } public function testRejectDupe() @@ -28,11 +29,8 @@ class UploadTest extends ShimmiePHPUnitTestCase public function testRejectUnknownFiletype() { - try { - $this->post_image("index.php", "test"); - } catch (UploadException $e) { - $this->assertStringContainsString("Invalid or corrupted file", $e->getMessage()); - } + $image_id = $this->post_image("index.php", "test"); + $this->assertEquals(-1, $image_id); // no file handler claimed this } public function testRejectHuge() diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 46c7992e..8a6dc3e3 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -35,9 +35,20 @@ $_tracer->end(); abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase { - protected $anon_name = "anonymous"; - protected $admin_name = "demo"; - protected $user_name = "test"; + protected static $anon_name = "anonymous"; + protected static $admin_name = "demo"; + protected static $user_name = "test"; + protected $wipe_time = "test"; + + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + global $_tracer; + $_tracer->begin("Test Class"); + + self::create_user(self::$admin_name); + self::create_user(self::$user_name); + } public function setUp(): void { @@ -49,18 +60,16 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase $this->markTestSkipped("$class not supported with this database"); } - $this->create_user($this->admin_name); - $this->create_user($this->user_name); + // If we have a parent test, don't wipe out the state they gave us + if (!$this->getDependencyInput()) { + // things to do after bootstrap and before request + // log in as anon + self::log_out(); - // things to do after bootstrap and before request - // log in as anon - $this->log_out(); - - $_tracer->begin("tearDown"); - foreach ($database->get_col("SELECT id FROM images") as $image_id) { - send_event(new ImageDeletionEvent(Image::by_id($image_id))); + foreach ($database->get_col("SELECT id FROM images") as $image_id) { + send_event(new ImageDeletionEvent(Image::by_id($image_id))); + } } - $_tracer->end(); $_tracer->end(); $_tracer->begin("test"); @@ -75,7 +84,14 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase $_tracer->flush("tests/trace.json"); } - protected function create_user(string $name) + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + global $_tracer; + $_tracer->end(); + } + + protected static function create_user(string $name) { if (is_null(User::by_name($name))) { $userPage = new UserPage(); @@ -84,7 +100,7 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase } } - protected function get_page($page_name, $args=null) + protected static function get_page($page_name, $args=null) { // use a fresh page global $page; @@ -101,7 +117,7 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase return $page; } - protected function post_page($page_name, $args=null) + protected static function post_page($page_name, $args=null) { // use a fresh page global $page; @@ -186,23 +202,31 @@ abstract class ShimmiePHPUnitTestCase extends \PHPUnit\Framework\TestCase $this->assertStringNotContainsString($content, $page->data); } + protected function assert_search_results($tags, $results) + { + $images = Image::find_images(0, null, $tags); + $ids = []; + foreach ($images as $image) { + $ids[] = $image->id; + } + $this->assertEquals($results, $ids); + } + // user things - protected function log_in_as_admin() + protected static function log_in_as_admin() { - send_event(new UserLoginEvent(User::by_name($this->admin_name))); + send_event(new UserLoginEvent(User::by_name(self::$admin_name))); } - protected function log_in_as_user() + protected static function log_in_as_user() { - send_event(new UserLoginEvent(User::by_name($this->user_name))); + send_event(new UserLoginEvent(User::by_name(self::$user_name))); } - protected function log_out() + protected static function log_out() { global $config; - $user = User::by_id($config->get_int("anon_id", 0)); - $this->assertNotNull($user); - send_event(new UserLoginEvent($user)); + send_event(new UserLoginEvent(User::by_id($config->get_int("anon_id", 0)))); } // post things