[core] organise exceptions a bit

This commit is contained in:
Shish 2024-02-11 15:47:40 +00:00
parent 278286da9f
commit 7ee4152942
59 changed files with 208 additions and 371 deletions

View file

@ -64,7 +64,7 @@ class CommandBuilder
log_debug('command_builder', "Command `$cmd` returned $ret and outputted $output");
if ($fail_on_non_zero_return && (int)$ret !== (int)0) {
throw new SCoreException("Command `$cmd` failed, returning $ret and outputting $output");
throw new ServerError("Command `$cmd` failed, returning $ret and outputting $output");
}
return $ret;
}

View file

@ -242,7 +242,7 @@ abstract class BaseConfig implements Config
{
$val = $this->get($name, $default);
if (!is_string($val) && !is_null($val)) {
throw new SCoreException("$name is not a string: $val");
throw new ServerError("$name is not a string: $val");
}
return $val;
}

View file

@ -82,7 +82,7 @@ class Database
if (preg_match("/^([^:]*)/", $this->dsn, $matches)) {
$db_proto = $matches[1];
} else {
throw new SCoreException("Can't figure out database engine");
throw new ServerError("Can't figure out database engine");
}
if ($db_proto === DatabaseDriverID::MYSQL->value) {
@ -116,7 +116,7 @@ class Database
if ($this->is_transaction_open()) {
return $this->get_db()->commit();
} else {
throw new SCoreException("Unable to call commit() as there is no transaction currently open.");
throw new ServerError("Unable to call commit() as there is no transaction currently open.");
}
}
@ -125,7 +125,7 @@ class Database
if ($this->is_transaction_open()) {
return $this->get_db()->rollback();
} else {
throw new SCoreException("Unable to call rollback() as there is no transaction currently open.");
throw new ServerError("Unable to call rollback() as there is no transaction currently open.");
}
}
@ -389,8 +389,6 @@ class Database
/**
* Returns the number of tables present in the current database.
*
* @throws SCoreException
*/
public function count_tables(): int
{
@ -408,7 +406,7 @@ class Database
);
} else {
$did = (string)$this->get_engine()->id;
throw new SCoreException("Can't count tables for database type {$did}");
throw new ServerError("Can't count tables for database type {$did}");
}
}

View file

@ -100,7 +100,7 @@ class PageRequestEvent extends Event
{
if(array_key_exists($key, $this->GET)) {
if(is_array($this->GET[$key])) {
throw new SCoreException("GET parameter {$key} is an array, expected single value");
throw new UserError("GET parameter {$key} is an array, expected single value");
}
return $this->GET[$key];
} else {
@ -112,7 +112,7 @@ class PageRequestEvent extends Event
{
$value = $this->get_GET($key);
if($value === null) {
throw new UserErrorException("Missing GET parameter {$key}");
throw new UserError("Missing GET parameter {$key}");
}
return $value;
}
@ -121,7 +121,7 @@ class PageRequestEvent extends Event
{
if(array_key_exists($key, $this->POST)) {
if(is_array($this->POST[$key])) {
throw new SCoreException("POST parameter {$key} is an array, expected single value");
throw new UserError("POST parameter {$key} is an array, expected single value");
}
return $this->POST[$key];
} else {
@ -133,7 +133,7 @@ class PageRequestEvent extends Event
{
$value = $this->get_POST($key);
if($value === null) {
throw new UserErrorException("Missing POST parameter {$key}");
throw new UserError("Missing POST parameter {$key}");
}
return $value;
}
@ -145,7 +145,7 @@ class PageRequestEvent extends Event
{
if(array_key_exists($key, $this->POST)) {
if(!is_array($this->POST[$key])) {
throw new SCoreException("POST parameter {$key} is a single value, expected array");
throw new UserError("POST parameter {$key} is a single value, expected array");
}
return $this->POST[$key];
} else {
@ -160,7 +160,7 @@ class PageRequestEvent extends Event
{
$value = $this->get_POST_array($key);
if($value === null) {
throw new UserErrorException("Missing POST parameter {$key}");
throw new UserError("Missing POST parameter {$key}");
}
return $value;
}
@ -214,10 +214,10 @@ class PageRequestEvent extends Event
// if we matched the method and the path, but the page requires
// authentication and the user is not authenticated, then complain
if($authed && $this->is_authed === false) {
throw new PermissionDeniedException("Permission Denied");
throw new PermissionDenied("Permission Denied");
}
if($permission !== null && !$user->can($permission)) {
throw new PermissionDeniedException("Permission Denied");
throw new PermissionDenied("Permission Denied");
}
return true;
@ -233,7 +233,7 @@ class PageRequestEvent extends Event
} elseif($default !== null) {
return $default;
} else {
throw new UserErrorException("Page argument {$n} is missing");
throw new UserError("Page argument {$n} is missing");
}
}
@ -241,13 +241,13 @@ class PageRequestEvent extends Event
{
if(array_key_exists($n, $this->named_args)) {
if(is_numberish($this->named_args[$n]) === false) {
throw new UserErrorException("Page argument {$n} exists but is not numeric");
throw new UserError("Page argument {$n} exists but is not numeric");
}
return int_escape($this->named_args[$n]);
} elseif($default !== null) {
return $default;
} else {
throw new UserErrorException("Page argument {$n} is missing");
throw new UserError("Page argument {$n} is missing");
}
}
}

View file

@ -34,12 +34,12 @@ class InstallerException extends \RuntimeException
}
}
class UserErrorException extends SCoreException
class UserError extends SCoreException
{
public int $http_code = 400;
}
class ServerErrorException extends SCoreException
class ServerError extends SCoreException
{
public int $http_code = 500;
}
@ -47,45 +47,28 @@ class ServerErrorException extends SCoreException
/**
* A fairly common, generic exception.
*/
class PermissionDeniedException extends UserErrorException
class PermissionDenied extends UserError
{
public int $http_code = 403;
}
/**
* This exception is used when an Image cannot be found by ID.
*/
class ImageDoesNotExist extends UserErrorException
class ObjectNotFound extends UserError
{
public int $http_code = 404;
}
/**
* This exception is used when a User cannot be found by some criteria.
*/
class UserDoesNotExist extends UserErrorException
class ImageNotFound extends ObjectNotFound
{
}
class UserNotFound extends ObjectNotFound
{
public int $http_code = 404;
}
/*
* For validate_input()
*/
class InvalidInput extends UserErrorException
class InvalidInput extends UserError
{
public int $http_code = 402;
}
/*
* This is used by the image resizing code when there is not enough memory to perform a resize.
*/
class InsufficientMemoryException extends ServerErrorException
{
}
/*
* This is used by the image resizing code when there is an error while resizing
*/
class ImageResizeException extends ServerErrorException
{
}

View file

@ -284,7 +284,7 @@ abstract class ExtensionInfo
$extension_info = new $class();
assert(is_a($extension_info, ExtensionInfo::class));
if (array_key_exists($extension_info->key, self::$all_info_by_key)) {
throw new SCoreException("Extension Info $class with key $extension_info->key has already been loaded");
throw new ServerError("Extension Info $class with key $extension_info->key has already been loaded");
}
self::$all_info_by_key[$extension_info->key] = $extension_info;

View file

@ -64,7 +64,7 @@ class Search
if (SPEED_HAX) {
if (!$user->can(Permissions::BIG_SEARCH) and count($tags) > 3) {
throw new PermissionDeniedException("Anonymous users may only search for up to 3 tags at a time");
throw new PermissionDenied("Anonymous users may only search for up to 3 tags at a time");
}
}
@ -388,7 +388,7 @@ class Search
WHERE negative.image_id IS NULL
");
} else {
throw new SCoreException("No criteria specified");
throw new InvalidInput("No criteria specified");
}
}

View file

@ -211,7 +211,7 @@ class Tag
} // hard-code one bad case...
if (mb_strlen($tag, 'UTF-8') > 255) {
throw new SCoreException("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n");
throw new InvalidInput("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n");
}
return $tag;
}
@ -263,7 +263,7 @@ class Tag
foreach ($tags as $tag) {
try {
$tag = Tag::sanitize($tag);
} catch (\Exception $e) {
} catch (UserError $e) {
$page->flash($e->getMessage());
continue;
}

View file

@ -117,7 +117,7 @@ function list_files(string $base, string $_sub_dir = ""): array
$files = [];
$dir = opendir("$base/$_sub_dir");
if ($dir === false) {
throw new SCoreException("Unable to open directory $base/$_sub_dir");
throw new UserError("Unable to open directory $base/$_sub_dir");
}
try {
while ($f = readdir($dir)) {

View file

@ -45,7 +45,6 @@ class User
* would be to use User::by_id, User::by_session, etc.
*
* @param array<string|int, mixed> $row
* @throws SCoreException
*/
public function __construct(array $row)
{
@ -58,7 +57,7 @@ class User
if (array_key_exists($row["class"], UserClass::$known_classes)) {
$this->class = UserClass::$known_classes[$row["class"]];
} else {
throw new SCoreException("User '{$this->name}' has invalid class '{$row["class"]}'");
throw new ServerError("User '{$this->name}' has invalid class '{$row["class"]}'");
}
}
@ -125,7 +124,7 @@ class User
{
$u = User::by_name($name);
if (is_null($u)) {
throw new UserDoesNotExist("Can't find any user named $name");
throw new UserNotFound("Can't find any user named $name");
} else {
return $u->id;
}
@ -189,7 +188,7 @@ class User
{
global $database;
if (User::by_name($name)) {
throw new SCoreException("Desired username is already in use");
throw new InvalidInput("Desired username is already in use");
}
$old_name = $this->name;
$this->name = $name;

View file

@ -56,8 +56,6 @@ class UserClass
/**
* Determine if this class of user can perform an action or has ability.
*
* @throws SCoreException
*/
public function can(string $ability): bool
{
@ -75,7 +73,7 @@ class UserClass
$min_ability = $a;
}
}
throw new SCoreException("Unknown ability '$ability'. Did the developer mean '$min_ability'?");
throw new ServerError("Unknown ability '$ability'. Did the developer mean '$min_ability'?");
}
}
}

View file

@ -9,12 +9,12 @@ class AdminPageTest extends ShimmiePHPUnitTestCase
public function testAuth(): void
{
$this->log_out();
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page('admin');
});
$this->log_in_as_user();
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page('admin');
});

View file

@ -52,7 +52,7 @@ class DeleteAliasEvent extends Event
}
}
class AddAliasException extends UserErrorException
class AddAliasException extends UserError
{
}
@ -175,12 +175,8 @@ class AliasEditor extends Extension
foreach (explode("\n", $csv) as $line) {
$parts = str_getcsv($line);
if (count($parts) == 2) {
try {
send_event(new AddAliasEvent($parts[0], $parts[1]));
$i++;
} catch (AddAliasException $ex) {
$this->theme->display_error(500, "Error adding alias", $ex->getMessage());
}
send_event(new AddAliasEvent($parts[0], $parts[1]));
$i++;
}
}
return $i;

View file

@ -207,7 +207,7 @@ class Approval extends Extension
* Deny images upon insufficient permissions.
**/
if (!$this->check_permissions($event->image)) {
throw new PermissionDeniedException("Access denied");
throw new PermissionDenied("Access denied");
}
}

View file

@ -73,13 +73,9 @@ class AutoTagger extends Extension
if ($event->page_matches("auto_tag/add", method: "POST", permission: Permissions::MANAGE_AUTO_TAG)) {
$input = validate_input(["c_tag" => "string", "c_additional_tags" => "string"]);
try {
send_event(new AddAutoTagEvent($input['c_tag'], $input['c_additional_tags']));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("auto_tag/list"));
} catch (AddAutoTagException $ex) {
$this->theme->display_error(500, "Error adding auto-tag", $ex->getMessage());
}
send_event(new AddAutoTagEvent($input['c_tag'], $input['c_additional_tags']));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("auto_tag/list"));
}
if ($event->page_matches("auto_tag/remove", method: "POST", permission: Permissions::MANAGE_AUTO_TAG)) {
$input = validate_input(["d_tag" => "string"]);
@ -191,12 +187,8 @@ class AutoTagger extends Extension
foreach (explode("\n", $csv) as $line) {
$parts = str_getcsv($line);
if (count($parts) == 2) {
try {
send_event(new AddAutoTagEvent($parts[0], $parts[1]));
$i++;
} catch (AddAutoTagException $ex) {
$this->theme->display_error(500, "Error adding auto-tags", $ex->getMessage());
}
send_event(new AddAutoTagEvent($parts[0], $parts[1]));
$i++;
}
}
return $i;

View file

@ -49,12 +49,12 @@ xanax
public function onSourceSet(SourceSetEvent $event): void
{
$this->test_text($event->source, new SCoreException("Source contains banned terms"));
$this->test_text($event->source, new UserError("Source contains banned terms"));
}
public function onTagSet(TagSetEvent $event): void
{
$this->test_text(Tag::implode($event->new_tags), new SCoreException("Tags contain banned terms"));
$this->test_text(Tag::implode($event->new_tags), new UserError("Tags contain banned terms"));
}
public function onSetupBuilding(SetupBuildingEvent $event): void

View file

@ -8,13 +8,13 @@ class BlotterTest extends ShimmiePHPUnitTestCase
{
public function testDenial(): void
{
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page("blotter/editor");
});
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->post_page("blotter/add");
});
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->post_page("blotter/remove");
});
}

View file

@ -8,9 +8,6 @@ use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\{InputInterface,InputArgument};
use Symfony\Component\Console\Output\OutputInterface;
class BulkActionException extends SCoreException
{
}
class BulkActionBlockBuildingEvent extends Event
{
/**
@ -26,7 +23,7 @@ class BulkActionBlockBuildingEvent extends Event
assert(strlen($access_key) == 1);
foreach ($this->actions as $existing) {
if ($existing["access_key"] == $access_key) {
throw new SCoreException("Access key $access_key is already in use");
throw new UserError("Access key $access_key is already in use");
}
}
}
@ -171,31 +168,26 @@ class BulkActions extends Extension
global $page, $user;
if ($event->page_matches("bulk_action", method: "POST", permission: Permissions::PERFORM_BULK_ACTIONS)) {
$action = $event->req_POST('bulk_action');
try {
$items = null;
if ($event->get_POST('bulk_selected_ids')) {
$data = json_decode($event->req_POST('bulk_selected_ids'));
if (!is_array($data) || empty($data)) {
throw new BulkActionException("No ids specified in bulk_selected_ids");
}
$items = $this->yield_items($data);
} elseif ($event->get_POST('bulk_query')) {
$query = $event->req_POST('bulk_query');
$items = $this->yield_search_results($query);
} else {
throw new BulkActionException("No ids selected and no query present, cannot perform bulk operation on entire collection");
$items = null;
if ($event->get_POST('bulk_selected_ids')) {
$data = json_decode($event->req_POST('bulk_selected_ids'));
if (!is_array($data) || empty($data)) {
throw new InvalidInput("No ids specified in bulk_selected_ids");
}
$items = $this->yield_items($data);
} elseif ($event->get_POST('bulk_query')) {
$query = $event->req_POST('bulk_query');
$items = $this->yield_search_results($query);
} else {
throw new InvalidInput("No ids selected and no query present, cannot perform bulk operation on entire collection");
}
shm_set_timeout(null);
$bae = send_event(new BulkActionEvent($action, $items, $event->POST));
shm_set_timeout(null);
$bae = send_event(new BulkActionEvent($action, $items, $event->POST));
if ($bae->redirect) {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
} catch (BulkActionException $e) {
log_error(BulkActionsInfo::KEY, $e->getMessage(), $e->getMessage());
if ($bae->redirect) {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(referer_or(make_link()));
}
}
}

View file

@ -8,10 +8,6 @@ class BulkDownloadConfig
{
public const SIZE_LIMIT = "bulk_download_size_limit";
}
class BulkDownloadException extends BulkActionException
{
}
class BulkDownload extends Extension
{
@ -58,7 +54,7 @@ class BulkDownload extends Extension
$img_loc = warehouse_path(Image::IMAGE_DIR, $image->hash, false);
$size_total += filesize($img_loc);
if ($size_total > $max_size) {
throw new BulkDownloadException("Bulk download limited to ".human_filesize($max_size));
throw new UserError("Bulk download limited to ".human_filesize($max_size));
}
$filename = urldecode($image->get_nice_image_name());

View file

@ -43,7 +43,7 @@ class BulkImportExport extends DataHandlerExtension
$tmpfile = shm_tempnam("bulk_import");
$stream = $zip->getStream($item->hash);
if ($stream === false) {
throw new SCoreException("Could not import " . $item->hash . ": File not in zip");
throw new UserError("Could not import " . $item->hash . ": File not in zip");
}
file_put_contents($tmpfile, $stream);
@ -56,7 +56,7 @@ class BulkImportExport extends DataHandlerExtension
]))->images;
if (count($images) == 0) {
throw new SCoreException("Unable to import file $item->hash");
throw new UserError("Unable to import file $item->hash");
}
foreach ($images as $image) {
$event->images[] = $image;
@ -84,7 +84,7 @@ class BulkImportExport extends DataHandlerExtension
"Imported $total items, skipped $skipped, $failed failed"
);
} else {
throw new SCoreException("Could not open zip archive");
throw new UserError("Could not open zip archive");
}
}
}

View file

@ -7,9 +7,6 @@ namespace Shimmie2;
class BulkParentChildConfig
{
}
class BulkParentChildException extends BulkActionException
{
}
class BulkParentChild extends Extension
{

View file

@ -42,7 +42,7 @@ class CommentDeletionEvent extends Event
}
}
class CommentPostingException extends SCoreException
class CommentPostingException extends InvalidInput
{
}
@ -203,14 +203,10 @@ class CommentList extends Extension
{
global $cache, $config, $database, $user, $page;
if ($event->page_matches("comment/add", method: "POST", permission: Permissions::CREATE_COMMENT)) {
try {
$i_iid = int_escape($event->req_POST('image_id'));
send_event(new CommentPostingEvent($i_iid, $user, $event->req_POST('comment')));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$i_iid", null, "comment_on_$i_iid"));
} catch (CommentPostingException $ex) {
$this->theme->display_error(403, "Comment Blocked", $ex->getMessage());
}
$i_iid = int_escape($event->req_POST('image_id'));
send_event(new CommentPostingEvent($i_iid, $user, $event->req_POST('comment')));
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/$i_iid", null, "comment_on_$i_iid"));
}
if ($event->page_matches("comment/delete/{comment_id}/{image_id}", permission: Permissions::DELETE_COMMENT)) {
// FIXME: post, not args

View file

@ -139,13 +139,13 @@ class CronUploader extends Extension
{
global $page;
if (empty($folder)) {
throw new SCoreException("folder empty");
throw new InvalidInput("folder empty");
}
$queue_dir = $this->get_queue_dir();
$stage_dir = join_path($this->get_failed_dir(), $folder);
if (!is_dir($stage_dir)) {
throw new SCoreException("Could not find $stage_dir");
throw new InvalidInput("Could not find $stage_dir");
}
$this->prep_root_dir();
@ -326,22 +326,22 @@ class CronUploader extends Extension
$this->set_headers();
if (!$config->get_bool(UserConfig::ENABLE_API_KEYS)) {
throw new SCoreException("User API keys are not enabled. Please enable them for the cron upload functionality to work.");
throw new ServerError("User API keys are not enabled. Please enable them for the cron upload functionality to work.");
}
if ($user->is_anonymous()) {
throw new SCoreException("User not present. Please specify the api_key for the user to run cron upload as.");
throw new UserError("User not present. Please specify the api_key for the user to run cron upload as.");
}
$this->log_message(SCORE_LOG_INFO, "Logged in as user {$user->name}");
if (!$user->can(Permissions::CRON_RUN)) {
throw new SCoreException("User does not have permission to run cron upload");
throw new PermissionDenied("User does not have permission to run cron upload");
}
$lockfile = false_throws(fopen($this->get_lock_file(), "w"));
if (!flock($lockfile, LOCK_EX | LOCK_NB)) {
throw new SCoreException("Cron upload process is already running");
throw new ServerError("Cron upload process is already running");
}
self::$IMPORT_RUNNING = true;

View file

@ -112,7 +112,7 @@ class Forum extends Extension
$errors = $this->sanity_check_viewed_thread($threadID);
if (count($errors) > 0) {
throw new UserErrorException(implode("<br>", $errors));
throw new InvalidInput(implode("<br>", $errors));
}
$this->show_posts($threadID, $pageNumber, $user->can(Permissions::FORUM_ADMIN));
@ -132,7 +132,7 @@ class Forum extends Extension
$errors = $this->sanity_check_new_thread();
if (count($errors) > 0) {
throw new UserErrorException(implode("<br>", $errors));
throw new InvalidInput(implode("<br>", $errors));
}
$newThreadID = $this->save_new_thread($user);
@ -171,7 +171,7 @@ class Forum extends Extension
$errors = $this->sanity_check_new_post();
if (count($errors) > 0) {
throw new UserErrorException(implode("<br>", $errors));
throw new InvalidInput(implode("<br>", $errors));
}
$this->save_new_post($threadID, $user);
}

View file

@ -6,9 +6,6 @@ namespace Shimmie2;
class Holiday extends Extension
{
/** @var HolidayTheme */
protected Themelet $theme;
public function onInitExt(InitExtEvent $event): void
{
global $config;
@ -23,9 +20,11 @@ class Holiday extends Extension
public function onPageRequest(PageRequestEvent $event): void
{
global $config;
global $config, $page;
if (date('d/m') == '01/04' && $config->get_bool("holiday_aprilfools")) {
$this->theme->display_holiday("aprilfools");
$page->add_html_header(
"<link rel='stylesheet' href='".get_base_href()."/ext/holiday/stylesheets/aprilfools.css' type='text/css'>"
);
}
}
}

View file

@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
class HolidayTheme extends Themelet
{
public function display_holiday(?string $holiday): void
{
global $page;
if ($holiday) {
$page->add_html_header(
"<link rel='stylesheet' href='".get_base_href()."/contrib/holiday/stylesheets/$holiday.css' type='text/css'>"
);
}
}
}

View file

@ -60,7 +60,7 @@ class SearchTermParseEvent extends Event
}
}
class SearchTermParseException extends SCoreException
class SearchTermParseException extends InvalidInput
{
}

View file

@ -42,64 +42,51 @@ class Index extends Extension
$page_number = $event->get_iarg('page_num', 1);
$page_size = $config->get_int(IndexConfig::IMAGES);
try {
$fast_page_limit = 500;
$fast_page_limit = 500;
$ua = $_SERVER["HTTP_USER_AGENT"] ?? "No UA";
if (
SPEED_HAX
&& (
str_contains($ua, "Googlebot")
|| str_contains($ua, "YandexBot")
|| str_contains($ua, "bingbot")
|| str_contains($ua, "msnbot")
)
&& (
$count_search_terms > 1
|| ($count_search_terms == 1 && $search_terms[0][0] == "-")
)
) {
// bots love searching for weird combinations of tags...
$fast_page_limit = 10;
}
$ua = $_SERVER["HTTP_USER_AGENT"] ?? "No UA";
if (
SPEED_HAX
&& (
str_contains($ua, "Googlebot")
|| str_contains($ua, "YandexBot")
|| str_contains($ua, "bingbot")
|| str_contains($ua, "msnbot")
)
&& (
$count_search_terms > 1
|| ($count_search_terms == 1 && $search_terms[0][0] == "-")
)
) {
// bots love searching for weird combinations of tags...
$fast_page_limit = 10;
}
if (SPEED_HAX && $page_number > $fast_page_limit && !$user->can("big_search")) {
$this->theme->display_error(
404,
"Search limit hit",
"Only $fast_page_limit pages of results are searchable - " .
"if you want to find older results, use more specific search terms"
if (SPEED_HAX && $page_number > $fast_page_limit && !$user->can("big_search")) {
throw new PermissionDenied(
"Only $fast_page_limit pages of results are searchable - " .
"if you want to find older results, use more specific search terms"
);
}
$total_pages = (int)ceil(Search::count_images($search_terms) / $config->get_int(IndexConfig::IMAGES));
if (SPEED_HAX && $total_pages > $fast_page_limit && !$user->can("big_search")) {
$total_pages = $fast_page_limit;
}
$images = null;
if (SPEED_HAX) {
if ($count_search_terms === 0 && ($page_number < 10)) {
// extra caching for the first few post/list pages
$images = cache_get_or_set(
"post-list:$page_number",
fn () => Search::find_images(($page_number - 1) * $page_size, $page_size, $search_terms),
60
);
return;
}
$total_pages = (int)ceil(Search::count_images($search_terms) / $config->get_int(IndexConfig::IMAGES));
if (SPEED_HAX && $total_pages > $fast_page_limit && !$user->can("big_search")) {
$total_pages = $fast_page_limit;
}
$images = null;
if (SPEED_HAX) {
if ($count_search_terms === 0 && ($page_number < 10)) {
// extra caching for the first few post/list pages
$images = cache_get_or_set(
"post-list:$page_number",
fn () => Search::find_images(($page_number - 1) * $page_size, $page_size, $search_terms),
60
);
}
}
if (is_null($images)) {
$images = Search::find_images(($page_number - 1) * $page_size, $page_size, $search_terms);
}
} catch (PermissionDeniedException $pde) {
$this->theme->display_error(403, "Permission denied", $pde->error);
$total_pages = 0;
$images = [];
} catch (SearchTermParseException $stpe) {
$this->theme->display_error(400, "Malformed search query", $stpe->error);
$total_pages = 0;
$images = [];
}
if (is_null($images)) {
$images = Search::find_images(($page_number - 1) * $page_size, $page_size, $search_terms);
}
$count_images = count($images);

View file

@ -10,7 +10,7 @@ class IPBanTest extends ShimmiePHPUnitTestCase
public function testAccess(): void
{
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page('ip_ban/list');
});
}

View file

@ -20,6 +20,10 @@ class MediaException extends SCoreException
{
}
class InsufficientMemoryException extends ServerError
{
}
class Media extends Extension
{
/** @var MediaTheme */
@ -171,8 +175,6 @@ class Media extends Extension
/**
* @param MediaResizeEvent $event
* @throws MediaException
* @throws InsufficientMemoryException
*/
public function onMediaResize(MediaResizeEvent $event): void
{
@ -407,7 +409,7 @@ class Media extends Extension
{
$ext = FileExtension::get_for_mime($mime);
if (empty($ext)) {
throw new SCoreException("Could not determine extension for $mime");
throw new ServerError("Could not determine extension for $mime");
}
return $ext;
}
@ -646,8 +648,6 @@ class Media extends Extension
* @param string $output_filename
* @param ?string $output_mime If set to null, the output file type will be automatically determined via the $info parameter. Otherwise an exception will be thrown.
* @param int $output_quality Defaults to 80.
* @throws MediaException
* @throws InsufficientMemoryException if the estimated memory usage exceeds the memory limit.
*/
public static function image_resize_gd(
string $image_filename,

View file

@ -43,7 +43,7 @@ class MimeSystem extends Extension
$mime = MimeType::get_for_extension($ext);
if (empty($mime) || $mime === MimeType::OCTET_STREAM) {
throw new SCoreException("Unknown extension: $ext");
throw new UserError("Unknown extension: $ext");
}
$normalized_extension = FileExtension::get_for_mime($mime);

View file

@ -226,7 +226,7 @@ class MimeType
public static function get_for_file(string $file, ?string $ext = null): string
{
if (!file_exists($file)) {
throw new SCoreException("File not found: ".$file);
throw new UserError("File not found: ".$file);
}
$output = self::OCTET_STREAM;

View file

@ -26,12 +26,9 @@ class NotATagTest extends ShimmiePHPUnitTestCase
$this->assert_title("Post $image_id: two");
// Modified Bad as user - redirect
try {
$this->assertException(TagSetException::class, function () use ($image) {
send_event(new TagSetEvent($image, ["three", "face"]));
$this->fail("Should've had an exception");
} catch (TagSetException $e) {
$this->assertTrue(true);
}
});
$this->get_page("post/view/$image_id");
$this->assert_title("Post $image_id: two");

View file

@ -50,10 +50,13 @@ class NumericScoreTest extends ShimmiePHPUnitTestCase
$this->assertEquals(404, $page->code);
# test errors
$page = $this->get_page("post/list/upvoted_by=asdfasdf/1");
$this->assertEquals(404, $page->code);
$page = $this->get_page("post/list/downvoted_by=asdfasdf/1");
$this->assertEquals(404, $page->code);
$this->assertException(SearchTermParseException::class, function () {
$this->get_page("post/list/upvoted_by=asdfasdf/1");
});
$this->assertException(SearchTermParseException::class, function () {
$this->get_page("post/list/downvoted_by=asdfasdf/1");
});
$page = $this->get_page("post/list/upvoted_by_id=0/1");
$this->assertEquals(404, $page->code);
$page = $this->get_page("post/list/downvoted_by_id=0/1");

View file

@ -266,7 +266,7 @@ class OuroborosAPI extends Extension
$this->sendResponse(403, 'You cannot create new posts');
}
} elseif ($this->match('update')) {
throw new SCoreException("update not implemented");
throw new ServerError("update not implemented");
} elseif ($this->match('show')) {
// Show
$id = !empty($_REQUEST['id']) ? (int)filter_var_ex($_REQUEST['id'], FILTER_SANITIZE_NUMBER_INT) : null;

View file

@ -244,7 +244,7 @@ class PrivMsg extends Extension
$this->theme->display_composer($page, $user, $from_user, "Re: ".$pmo->subject);
}
} else {
throw new PermissionDeniedException("You do not have permission to view this PM");
throw new PermissionDenied("You do not have permission to view this PM");
}
}
if ($event->page_matches("pm/delete", method: "POST", permission: Permissions::READ_PM)) {

View file

@ -18,13 +18,6 @@ abstract class PoolsConfig
public const AUTO_INCREMENT_ORDER = "poolsAutoIncrementOrder";
}
/**
* This class is just a wrapper around SCoreException.
*/
class PoolCreationException extends SCoreException
{
}
class PoolAddPostsEvent extends Event
{
public int $pool_id;
@ -254,20 +247,16 @@ class Pools extends Extension
$this->theme->new_pool_composer($page);
}
if ($event->page_matches("pool/create", method: "POST", permission: Permissions::POOLS_CREATE)) {
try {
$pce = send_event(
new PoolCreationEvent(
$event->req_POST("title"),
$user,
bool_escape($event->req_POST("public")),
$event->req_POST("description")
)
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pce->new_id));
} catch (PoolCreationException $e) {
$this->theme->display_error(400, "Error", $e->error);
}
$pce = send_event(
new PoolCreationEvent(
$event->req_POST("title"),
$user,
bool_escape($event->req_POST("public")),
$event->req_POST("description")
)
);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/view/" . $pce->new_id));
}
if ($event->page_matches("pool/view/{poolID}", method: "GET", paged: true)) {
$poolID = $event->get_iarg('poolID');
@ -426,7 +415,7 @@ class Pools extends Extension
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("pool/list"));
} else {
throw new PermissionDeniedException("You do not have permission to access this page");
throw new PermissionDenied("You do not have permission to access this page");
}
}
}
@ -613,7 +602,7 @@ class Pools extends Extension
private function assert_permission(User $user, Pool $pool): void
{
if (!$this->have_permission($user, $pool)) {
throw new PermissionDeniedException("You do not have permission to access this pool");
throw new PermissionDenied("You do not have permission to access this pool");
}
}
@ -659,13 +648,13 @@ class Pools extends Extension
global $user, $database;
if (!$user->can(Permissions::POOLS_UPDATE)) {
throw new PoolCreationException("You must be registered and logged in to add a image.");
throw new PermissionDenied("You must be registered and logged in to add a image.");
}
if (empty($event->title)) {
throw new PoolCreationException("Pool title is empty.");
throw new InvalidInput("Pool title is empty.");
}
if ($this->get_single_pool_from_title($event->title)) {
throw new PoolCreationException("A pool using this title already exists.");
throw new InvalidInput("A pool using this title already exists.");
}
$database->execute(

View file

@ -27,7 +27,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
$this->get_page('pool/list');
$this->assert_title("Pools");
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page('pool/new');
});
}

View file

@ -47,10 +47,10 @@ class PrivateImage extends Extension
$image_id = $event->get_iarg('image_id');
$image = Image::by_id($image_id);
if ($image == null) {
throw new SCoreException("Post not found.");
throw new ImageNotFound("Post not found.");
}
if ($image->owner_id != $user->can(Permissions::SET_OTHERS_PRIVATE_IMAGES)) {
throw new SCoreException("Cannot set another user's image to private.");
throw new PermissionDenied("Cannot set another user's image to private.");
}
self::privatize_image($image_id);
@ -62,10 +62,10 @@ class PrivateImage extends Extension
$image_id = $event->get_iarg('image_id');
$image = Image::by_id($image_id);
if ($image == null) {
throw new SCoreException("Post not found.");
throw new ImageNotFound("Post not found.");
}
if ($image->owner_id != $user->can(Permissions::SET_OTHERS_PRIVATE_IMAGES)) {
throw new SCoreException("Cannot set another user's image to public.");
throw new PermissionDenied("Cannot set another user's image to public.");
}
self::publicize_image($image_id);
@ -76,7 +76,7 @@ class PrivateImage extends Extension
if ($event->page_matches("user_admin/private_image", method: "POST")) {
$id = int_escape($event->req_POST('id'));
if ($id != $user->id) {
throw new SCoreException("Cannot change another user's settings");
throw new PermissionDenied("Cannot change another user's settings");
}
$set_default = array_key_exists("set_default", $event->POST);
$view_default = array_key_exists("view_default", $event->POST);

View file

@ -21,7 +21,7 @@ class RandomImage extends Extension
$search_terms = Tag::explode($event->get_arg('search', ""), false);
$image = Image::by_random($search_terms);
if (!$image) {
throw new SCoreException("Couldn't find any posts randomly");
throw new ImageNotFound("Couldn't find any posts randomly");
}
if ($action === "download") {

View file

@ -117,7 +117,7 @@ class Ratings extends Extension
* Deny images upon insufficient permissions.
**/
if (!$this->check_permissions($event->image)) {
throw new SCoreException("Access denied");
throw new PermissionDenied("Access denied");
}
}

View file

@ -16,14 +16,15 @@ abstract class ResizeConfig
public const GET_ENABLED = 'resize_get_enabled';
}
class ImageResizeException extends ServerError
{
}
/**
* This class handles image resize requests.
*/
class ResizeImage extends Extension
{
/** @var ResizeImageTheme */
protected Themelet $theme;
/**
* Needs to be after the data processing extensions
*/
@ -120,11 +121,7 @@ class ResizeImage extends Extension
}
}
if ($isanigif == 0) {
try {
$this->resize_image($image_obj, $width, $height);
} catch (ImageResizeException $e) {
$this->theme->display_resize_error($page, "Error Resizing", $e->error);
}
$this->resize_image($image_obj, $width, $height);
//Need to generate thumbnail again...
//This only seems to be an issue if one of the sizes was set to 0.
@ -152,13 +149,9 @@ class ResizeImage extends Extension
$width = int_escape($event->get_POST('resize_width'));
$height = int_escape($event->get_POST('resize_height'));
if ($width || $height) {
try {
$this->resize_image($image, $width, $height);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$image_id));
} catch (ImageResizeException $e) {
$this->theme->display_resize_error($page, "Error Resizing", $e->error);
}
$this->resize_image($image, $width, $height);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$image_id));
}
}
}

View file

@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
use function MicroHTML\{rawHTML};
class ResizeImageTheme extends Themelet
{
public function display_resize_error(Page $page, string $title, string $message): void
{
$page->set_title("Resize Image");
$page->set_heading("Resize Image");
$page->add_block(new NavBlock());
$page->add_block(new Block($title, $message));
}
}

View file

@ -20,9 +20,6 @@ class ImageRotateException extends SCoreException
*/
class RotateImage extends Extension
{
/** @var RotateImageTheme */
protected Themelet $theme;
public const SUPPORTED_MIME = [MimeType::JPEG, MimeType::PNG, MimeType::GIF, MimeType::WEBP];
public function onInitExt(InitExtEvent $event): void
@ -70,13 +67,9 @@ class RotateImage extends Extension
$deg = int_escape($event->req_POST('rotate_deg'));
/* Attempt to rotate the image */
try {
$this->rotate_image($image_id, $deg);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$image_id));
} catch (ImageRotateException $e) {
$this->theme->display_rotate_error($page, "Error Rotating", $e->error);
}
$this->rotate_image($image_id, $deg);
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/view/".$image_id));
}
}
}

View file

@ -1,19 +0,0 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
class RotateImageTheme extends Themelet
{
/**
* Display the error.
*/
public function display_rotate_error(Page $page, string $title, string $message): void
{
$page->set_title("Rotate Image");
$page->set_heading("Rotate Image");
$page->add_block(new NavBlock());
$page->add_block(new Block($title, $message));
}
}

View file

@ -39,14 +39,8 @@ class RSSImages extends Extension
if (SPEED_HAX && $page_number > 9) {
return;
}
try {
$images = Search::find_images(($page_number - 1) * $page_size, $page_size, $search_terms);
$this->do_rss($images, $search_terms, $page_number);
} catch (SearchTermParseException $stpe) {
$this->theme->display_error(400, "Search parse error", $stpe->error);
} catch (PermissionDeniedException $pde) {
$this->theme->display_error(403, "Permission denied", $pde->error);
}
$images = Search::find_images(($page_number - 1) * $page_size, $page_size, $search_terms);
$this->do_rss($images, $search_terms, $page_number);
}
}

View file

@ -18,7 +18,7 @@ class SetupTest extends ShimmiePHPUnitTestCase
public function testAuthAnon(): void
{
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page('setup');
});
}
@ -26,7 +26,7 @@ class SetupTest extends ShimmiePHPUnitTestCase
public function testAuthUser(): void
{
$this->log_in_as_user();
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page('setup');
});
}

View file

@ -42,7 +42,7 @@ class SourceSetEvent extends Event
}
class TagSetException extends UserErrorException
class TagSetException extends UserError
{
public ?string $redirect;
@ -202,7 +202,7 @@ class TagEdit extends Extension
if ($owner instanceof User) {
send_event(new OwnerSetEvent($event->image, $owner));
} else {
throw new NullUserException("Error: No user with that name was found.");
throw new UserNotFound("Error: No user with that name was found.");
}
}
if ($user->can(Permissions::EDIT_IMAGE_TAG) && isset($event->params['tag_edit__tags'])) {

View file

@ -207,7 +207,7 @@ class TagHistory extends Extension
$image = Image::by_id($stored_image_id);
if (!$image instanceof Image) {
throw new ImageDoesNotExist("Error: cannot find any image with the ID = ". $stored_image_id);
throw new ImageNotFound("Error: cannot find any image with the ID = ". $stored_image_id);
}
log_debug("tag_history", 'Reverting tags of >>'.$stored_image_id.' to ['.$stored_tags.']');

View file

@ -53,7 +53,7 @@ class Trash extends Extension
* Deny images upon insufficient permissions.
**/
if (!$this->check_permissions($event->image)) {
throw new SCoreException("Access denied");
throw new PermissionDenied("Access denied");
}
}

View file

@ -4,8 +4,6 @@ declare(strict_types=1);
namespace Shimmie2;
use function MicroHTML\INPUT;
class TrashTheme extends Themelet
{
public function get_help_html(): string

View file

@ -74,10 +74,6 @@ class UserCreationException extends SCoreException
{
}
class NullUserException extends SCoreException
{
}
#[Type]
class LoginResult
{
@ -268,7 +264,7 @@ class UserPage extends Extension
$duser = User::by_id($input['id']);
if ($this->user_can_edit_user($user, $duser)) {
if ($input['pass1'] != $input['pass2']) {
throw new UserErrorException("Passwords don't match");
throw new InvalidInput("Passwords don't match");
} else {
// FIXME: send_event()
$duser->set_password($input['pass1']);
@ -664,7 +660,7 @@ class UserPage extends Extension
} elseif (is_null($my_user->email)) {
$this->theme->display_error(400, "Error", "That user has no registered email address");
} else {
throw new SCoreException("Email sending not implemented");
throw new ServerError("Email sending not implemented");
}
}

View file

@ -57,7 +57,7 @@ class UserPageTest extends ShimmiePHPUnitTestCase
{
global $page;
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->log_out();
$this->post_page('user_admin/create_other', [
'name' => 'testnew',

View file

@ -144,7 +144,7 @@ class UserConfig extends Extension
$duser = User::by_id($input['id']);
if ($user->id != $duser->id && !$user->can(Permissions::CHANGE_OTHER_USER_SETTING)) {
throw new PermissionDeniedException("You do not have permission to change other user's settings");
throw new PermissionDenied("You do not have permission to change other user's settings");
}
$target_config = UserConfig::get_for_user($duser->id);

View file

@ -10,7 +10,7 @@ class UserConfigTest extends ShimmiePHPUnitTestCase
public function testUserConfigPage(): void
{
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page('user_config');
});

View file

@ -34,7 +34,7 @@ class VarnishPurger extends Extension
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode != 200) {
throw new SCoreException('PURGE ' . $url . ' unsuccessful (HTTP '. $httpCode . ')');
throw new ServerError('PURGE ' . $url . ' unsuccessful (HTTP '. $httpCode . ')');
}
curl_close($ch);
}

View file

@ -46,10 +46,6 @@ class WikiDeletePageEvent extends Event
}
}
class WikiUpdateException extends SCoreException
{
}
#[Type(name: "WikiPage")]
class WikiPage
{
@ -188,7 +184,7 @@ class Wiki extends Extension
if ($this->can_edit($user, $content)) {
$this->theme->display_page_editor($page, $content);
} else {
throw new PermissionDeniedException("You are not allowed to edit this page");
throw new PermissionDenied("You are not allowed to edit this page");
}
}
}
@ -211,7 +207,7 @@ class Wiki extends Extension
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("wiki/$u_title"));
} else {
throw new PermissionDeniedException("You are not allowed to edit this page");
throw new PermissionDenied("You are not allowed to edit this page");
}
} elseif($action == "delete_revision") {
$content = $this->get_page($title);
@ -222,7 +218,7 @@ class Wiki extends Extension
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("wiki/$u_title"));
} else {
throw new PermissionDeniedException("You are not allowed to edit this page");
throw new PermissionDenied("You are not allowed to edit this page");
}
} elseif($action == "delete_all") {
if ($user->can(Permissions::WIKI_ADMIN)) {
@ -282,7 +278,7 @@ class Wiki extends Extension
);
}
} catch (\Exception $e) {
throw new WikiUpdateException("Somebody else edited that page at the same time :-(");
throw new UserError("Somebody else edited that page at the same time :-(");
}
}

View file

@ -21,7 +21,7 @@ class WikiTest extends ShimmiePHPUnitTestCase
$this->assert_title("test");
$this->assert_text("This is a default page");
$this->assertException(PermissionDeniedException::class, function () {
$this->assertException(PermissionDenied::class, function () {
$this->get_page("wiki/test/edit");
});
}

View file

@ -105,7 +105,7 @@ try {
if ($database->is_transaction_open()) {
$database->rollback();
}
if(is_a($e, \Shimmie2\UserErrorException::class)) {
if(is_a($e, \Shimmie2\UserError::class)) {
$page->set_mode(PageMode::PAGE);
$page->set_code($e->http_code);
$page->set_title("Error");