[core] a load more type hints, and fix bugs revealed by type hints
This commit is contained in:
parent
373be4e05c
commit
b60c3fe362
158 changed files with 1532 additions and 616 deletions
|
@ -496,6 +496,9 @@ class BasePage
|
|||
return ["script.js"];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: NavLink[], 1: NavLink[]}
|
||||
*/
|
||||
protected function get_nav_links(): array
|
||||
{
|
||||
$pnbe = send_event(new PageNavBuildingEvent());
|
||||
|
@ -641,6 +644,7 @@ class BasePage
|
|||
|
||||
class PageNavBuildingEvent extends Event
|
||||
{
|
||||
/** @var NavLink[] */
|
||||
public array $links = [];
|
||||
|
||||
public function add_nav_link(string $name, Link $link, string $desc, ?bool $active = null, int $order = 50): void
|
||||
|
@ -653,6 +657,7 @@ class PageSubNavBuildingEvent extends Event
|
|||
{
|
||||
public string $parent;
|
||||
|
||||
/** @var NavLink[] */
|
||||
public array $links = [];
|
||||
|
||||
public function __construct(string $parent)
|
||||
|
@ -704,6 +709,9 @@ class NavLink
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $pages_matched
|
||||
*/
|
||||
public static function is_active(array $pages_matched, string $url = null): bool
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -67,6 +67,11 @@ class EventTracingCache implements CacheInterface
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $keys
|
||||
* @param mixed $default
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getMultiple($keys, $default = null)
|
||||
{
|
||||
$this->tracer->begin("Cache Get Multiple", ["keys" => $keys]);
|
||||
|
@ -75,6 +80,9 @@ class EventTracingCache implements CacheInterface
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $values
|
||||
*/
|
||||
public function setMultiple($values, $ttl = null)
|
||||
{
|
||||
$this->tracer->begin("Cache Set Multiple", ["keys" => array_keys($values)]);
|
||||
|
@ -83,6 +91,9 @@ class EventTracingCache implements CacheInterface
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $keys
|
||||
*/
|
||||
public function deleteMultiple($keys)
|
||||
{
|
||||
$this->tracer->begin("Cache Delete Multiple", ["keys" => $keys]);
|
||||
|
|
|
@ -10,7 +10,9 @@ namespace Shimmie2;
|
|||
class CommandBuilder
|
||||
{
|
||||
private string $executable;
|
||||
/** @var string[] */
|
||||
private array $args = [];
|
||||
/** @var string[] */
|
||||
public array $output;
|
||||
|
||||
public function __construct(string $executable)
|
||||
|
|
|
@ -41,6 +41,8 @@ interface Config
|
|||
|
||||
/**
|
||||
* Set a configuration option to a new value, regardless of what the value is at the moment.
|
||||
*
|
||||
* @param mixed[] $value
|
||||
*/
|
||||
public function set_array(string $name, array $value): void;
|
||||
//@} /*--------------------------------------------------------------------------------------------*/
|
||||
|
@ -93,6 +95,8 @@ interface Config
|
|||
* This has the advantage that the values will show up in the "advanced" setup
|
||||
* page where they can be modified, while calling get_* with a "default"
|
||||
* parameter won't show up.
|
||||
*
|
||||
* @param mixed[] $value
|
||||
*/
|
||||
public function set_default_array(string $name, array $value): void;
|
||||
//@} /*--------------------------------------------------------------------------------------------*/
|
||||
|
@ -120,6 +124,9 @@ interface Config
|
|||
|
||||
/**
|
||||
* Pick a value out of the table by name, cast to the appropriate data type.
|
||||
*
|
||||
* @param mixed[] $default
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function get_array(string $name, ?array $default = []): ?array;
|
||||
//@} /*--------------------------------------------------------------------------------------------*/
|
||||
|
@ -134,6 +141,7 @@ interface Config
|
|||
*/
|
||||
abstract class BaseConfig implements Config
|
||||
{
|
||||
/** @var array<string, mixed> */
|
||||
public array $values = [];
|
||||
|
||||
public function set_int(string $name, ?int $value): void
|
||||
|
@ -205,16 +213,31 @@ abstract class BaseConfig implements Config
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of int|null
|
||||
* @param T $default
|
||||
* @return T|int
|
||||
*/
|
||||
public function get_int(string $name, ?int $default = null): ?int
|
||||
{
|
||||
return (int)($this->get($name, $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of float|null
|
||||
* @param T $default
|
||||
* @return T|float
|
||||
*/
|
||||
public function get_float(string $name, ?float $default = null): ?float
|
||||
{
|
||||
return (float)($this->get($name, $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of string|null
|
||||
* @param T $default
|
||||
* @return T|string
|
||||
*/
|
||||
public function get_string(string $name, ?string $default = null): ?string
|
||||
{
|
||||
$val = $this->get($name, $default);
|
||||
|
@ -224,17 +247,34 @@ abstract class BaseConfig implements Config
|
|||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of bool|null
|
||||
* @param T $default
|
||||
* @return T|bool
|
||||
*/
|
||||
public function get_bool(string $name, ?bool $default = null): ?bool
|
||||
{
|
||||
return bool_escape($this->get($name, $default));
|
||||
}
|
||||
|
||||
public function get_array(string $name, ?array $default = []): ?array
|
||||
/**
|
||||
* @template T of array<string>|null
|
||||
* @param T $default
|
||||
* @return T|array<string>
|
||||
*/
|
||||
public function get_array(string $name, ?array $default = null): ?array
|
||||
{
|
||||
return explode(",", $this->get($name, ""));
|
||||
$val = $this->get($name);
|
||||
if(is_null($val)) {
|
||||
return $default;
|
||||
}
|
||||
if(empty($val)) {
|
||||
return [];
|
||||
}
|
||||
return explode(",", $val);
|
||||
}
|
||||
|
||||
private function get(string $name, $default = null): mixed
|
||||
private function get(string $name, mixed $default = null): mixed
|
||||
{
|
||||
if (isset($this->values[$name])) {
|
||||
return $this->values[$name];
|
||||
|
|
|
@ -19,8 +19,12 @@ enum DatabaseDriverID: string
|
|||
class DatabaseException extends SCoreException
|
||||
{
|
||||
public string $query;
|
||||
/** @var array<string, mixed> */
|
||||
public array $args;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $args
|
||||
*/
|
||||
public function __construct(string $msg, string $query, array $args)
|
||||
{
|
||||
parent::__construct($msg);
|
||||
|
@ -32,6 +36,8 @@ class DatabaseException extends SCoreException
|
|||
|
||||
/**
|
||||
* A class for controlled database access
|
||||
*
|
||||
* @phpstan-type QueryArgs array<string, string|int|bool|null>
|
||||
*/
|
||||
class Database
|
||||
{
|
||||
|
@ -52,6 +58,7 @@ class Database
|
|||
* How many queries this DB object has run
|
||||
*/
|
||||
public int $query_count = 0;
|
||||
/** @var string[] */
|
||||
public array $queries = [];
|
||||
|
||||
public function __construct(string $dsn)
|
||||
|
@ -162,13 +169,15 @@ class Database
|
|||
return $this->get_engine()->get_version($this->get_db());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryArgs $args
|
||||
*/
|
||||
private function count_time(string $method, float $start, string $query, ?array $args): void
|
||||
{
|
||||
global $_tracer, $tracer_enabled;
|
||||
$dur = ftime() - $start;
|
||||
// trim whitespace
|
||||
$query = preg_replace('/[\n\t ]/m', ' ', $query);
|
||||
$query = preg_replace('/ +/m', ' ', $query);
|
||||
$query = preg_replace('/[\n\t ]+/m', ' ', $query);
|
||||
$query = trim($query);
|
||||
if ($tracer_enabled) {
|
||||
$_tracer->complete($start * 1000000, $dur * 1000000, "DB Query", ["query" => $query, "args" => $args, "method" => $method]);
|
||||
|
@ -188,6 +197,9 @@ class Database
|
|||
$this->get_engine()->notify($this->get_db(), $channel, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryArgs $args
|
||||
*/
|
||||
public function _execute(string $query, array $args = []): PDOStatement
|
||||
{
|
||||
try {
|
||||
|
@ -203,6 +215,8 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query with no return
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
*/
|
||||
public function execute(string $query, array $args = []): PDOStatement
|
||||
{
|
||||
|
@ -214,6 +228,9 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and return a 2D array.
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
* @return array<array<string, mixed>>
|
||||
*/
|
||||
public function get_all(string $query, array $args = []): array
|
||||
{
|
||||
|
@ -225,6 +242,8 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and return a iterable object for use with generators.
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
*/
|
||||
public function get_all_iterable(string $query, array $args = []): PDOStatement
|
||||
{
|
||||
|
@ -236,6 +255,9 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and return a single row.
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_row(string $query, array $args = []): ?array
|
||||
{
|
||||
|
@ -247,6 +269,9 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and return the first column of each row.
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function get_col(string $query, array $args = []): array
|
||||
{
|
||||
|
@ -258,6 +283,8 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and return the first column of each row as a single iterable object.
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
*/
|
||||
public function get_col_iterable(string $query, array $args = []): \Generator
|
||||
{
|
||||
|
@ -271,6 +298,9 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and return the the first column => the second column.
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function get_pairs(string $query, array $args = []): array
|
||||
{
|
||||
|
@ -283,6 +313,8 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and return the the first column => the second column as an iterable object.
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
*/
|
||||
public function get_pairs_iterable(string $query, array $args = []): \Generator
|
||||
{
|
||||
|
@ -296,6 +328,8 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and return a single value, or null.
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
*/
|
||||
public function get_one(string $query, array $args = []): mixed
|
||||
{
|
||||
|
@ -307,6 +341,8 @@ class Database
|
|||
|
||||
/**
|
||||
* Execute an SQL query and returns a bool indicating if any data was returned
|
||||
*
|
||||
* @param QueryArgs $args
|
||||
*/
|
||||
public function exists(string $query, array $args = []): bool
|
||||
{
|
||||
|
|
|
@ -129,7 +129,7 @@ class PostgreSQL extends DBEngine
|
|||
}
|
||||
|
||||
// shimmie functions for export to sqlite
|
||||
function _unix_timestamp($date): int
|
||||
function _unix_timestamp(string $date): int
|
||||
{
|
||||
return strtotime($date);
|
||||
}
|
||||
|
@ -137,11 +137,11 @@ function _now(): string
|
|||
{
|
||||
return date("Y-m-d H:i:s");
|
||||
}
|
||||
function _floor($a): float
|
||||
function _floor(float|int $a): float
|
||||
{
|
||||
return floor($a);
|
||||
}
|
||||
function _log($a, $b = null): float
|
||||
function _log(float $a, ?float $b = null): float
|
||||
{
|
||||
if (is_null($b)) {
|
||||
return log($a);
|
||||
|
@ -149,19 +149,19 @@ function _log($a, $b = null): float
|
|||
return log($b, $a);
|
||||
}
|
||||
}
|
||||
function _isnull($a): bool
|
||||
function _isnull(mixed $a): bool
|
||||
{
|
||||
return is_null($a);
|
||||
}
|
||||
function _md5($a): string
|
||||
function _md5(string $a): string
|
||||
{
|
||||
return md5($a);
|
||||
}
|
||||
function _concat($a, $b): string
|
||||
function _concat(string $a, string $b): string
|
||||
{
|
||||
return $a . $b;
|
||||
}
|
||||
function _lower($a): string
|
||||
function _lower(string $a): string
|
||||
{
|
||||
return strtolower($a);
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ function _rand(): int
|
|||
{
|
||||
return rand();
|
||||
}
|
||||
function _ln($n): float
|
||||
function _ln(float $n): float
|
||||
{
|
||||
return log($n);
|
||||
}
|
||||
|
|
|
@ -143,6 +143,9 @@ class PageRequestEvent extends Event
|
|||
* Many things use these functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_search_terms(): array
|
||||
{
|
||||
$search_terms = [];
|
||||
|
@ -172,7 +175,6 @@ class PageRequestEvent extends Event
|
|||
$str = $out;
|
||||
// end legacy
|
||||
|
||||
|
||||
$search_terms = Tag::explode($str);
|
||||
}
|
||||
return $search_terms;
|
||||
|
|
|
@ -22,9 +22,10 @@ abstract class Extension
|
|||
protected Themelet $theme;
|
||||
public ExtensionInfo $info;
|
||||
|
||||
/** @var string[] */
|
||||
private static array $enabled_extensions = [];
|
||||
|
||||
public function __construct($class = null)
|
||||
public function __construct(?string $class = null)
|
||||
{
|
||||
$class = $class ?? get_called_class();
|
||||
$this->theme = $this->get_theme_object($class);
|
||||
|
@ -87,6 +88,9 @@ abstract class Extension
|
|||
return in_array($key, self::$enabled_extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_enabled_extensions(): array
|
||||
{
|
||||
return self::$enabled_extensions;
|
||||
|
@ -141,8 +145,11 @@ abstract class ExtensionInfo
|
|||
public string $name;
|
||||
public string $license;
|
||||
public string $description;
|
||||
/** @var array<string, string> */
|
||||
public array $authors = [];
|
||||
/** @var string[] */
|
||||
public array $dependencies = [];
|
||||
/** @var string[] */
|
||||
public array $conflicts = [];
|
||||
public ExtensionVisibility $visibility = ExtensionVisibility::DEFAULT;
|
||||
public ?string $link = null;
|
||||
|
@ -170,8 +177,11 @@ abstract class ExtensionInfo
|
|||
return $this->support_info;
|
||||
}
|
||||
|
||||
/** @var array<string, ExtensionInfo> */
|
||||
private static array $all_info_by_key = [];
|
||||
/** @var array<string, ExtensionInfo> */
|
||||
private static array $all_info_by_class = [];
|
||||
/** @var string[] */
|
||||
private static array $core_extensions = [];
|
||||
|
||||
protected function __construct()
|
||||
|
@ -207,16 +217,25 @@ abstract class ExtensionInfo
|
|||
$this->supported = empty($this->support_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ExtensionInfo[]
|
||||
*/
|
||||
public static function get_all(): array
|
||||
{
|
||||
return array_values(self::$all_info_by_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_all_keys(): array
|
||||
{
|
||||
return array_keys(self::$all_info_by_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_core_extensions(): array
|
||||
{
|
||||
return self::$core_extensions;
|
||||
|
@ -285,6 +304,7 @@ abstract class FormatterExtension extends Extension
|
|||
*/
|
||||
abstract class DataHandlerExtension extends Extension
|
||||
{
|
||||
/** @var string[] */
|
||||
protected array $SUPPORTED_MIME = [];
|
||||
|
||||
public function onDataUpload(DataUploadEvent $event): void
|
||||
|
@ -396,6 +416,9 @@ abstract class DataHandlerExtension extends Extension
|
|||
return MimeType::matches_array($mime, $this->SUPPORTED_MIME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_all_supported_mimes(): array
|
||||
{
|
||||
$arr = [];
|
||||
|
@ -413,6 +436,9 @@ abstract class DataHandlerExtension extends Extension
|
|||
return $arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_all_supported_exts(): array
|
||||
{
|
||||
$arr = [];
|
||||
|
|
|
@ -63,7 +63,9 @@ class ImageReplaceEvent extends Event
|
|||
) {
|
||||
parent::__construct();
|
||||
$this->old_hash = $image->hash;
|
||||
$this->new_hash = md5_file($tmp_filename);
|
||||
$hash = md5_file($tmp_filename);
|
||||
assert($hash !== false, "Failed to hash file $tmp_filename");
|
||||
$this->new_hash = $hash;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ enum ImagePropType
|
|||
* As of 2.2, this no longer necessarily represents an
|
||||
* image per se, but could be a video, sound file, or any
|
||||
* other supported upload type.
|
||||
*
|
||||
* @implements \ArrayAccess<string, mixed>
|
||||
*/
|
||||
#[Type(name: "Post")]
|
||||
class Image implements \ArrayAccess
|
||||
|
@ -71,6 +73,8 @@ class Image implements \ArrayAccess
|
|||
/**
|
||||
* One will very rarely construct an image directly, more common
|
||||
* would be to use Image::by_id, Image::by_hash, etc.
|
||||
*
|
||||
* @param array<string|int, mixed>|null $row
|
||||
*/
|
||||
public function __construct(?array $row = null)
|
||||
{
|
||||
|
@ -82,6 +86,7 @@ class Image implements \ArrayAccess
|
|||
continue;
|
||||
} elseif(property_exists($this, $name)) {
|
||||
$t = (new \ReflectionProperty($this, $name))->getType();
|
||||
assert(!is_null($t));
|
||||
if(is_a($t, \ReflectionNamedType::class)) {
|
||||
$this->$name = match($t->getName()) {
|
||||
"int" => is_null($value) ? $value : int_escape((string)$value),
|
||||
|
@ -116,10 +121,12 @@ class Image implements \ArrayAccess
|
|||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
assert(is_string($offset));
|
||||
return array_key_exists($offset, static::$prop_types);
|
||||
}
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
assert(is_string($offset));
|
||||
if(!$this->offsetExists($offset)) {
|
||||
throw new \OutOfBoundsException("Undefined dynamic property: $offset");
|
||||
}
|
||||
|
@ -127,16 +134,19 @@ class Image implements \ArrayAccess
|
|||
}
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
assert(is_string($offset));
|
||||
$this->dynamic_props[$offset] = $value;
|
||||
}
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
assert(is_string($offset));
|
||||
unset($this->dynamic_props[$offset]);
|
||||
}
|
||||
|
||||
#[Field(name: "post_id")]
|
||||
public function graphql_oid(): int
|
||||
{
|
||||
assert(!is_null($this->id));
|
||||
return $this->id;
|
||||
}
|
||||
#[Field(name: "id")]
|
||||
|
@ -170,6 +180,9 @@ class Image implements \ArrayAccess
|
|||
return (is_numberish($id) && strlen($id) != 32) ? Image::by_id((int)$id) : Image::by_hash($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
*/
|
||||
public static function by_random(array $tags = [], int $limit_range = 0): ?Image
|
||||
{
|
||||
$max = Search::count_images($tags);
|
||||
|
@ -234,7 +247,9 @@ class Image implements \ArrayAccess
|
|||
#[Field(name: "owner")]
|
||||
public function get_owner(): User
|
||||
{
|
||||
return User::by_id($this->owner_id);
|
||||
$user = User::by_id($this->owner_id);
|
||||
assert(!is_null($user));
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -457,7 +472,7 @@ class Image implements \ArrayAccess
|
|||
* Get the image's mime type.
|
||||
*/
|
||||
#[Field(name: "mime")]
|
||||
public function get_mime(): ?string
|
||||
public function get_mime(): string
|
||||
{
|
||||
if ($this->mime === MimeType::WEBP && $this->lossless) {
|
||||
return MimeType::WEBP_LOSSLESS;
|
||||
|
@ -468,7 +483,7 @@ class Image implements \ArrayAccess
|
|||
/**
|
||||
* Set the image's mime type.
|
||||
*/
|
||||
public function set_mime($mime): void
|
||||
public function set_mime(string $mime): void
|
||||
{
|
||||
$this->mime = $mime;
|
||||
$ext = FileExtension::get_for_mime($this->get_mime());
|
||||
|
@ -545,6 +560,8 @@ class Image implements \ArrayAccess
|
|||
|
||||
/**
|
||||
* Set the tags for this image.
|
||||
*
|
||||
* @param string[] $unfiltered_tags
|
||||
*/
|
||||
public function set_tags(array $unfiltered_tags): void
|
||||
{
|
||||
|
|
|
@ -12,9 +12,10 @@ namespace Shimmie2;
|
|||
* Add a directory full of images
|
||||
*
|
||||
* @param string $base
|
||||
* @param string[] $extra_tags
|
||||
* @return UploadResult[]
|
||||
*/
|
||||
function add_dir(string $base, ?array $extra_tags = []): array
|
||||
function add_dir(string $base, array $extra_tags = []): array
|
||||
{
|
||||
global $database;
|
||||
$results = [];
|
||||
|
@ -33,6 +34,7 @@ function add_dir(string $base, ?array $extra_tags = []): array
|
|||
]));
|
||||
$results = [];
|
||||
foreach($dae->images as $image) {
|
||||
assert(!is_null($image->id));
|
||||
$results[] = new UploadSuccess($filename, $image->id);
|
||||
}
|
||||
return $results;
|
||||
|
@ -59,7 +61,7 @@ function get_file_ext(string $filename): ?string
|
|||
* @param int $orig_width
|
||||
* @param int $orig_height
|
||||
* @param bool $use_dpi_scaling Enables the High-DPI scaling.
|
||||
* @return array
|
||||
* @return array{0: int, 1: int}
|
||||
*/
|
||||
function get_thumbnail_size(int $orig_width, int $orig_height, bool $use_dpi_scaling = false): array
|
||||
{
|
||||
|
@ -107,6 +109,9 @@ function get_thumbnail_size(int $orig_width, int $orig_height, bool $use_dpi_sca
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: int, 1: int, 2: float}
|
||||
*/
|
||||
function get_scaled_by_aspect_ratio(int $original_width, int $original_height, int $max_width, int $max_height): array
|
||||
{
|
||||
$xscale = ($max_width / $original_width);
|
||||
|
@ -120,7 +125,7 @@ function get_scaled_by_aspect_ratio(int $original_width, int $original_height, i
|
|||
/**
|
||||
* Fetches the thumbnails height and width settings and applies the High-DPI scaling setting before returning the dimensions.
|
||||
*
|
||||
* @return array [width, height]
|
||||
* @return array{0: int, 1: int}
|
||||
*/
|
||||
function get_thumbnail_max_size_scaled(): array
|
||||
{
|
||||
|
@ -147,7 +152,9 @@ function create_image_thumb(Image $image, string $engine = null): void
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param array{0: int, 1: int} $tsize
|
||||
*/
|
||||
function create_scaled_image(
|
||||
string $inname,
|
||||
string $outname,
|
||||
|
|
|
@ -86,7 +86,8 @@ class TagUsage
|
|||
*/
|
||||
class Tag
|
||||
{
|
||||
private static $tag_id_cache = [];
|
||||
/** @var array<string, int> */
|
||||
private static array $tag_id_cache = [];
|
||||
|
||||
public static function get_or_create_id(string $tag): int
|
||||
{
|
||||
|
@ -196,9 +197,13 @@ class Tag
|
|||
public static function sanitize(string $tag): string
|
||||
{
|
||||
$tag = preg_replace("/\s/", "", $tag); # whitespace
|
||||
assert($tag !== null);
|
||||
$tag = preg_replace('/\x20[\x0e\x0f]/', '', $tag); # unicode RTL
|
||||
assert($tag !== null);
|
||||
$tag = preg_replace("/\.+/", ".", $tag); # strings of dots?
|
||||
assert($tag !== null);
|
||||
$tag = preg_replace("/^(\.+[\/\\\\])+/", "", $tag); # trailing slashes?
|
||||
assert($tag !== null);
|
||||
$tag = trim($tag, ", \t\n\r\0\x0B");
|
||||
|
||||
if ($tag == ".") {
|
||||
|
@ -211,6 +216,10 @@ class Tag
|
|||
return $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $tags1
|
||||
* @param string[] $tags2
|
||||
*/
|
||||
public static function compare(array $tags1, array $tags2): bool
|
||||
{
|
||||
if (count($tags1) !== count($tags2)) {
|
||||
|
@ -225,6 +234,11 @@ class Tag
|
|||
return $tags1 == $tags2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $source
|
||||
* @param string[] $remove
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_diff_tags(array $source, array $remove): array
|
||||
{
|
||||
$before = array_map('strtolower', $source);
|
||||
|
@ -238,6 +252,10 @@ class Tag
|
|||
return $after;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
* @return string[]
|
||||
*/
|
||||
public static function sanitize_array(array $tags): array
|
||||
{
|
||||
global $page;
|
||||
|
|
|
@ -46,13 +46,19 @@ function SHM_FORM(string $target, string $method = "POST", bool $multipart = fal
|
|||
);
|
||||
}
|
||||
|
||||
function SHM_SIMPLE_FORM($target, ...$children): HTMLElement
|
||||
/**
|
||||
* @param array<string|HTMLElement|null> $children
|
||||
*/
|
||||
function SHM_SIMPLE_FORM(string $target, ...$children): HTMLElement
|
||||
{
|
||||
$form = SHM_FORM($target);
|
||||
$form->appendChild(emptyHTML(...$children));
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $args
|
||||
*/
|
||||
function SHM_SUBMIT(string $text, array $args = []): HTMLElement
|
||||
{
|
||||
$args["type"] = "submit";
|
||||
|
@ -60,6 +66,9 @@ function SHM_SUBMIT(string $text, array $args = []): HTMLElement
|
|||
return INPUT($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $args
|
||||
*/
|
||||
function SHM_A(string $href, string|HTMLElement $text, string $id = "", string $class = "", array $args = []): HTMLElement
|
||||
{
|
||||
$args["href"] = make_link($href);
|
||||
|
@ -83,7 +92,7 @@ function SHM_COMMAND_EXAMPLE(string $ex, string $desc): HTMLElement
|
|||
);
|
||||
}
|
||||
|
||||
function SHM_USER_FORM(User $duser, string $target, string $title, $body, $foot): HTMLElement
|
||||
function SHM_USER_FORM(User $duser, string $target, string $title, HTMLElement $body, HTMLElement|string $foot): HTMLElement
|
||||
{
|
||||
if (is_string($foot)) {
|
||||
$foot = TFOOT(TR(TD(["colspan" => "2"], INPUT(["type" => "submit", "value" => $foot]))));
|
||||
|
@ -106,12 +115,12 @@ function SHM_USER_FORM(User $duser, string $target, string $title, $body, $foot)
|
|||
* Generates a <select> element and sets up the given options.
|
||||
*
|
||||
* @param string $name The name attribute of <select>.
|
||||
* @param array $options An array of pairs of parameters for <option> tags. First one is value, second one is text. Example: ('optionA', 'Choose Option A').
|
||||
* @param array $selected_options The values of options that should be pre-selected.
|
||||
* @param array<string|int, string> $options An array of pairs of parameters for <option> tags. First one is value, second one is text. Example: ('optionA', 'Choose Option A').
|
||||
* @param array<string> $selected_options The values of options that should be pre-selected.
|
||||
* @param bool $required Wether the <select> element is required.
|
||||
* @param bool $multiple Wether the <select> element is multiple-choice.
|
||||
* @param bool $empty_option Whether the first option should be an empty one.
|
||||
* @param array $attrs Additional attributes dict for <select>. Example: ["id"=>"some_id", "class"=>"some_class"].
|
||||
* @param array<string, mixed> $attrs Additional attributes dict for <select>. Example: ["id"=>"some_id", "class"=>"some_class"].
|
||||
*/
|
||||
function SHM_SELECT(string $name, array $options, array $selected_options = [], bool $required = false, bool $multiple = false, bool $empty_option = false, array $attrs = []): HTMLElement
|
||||
{
|
||||
|
|
|
@ -10,6 +10,9 @@ namespace Shimmie2;
|
|||
|
||||
/**
|
||||
* Return the unique elements of an array, case insensitively
|
||||
*
|
||||
* @param array<string> $array
|
||||
* @return list<string>
|
||||
*/
|
||||
function array_iunique(array $array): array
|
||||
{
|
||||
|
@ -98,6 +101,8 @@ function full_copy(string $source, string $target): void
|
|||
|
||||
/**
|
||||
* Return a list of all the regular files in a directory and subdirectories
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
function list_files(string $base, string $_sub_dir = ""): array
|
||||
{
|
||||
|
@ -203,6 +208,8 @@ if (!function_exists('http_parse_headers')) {
|
|||
/**
|
||||
* HTTP Headers can sometimes be lowercase which will cause issues.
|
||||
* In cases like these, we need to make sure to check for them if the camelcase version does not exist.
|
||||
*
|
||||
* @param array<string, mixed> $headers
|
||||
*/
|
||||
function find_header(array $headers, string $name): ?string
|
||||
{
|
||||
|
@ -225,20 +232,22 @@ function find_header(array $headers, string $name): ?string
|
|||
if (!function_exists('mb_strlen')) {
|
||||
// TODO: we should warn the admin that they are missing multibyte support
|
||||
/** @noinspection PhpUnusedParameterInspection */
|
||||
function mb_strlen($str, $encoding): int
|
||||
function mb_strlen(string $str, string $encoding): int
|
||||
{
|
||||
return strlen($str);
|
||||
}
|
||||
function mb_internal_encoding($encoding): void
|
||||
function mb_internal_encoding(string $encoding): void
|
||||
{
|
||||
}
|
||||
function mb_strtolower($str): string
|
||||
function mb_strtolower(string $str): string
|
||||
{
|
||||
return strtolower($str);
|
||||
}
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
/**
|
||||
* @return class-string[]
|
||||
*/
|
||||
function get_subclasses_of(string $parent): array
|
||||
{
|
||||
$result = [];
|
||||
|
@ -307,6 +316,8 @@ function get_base_href(): string
|
|||
|
||||
/**
|
||||
* The opposite of the standard library's parse_url
|
||||
*
|
||||
* @param array<string, string|int> $parsed_url
|
||||
*/
|
||||
function unparse_url(array $parsed_url): string
|
||||
{
|
||||
|
@ -376,7 +387,7 @@ function url_escape(?string $input): string
|
|||
/**
|
||||
* Turn all manner of HTML / INI / JS / DB booleans into a PHP one
|
||||
*/
|
||||
function bool_escape($input): bool
|
||||
function bool_escape(mixed $input): bool
|
||||
{
|
||||
/*
|
||||
Sometimes, I don't like PHP -- this, is one of those times...
|
||||
|
@ -634,6 +645,10 @@ function isValidDate(string $date): bool
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $inputs
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
function validate_input(array $inputs): array
|
||||
{
|
||||
$outputs = [];
|
||||
|
@ -754,6 +769,12 @@ function join_path(string ...$paths): string
|
|||
|
||||
/**
|
||||
* Perform callback on each item returned by an iterator.
|
||||
*
|
||||
* @template T
|
||||
* @template U
|
||||
* @param callable(U):T $callback
|
||||
* @param \iterator<U> $iter
|
||||
* @return \Generator<T>
|
||||
*/
|
||||
function iterator_map(callable $callback, \iterator $iter): \Generator
|
||||
{
|
||||
|
@ -764,6 +785,12 @@ function iterator_map(callable $callback, \iterator $iter): \Generator
|
|||
|
||||
/**
|
||||
* Perform callback on each item returned by an iterator and combine the result into an array.
|
||||
*
|
||||
* @template T
|
||||
* @template U
|
||||
* @param callable(U):T $callback
|
||||
* @param \iterator<U> $iter
|
||||
* @return array<T>
|
||||
*/
|
||||
function iterator_map_to_array(callable $callback, \iterator $iter): array
|
||||
{
|
||||
|
|
|
@ -75,11 +75,16 @@ function _namespaced_class_name(string $class): string
|
|||
return str_replace("Shimmie2\\", "", $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the event listeners to a file for faster loading.
|
||||
*
|
||||
* @param array<string, array<int, Extension>> $event_listeners
|
||||
*/
|
||||
function _dump_event_listeners(array $event_listeners, string $path): void
|
||||
{
|
||||
$p = "<"."?php\nnamespace Shimmie2;\n";
|
||||
|
||||
foreach (get_subclasses_of("Shimmie2\Extension") as $class) {
|
||||
foreach (get_subclasses_of(Extension::class) as $class) {
|
||||
$scn = _namespaced_class_name($class);
|
||||
$p .= "\$$scn = new $scn(); ";
|
||||
}
|
||||
|
|
|
@ -69,7 +69,11 @@ if(class_exists("\\PHPUnit\\Framework\\TestCase")) {
|
|||
$_tracer->flush("data/test-trace.json");
|
||||
}
|
||||
|
||||
private static function check_args(?array $args): array
|
||||
/**
|
||||
* @param array<string, mixed> $args
|
||||
* @return array<string, string|mixed[]>
|
||||
*/
|
||||
private static function check_args(array $args): array
|
||||
{
|
||||
if (!$args) {
|
||||
return [];
|
||||
|
@ -84,11 +88,15 @@ if(class_exists("\\PHPUnit\\Framework\\TestCase")) {
|
|||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $get_args
|
||||
* @param array<string, mixed> $post_args
|
||||
*/
|
||||
protected static function request(
|
||||
string $method,
|
||||
string $page_name,
|
||||
?array $get_args = null,
|
||||
?array $post_args = null
|
||||
array $get_args = [],
|
||||
array $post_args = []
|
||||
): Page {
|
||||
// use a fresh page
|
||||
global $page;
|
||||
|
@ -109,14 +117,20 @@ if(class_exists("\\PHPUnit\\Framework\\TestCase")) {
|
|||
return $page;
|
||||
}
|
||||
|
||||
protected static function get_page(string $page_name, array $args = null): Page
|
||||
/**
|
||||
* @param array<string, mixed> $args
|
||||
*/
|
||||
protected static function get_page(string $page_name, array $args = []): Page
|
||||
{
|
||||
return self::request("GET", $page_name, $args, null);
|
||||
return self::request("GET", $page_name, $args, []);
|
||||
}
|
||||
|
||||
protected static function post_page(string $page_name, array $args = null): Page
|
||||
/**
|
||||
* @param array<string, mixed> $args
|
||||
*/
|
||||
protected static function post_page(string $page_name, array $args = []): Page
|
||||
{
|
||||
return self::request("POST", $page_name, null, $args);
|
||||
return self::request("POST", $page_name, [], $args);
|
||||
}
|
||||
|
||||
// page things
|
||||
|
|
|
@ -25,7 +25,9 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
$this->assert_search_results(["exclamation%"], [$image_id_2]);
|
||||
}
|
||||
|
||||
// base case
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function testUpload(): array
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
|
@ -41,8 +43,13 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
/** ******************************************************
|
||||
* Test turning a string into an abstract query
|
||||
*
|
||||
* @param string $tags
|
||||
* @param TagCondition[] $expected_tag_conditions
|
||||
* @param ImgCondition[] $expected_img_conditions
|
||||
* @param string $expected_order
|
||||
*/
|
||||
private function assert_TTC(
|
||||
string $tags,
|
||||
|
@ -142,8 +149,16 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
);
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
/** ******************************************************
|
||||
* Test turning an abstract query into SQL + fetching the results
|
||||
*
|
||||
* @param string[] $tcs
|
||||
* @param string[] $ics
|
||||
* @param string $order
|
||||
* @param int $limit
|
||||
* @param int $start
|
||||
* @param int[] $res
|
||||
* @param string[] $path
|
||||
*/
|
||||
private function assert_BSQ(
|
||||
array $tcs = [],
|
||||
|
@ -196,7 +211,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
* No-tag search *
|
||||
* * * * * * * * * * */
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_NoTags(array $image_ids): void
|
||||
public function testBSQ_NoTags(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -210,7 +225,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
* Fast-path search *
|
||||
* * * * * * * * * * */
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_FastPath_NoResults(array $image_ids): void
|
||||
public function testBSQ_FastPath_NoResults(): void
|
||||
{
|
||||
$this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -221,7 +236,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_FastPath_OneResult(array $image_ids): void
|
||||
public function testBSQ_FastPath_OneResult(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -232,7 +247,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_FastPath_ManyResults(array $image_ids): void
|
||||
public function testBSQ_FastPath_ManyResults(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -243,7 +258,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_FastPath_WildNoResults(array $image_ids): void
|
||||
public function testBSQ_FastPath_WildNoResults(): void
|
||||
{
|
||||
$this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -262,7 +277,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
* https://github.com/shish/shimmie2/issues/547
|
||||
*/
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_FastPath_WildOneResult(array $image_ids): void
|
||||
public function testBSQ_FastPath_WildOneResult(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -277,7 +292,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
* when a wildcard matches one image multiple times.
|
||||
*/
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_FastPath_WildManyResults(array $image_ids): void
|
||||
public function testBSQ_FastPath_WildManyResults(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
// two images match comp* - one matches it once, one matches it twice
|
||||
|
@ -292,7 +307,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
* General search *
|
||||
* * * * * * * * * * */
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_NoResults(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_NoResults(): void
|
||||
{
|
||||
$this->testUpload();
|
||||
# multiple tags, one of which doesn't exist
|
||||
|
@ -305,7 +320,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_OneResult(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_OneResult(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -324,7 +339,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
* https://github.com/shish/shimmie2/issues/547
|
||||
*/
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_WildOneResult(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_WildOneResult(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -335,7 +350,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_ManyResults(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_ManyResults(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -346,7 +361,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_WildManyResults(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_WildManyResults(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -357,7 +372,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_SubtractValidFromResults(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_SubtractValidFromResults(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -368,7 +383,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_SubtractNotValidFromResults(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_SubtractNotValidFromResults(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -379,7 +394,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_SubtractValidFromDefault(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_SubtractValidFromDefault(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
// negative tag alone, should remove the image with that tag
|
||||
|
@ -391,7 +406,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_SubtractNotValidFromDefault(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_SubtractNotValidFromDefault(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
// negative that doesn't exist, should return all results
|
||||
|
@ -403,7 +418,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_GeneralPath_SubtractMultipleNotValidFromDefault(array $image_ids): void
|
||||
public function testBSQ_GeneralPath_SubtractMultipleNotValidFromDefault(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
// multiple negative tags that don't exist, should return all results
|
||||
|
@ -418,7 +433,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
* Meta Search *
|
||||
* * * * * * * * * * */
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_ImgCond_NoResults(array $image_ids): void
|
||||
public function testBSQ_ImgCond_NoResults(): void
|
||||
{
|
||||
$this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -434,7 +449,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_ImgCond_OneResult(array $image_ids): void
|
||||
public function testBSQ_ImgCond_OneResult(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
$this->assert_BSQ(
|
||||
|
@ -455,7 +470,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_ImgCond_ManyResults(array $image_ids): void
|
||||
public function testBSQ_ImgCond_ManyResults(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
|
||||
|
@ -480,7 +495,7 @@ class SearchTest extends ShimmiePHPUnitTestCase
|
|||
* Mixed *
|
||||
* * * * * * * * * * */
|
||||
#[Depends('testUpload')]
|
||||
public function testBSQ_TagCondWithImgCond(array $image_ids): void
|
||||
public function testBSQ_TagCondWithImgCond(): void
|
||||
{
|
||||
$image_ids = $this->testUpload();
|
||||
// multiple tags, many results
|
||||
|
|
|
@ -44,6 +44,7 @@ class User
|
|||
* One will very rarely construct a user directly, more common
|
||||
* would be to use User::by_id, User::by_session, etc.
|
||||
*
|
||||
* @param array<string|int, mixed> $row
|
||||
* @throws SCoreException
|
||||
*/
|
||||
public function __construct(array $row)
|
||||
|
|
|
@ -23,8 +23,13 @@ class UserClass
|
|||
#[Field]
|
||||
public ?string $name = null;
|
||||
public ?UserClass $parent = null;
|
||||
|
||||
/** @var array<string, bool> */
|
||||
public array $abilities = [];
|
||||
|
||||
/**
|
||||
* @param array<string, bool> $abilities
|
||||
*/
|
||||
public function __construct(string $name, string $parent = null, array $abilities = [])
|
||||
{
|
||||
global $_shm_user_classes;
|
||||
|
@ -39,6 +44,9 @@ class UserClass
|
|||
$_shm_user_classes[$name] = $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
#[Field(type: "[Permission!]!")]
|
||||
public function permissions(): array
|
||||
{
|
||||
|
|
|
@ -285,12 +285,16 @@ function load_balance_url(string $tmpl, string $hash, int $n = 0): string
|
|||
return $tmpl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|array<string, mixed>
|
||||
*/
|
||||
function fetch_url(string $url, string $mfile): ?array
|
||||
{
|
||||
global $config;
|
||||
|
||||
if ($config->get_string(UploadConfig::TRANSLOAD_ENGINE) === "curl" && function_exists("curl_init")) {
|
||||
$ch = curl_init($url);
|
||||
assert($ch !== false);
|
||||
$fp = fopen($mfile, "w");
|
||||
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
@ -397,6 +401,9 @@ function path_to_tags(string $path): array
|
|||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
function get_dir_contents(string $dir): array
|
||||
{
|
||||
assert(!empty($dir));
|
||||
|
@ -442,7 +449,9 @@ function remove_empty_dirs(string $dir): bool
|
|||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
function get_files_recursively(string $dir): array
|
||||
{
|
||||
assert(!empty($dir));
|
||||
|
@ -475,6 +484,8 @@ function get_files_recursively(string $dir): array
|
|||
|
||||
/**
|
||||
* Returns amount of files & total size of dir.
|
||||
*
|
||||
* @return array{"path": string, "total_files": int, "total_mb": string}
|
||||
*/
|
||||
function scan_dir(string $path): array
|
||||
{
|
||||
|
|
|
@ -174,6 +174,7 @@ class AliasEditor extends Extension
|
|||
$csv = "";
|
||||
$aliases = $database->get_pairs("SELECT oldtag, newtag FROM aliases ORDER BY newtag");
|
||||
foreach ($aliases as $old => $new) {
|
||||
assert(is_string($new));
|
||||
$csv .= "\"$old\",\"$new\"\n";
|
||||
}
|
||||
return $csv;
|
||||
|
|
|
@ -174,7 +174,9 @@ class Approval extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string[] $context
|
||||
*/
|
||||
private function no_approval_query(array $context): bool
|
||||
{
|
||||
foreach ($context as $term) {
|
||||
|
@ -185,7 +187,7 @@ class Approval extends Extension
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function approve_image($image_id)
|
||||
public static function approve_image(int $image_id): void
|
||||
{
|
||||
global $database, $user;
|
||||
|
||||
|
@ -195,7 +197,7 @@ class Approval extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
public static function disapprove_image($image_id)
|
||||
public static function disapprove_image(int $image_id): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
|
|
@ -495,43 +495,52 @@ class Artists extends Extension
|
|||
return (int)$database->get_one("SELECT artist_id FROM artist_urls WHERE id = :id", ['id' => $urlID]);
|
||||
}
|
||||
|
||||
private function delete_alias(int $aliasID)
|
||||
private function delete_alias(int $aliasID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("DELETE FROM artist_alias WHERE id = :id", ['id' => $aliasID]);
|
||||
}
|
||||
|
||||
private function delete_url(int $urlID)
|
||||
private function delete_url(int $urlID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("DELETE FROM artist_urls WHERE id = :id", ['id' => $urlID]);
|
||||
}
|
||||
|
||||
private function delete_member(int $memberID)
|
||||
private function delete_member(int $memberID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("DELETE FROM artist_members WHERE id = :id", ['id' => $memberID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_alias_by_id(int $aliasID): array
|
||||
{
|
||||
global $database;
|
||||
return $database->get_row("SELECT * FROM artist_alias WHERE id = :id", ['id' => $aliasID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_url_by_id(int $urlID): array
|
||||
{
|
||||
global $database;
|
||||
return $database->get_row("SELECT * FROM artist_urls WHERE id = :id", ['id' => $urlID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_member_by_id(int $memberID): array
|
||||
{
|
||||
global $database;
|
||||
return $database->get_row("SELECT * FROM artist_members WHERE id = :id", ['id' => $memberID]);
|
||||
}
|
||||
|
||||
private function update_artist()
|
||||
private function update_artist(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
|
@ -629,7 +638,7 @@ class Artists extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function update_alias()
|
||||
private function update_alias(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
|
@ -639,7 +648,7 @@ class Artists extends Extension
|
|||
$this->save_existing_alias($inputs['aliasID'], $inputs['alias'], $user->id);
|
||||
}
|
||||
|
||||
private function save_existing_alias(int $aliasID, string $alias, int $userID)
|
||||
private function save_existing_alias(int $aliasID, string $alias, int $userID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute(
|
||||
|
@ -648,7 +657,7 @@ class Artists extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
private function update_url()
|
||||
private function update_url(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
|
@ -658,7 +667,7 @@ class Artists extends Extension
|
|||
$this->save_existing_url($inputs['urlID'], $inputs['url'], $user->id);
|
||||
}
|
||||
|
||||
private function save_existing_url(int $urlID, string $url, int $userID)
|
||||
private function save_existing_url(int $urlID, string $url, int $userID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute(
|
||||
|
@ -667,7 +676,7 @@ class Artists extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
private function update_member()
|
||||
private function update_member(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
|
@ -677,7 +686,7 @@ class Artists extends Extension
|
|||
$this->save_existing_member($inputs['memberID'], $inputs['name'], $user->id);
|
||||
}
|
||||
|
||||
private function save_existing_member(int $memberID, string $memberName, int $userID)
|
||||
private function save_existing_member(int $memberID, string $memberName, int $userID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute(
|
||||
|
@ -772,6 +781,9 @@ class Artists extends Extension
|
|||
return ($result != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_artist(int $artistID): array
|
||||
{
|
||||
global $database;
|
||||
|
@ -786,6 +798,9 @@ class Artists extends Extension
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_members(int $artistID): array
|
||||
{
|
||||
global $database;
|
||||
|
@ -802,6 +817,9 @@ class Artists extends Extension
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_urls(int $artistID): array
|
||||
{
|
||||
global $database;
|
||||
|
@ -837,7 +855,7 @@ class Artists extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
private function delete_artist(int $artistID)
|
||||
private function delete_artist(int $artistID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute(
|
||||
|
@ -849,7 +867,7 @@ class Artists extends Extension
|
|||
/*
|
||||
* HERE WE GET THE LIST OF ALL ARTIST WITH PAGINATION
|
||||
*/
|
||||
private function get_listing(PageRequestEvent $event)
|
||||
private function get_listing(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $database;
|
||||
|
||||
|
@ -927,7 +945,7 @@ class Artists extends Extension
|
|||
ON a.id = aa.artist_id
|
||||
");
|
||||
|
||||
$totalPages = ceil($count / $artistsPerPage);
|
||||
$totalPages = (int)ceil($count / $artistsPerPage);
|
||||
|
||||
$this->theme->list_artists($listing, $pageNumber + 1, $totalPages);
|
||||
}
|
||||
|
@ -935,7 +953,7 @@ class Artists extends Extension
|
|||
/*
|
||||
* HERE WE ADD AN ALIAS
|
||||
*/
|
||||
private function add_urls()
|
||||
private function add_urls(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
|
@ -952,7 +970,7 @@ class Artists extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function save_new_url(int $artistID, string $url, int $userID)
|
||||
private function save_new_url(int $artistID, string $url, int $userID): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
@ -962,7 +980,7 @@ class Artists extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
private function add_alias()
|
||||
private function add_alias(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
|
@ -979,7 +997,7 @@ class Artists extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function save_new_alias(int $artistID, string $alias, int $userID)
|
||||
private function save_new_alias(int $artistID, string $alias, int $userID): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
@ -989,7 +1007,7 @@ class Artists extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
private function add_members()
|
||||
private function add_members(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
|
@ -1006,7 +1024,7 @@ class Artists extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function save_new_member(int $artistID, string $member, int $userID)
|
||||
private function save_new_member(int $artistID, string $member, int $userID): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
@ -1040,6 +1058,8 @@ class Artists extends Extension
|
|||
|
||||
/**
|
||||
* HERE WE GET THE INFO OF THE ALIAS
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_alias(int $artistID): array
|
||||
{
|
||||
|
|
|
@ -9,6 +9,12 @@ use MicroHTML\HTMLElement;
|
|||
use function MicroHTML\emptyHTML;
|
||||
use function MicroHTML\{INPUT,P};
|
||||
|
||||
/**
|
||||
* @phpstan-type ArtistArtist array{id:int,artist_id:int,user_name:string,name:string,notes:string,type:string,posts:int}
|
||||
* @phpstan-type ArtistAlias array{id:int,alias_id:int,alias_name:string,alias:string}
|
||||
* @phpstan-type ArtistMember array{id:int,name:string}
|
||||
* @phpstan-type ArtistUrl array{id:int,url:string}
|
||||
*/
|
||||
class ArtistsTheme extends Themelet
|
||||
{
|
||||
public function get_author_editor_html(string $author): HTMLElement
|
||||
|
@ -20,7 +26,7 @@ class ArtistsTheme extends Themelet
|
|||
);
|
||||
}
|
||||
|
||||
public function sidebar_options(string $mode, ?int $artistID = null, $is_admin = false): void
|
||||
public function sidebar_options(string $mode, ?int $artistID = null, bool $is_admin = false): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
|
@ -77,7 +83,13 @@ class ArtistsTheme extends Themelet
|
|||
}
|
||||
}
|
||||
|
||||
public function show_artist_editor($artist, $aliases, $members, $urls)
|
||||
/**
|
||||
* @param ArtistArtist $artist
|
||||
* @param ArtistAlias[] $aliases
|
||||
* @param ArtistMember[] $members
|
||||
* @param ArtistUrl[] $urls
|
||||
*/
|
||||
public function show_artist_editor(array $artist, array $aliases, array $members, array $urls): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -137,7 +149,7 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Edit artist", $html, "main", 10));
|
||||
}
|
||||
|
||||
public function new_artist_composer()
|
||||
public function new_artist_composer(): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
|
@ -158,7 +170,10 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Artists", $html, "main", 10));
|
||||
}
|
||||
|
||||
public function list_artists($artists, $pageNumber, $totalPages)
|
||||
/**
|
||||
* @param ArtistArtist[] $artists
|
||||
*/
|
||||
public function list_artists(array $artists, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
global $user, $page;
|
||||
|
||||
|
@ -237,7 +252,7 @@ class ArtistsTheme extends Themelet
|
|||
$this->display_paginator($page, "artist/list", null, $pageNumber, $totalPages);
|
||||
}
|
||||
|
||||
public function show_new_alias_composer($artistID)
|
||||
public function show_new_alias_composer(int $artistID): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -256,7 +271,7 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Artist Aliases", $html, "main", 20));
|
||||
}
|
||||
|
||||
public function show_new_member_composer($artistID)
|
||||
public function show_new_member_composer(int $artistID): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -275,7 +290,7 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Artist members", $html, "main", 30));
|
||||
}
|
||||
|
||||
public function show_new_url_composer($artistID)
|
||||
public function show_new_url_composer(int $artistID): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -294,7 +309,10 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Artist URLs", $html, "main", 40));
|
||||
}
|
||||
|
||||
public function show_alias_editor($alias)
|
||||
/**
|
||||
* @param ArtistAlias $alias
|
||||
*/
|
||||
public function show_alias_editor(array $alias): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -312,7 +330,10 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Edit Alias", $html, "main", 10));
|
||||
}
|
||||
|
||||
public function show_url_editor($url)
|
||||
/**
|
||||
* @param ArtistUrl $url
|
||||
*/
|
||||
public function show_url_editor(array $url): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -330,7 +351,10 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Edit URL", $html, "main", 10));
|
||||
}
|
||||
|
||||
public function show_member_editor($member)
|
||||
/**
|
||||
* @param ArtistMember $member
|
||||
*/
|
||||
public function show_member_editor(array $member): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -348,7 +372,14 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Edit Member", $html, "main", 10));
|
||||
}
|
||||
|
||||
public function show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin)
|
||||
/**
|
||||
* @param ArtistArtist $artist
|
||||
* @param ArtistAlias[] $aliases
|
||||
* @param ArtistMember[] $members
|
||||
* @param ArtistUrl[] $urls
|
||||
* @param Image[] $images
|
||||
*/
|
||||
public function show_artist(array $artist, array $aliases, array $members, array $urls, array $images, bool $userIsLogged, bool $userIsAdmin): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
@ -416,6 +447,9 @@ class ArtistsTheme extends Themelet
|
|||
$page->add_block(new Block("Artist Posts", $artist_images, "main", 20));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArtistAlias[] $aliases
|
||||
*/
|
||||
private function render_aliases(array $aliases, bool $userIsLogged, bool $userIsAdmin): string
|
||||
{
|
||||
$html = "";
|
||||
|
@ -462,6 +496,9 @@ class ArtistsTheme extends Themelet
|
|||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArtistMember[] $members
|
||||
*/
|
||||
private function render_members(array $members, bool $userIsLogged, bool $userIsAdmin): string
|
||||
{
|
||||
$html = "";
|
||||
|
@ -506,6 +543,9 @@ class ArtistsTheme extends Themelet
|
|||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArtistUrl[] $urls
|
||||
*/
|
||||
private function render_urls(array $urls, bool $userIsLogged, bool $userIsAdmin): string
|
||||
{
|
||||
$html = "";
|
||||
|
|
|
@ -186,6 +186,7 @@ class AutoTagger extends Extension
|
|||
$csv = "";
|
||||
$pairs = $database->get_pairs("SELECT tag, additional_tags FROM auto_tag ORDER BY tag");
|
||||
foreach ($pairs as $old => $new) {
|
||||
assert(is_string($new));
|
||||
$csv .= "\"$old\",\"$new\"\n";
|
||||
}
|
||||
return $csv;
|
||||
|
@ -209,7 +210,7 @@ class AutoTagger extends Extension
|
|||
return $i;
|
||||
}
|
||||
|
||||
private function add_auto_tag(string $tag, string $additional_tags)
|
||||
private function add_auto_tag(string $tag, string $additional_tags): void
|
||||
{
|
||||
global $database;
|
||||
$existing_tags = $database->get_one("SELECT additional_tags FROM auto_tag WHERE LOWER(tag)=LOWER(:tag)", ["tag" => $tag]);
|
||||
|
@ -250,7 +251,7 @@ class AutoTagger extends Extension
|
|||
$this->apply_new_auto_tag($tag);
|
||||
}
|
||||
|
||||
private function apply_new_auto_tag(string $tag)
|
||||
private function apply_new_auto_tag(string $tag): void
|
||||
{
|
||||
global $database;
|
||||
$tag_id = $database->get_one("SELECT id FROM tags WHERE LOWER(tag) = LOWER(:tag)", ["tag" => $tag]);
|
||||
|
@ -264,7 +265,7 @@ class AutoTagger extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function remove_auto_tag(string $tag)
|
||||
private function remove_auto_tag(string $tag): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
@ -273,6 +274,7 @@ class AutoTagger extends Extension
|
|||
|
||||
/**
|
||||
* @param string[] $tags_mixed
|
||||
* @return string[]
|
||||
*/
|
||||
private function apply_auto_tags(array $tags_mixed): array
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shimmie2;
|
||||
|
||||
use MicroHTML\HTMLElement;
|
||||
|
||||
class AutoTaggerTheme extends Themelet
|
||||
{
|
||||
/**
|
||||
|
@ -11,7 +13,7 @@ class AutoTaggerTheme extends Themelet
|
|||
*
|
||||
* Note: $can_manage = whether things like "add new alias" should be shown
|
||||
*/
|
||||
public function display_auto_tagtable($table, $paginator): void
|
||||
public function display_auto_tagtable(HTMLElement $table, HTMLElement $paginator): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ class AutoComplete extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, int>
|
||||
*/
|
||||
private function complete(string $search, int $limit): array
|
||||
{
|
||||
global $cache, $database;
|
||||
|
|
|
@ -97,6 +97,9 @@ xanax
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function get_words(): array
|
||||
{
|
||||
global $config;
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Shimmie2;
|
|||
|
||||
class BanWordsTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function check_blocked($image_id, $words)
|
||||
public function check_blocked(int $image_id, string $words): void
|
||||
{
|
||||
global $user;
|
||||
try {
|
||||
|
|
|
@ -101,13 +101,13 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
|||
);
|
||||
}
|
||||
|
||||
private function filter($in): string
|
||||
private function filter(string $in): string
|
||||
{
|
||||
$bb = new BBCode();
|
||||
return $bb->_format($in);
|
||||
}
|
||||
|
||||
private function strip($in): string
|
||||
private function strip(string $in): string
|
||||
{
|
||||
$bb = new BBCode();
|
||||
return $bb->strip($in);
|
||||
|
|
|
@ -16,7 +16,10 @@ use function MicroHTML\OPTION;
|
|||
|
||||
class BlocksTheme extends Themelet
|
||||
{
|
||||
public function display_blocks($blocks): void
|
||||
/**
|
||||
* @param array<array{id:int,title:string,area:string,priority:int,userclass:string,pages:string,content:string}> $blocks
|
||||
*/
|
||||
public function display_blocks(array $blocks): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ class Blotter extends Extension
|
|||
$this->display_blotter();
|
||||
}
|
||||
|
||||
private function display_blotter()
|
||||
private function display_blotter(): void
|
||||
{
|
||||
global $database, $config;
|
||||
$limit = $config->get_int("blotter_recent", 5);
|
||||
|
|
|
@ -4,9 +4,15 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shimmie2;
|
||||
|
||||
/**
|
||||
* @phpstan-type BlotterEntry array{id:int,entry_date:string,entry_text:string,important:bool}
|
||||
*/
|
||||
class BlotterTheme extends Themelet
|
||||
{
|
||||
public function display_editor($entries): void
|
||||
/**
|
||||
* @param BlotterEntry[] $entries
|
||||
*/
|
||||
public function display_editor(array $entries): void
|
||||
{
|
||||
global $page;
|
||||
$html = $this->get_html_for_blotter_editor($entries);
|
||||
|
@ -16,7 +22,10 @@ class BlotterTheme extends Themelet
|
|||
$page->add_block(new Block("Navigation", "<a href='".make_link()."'>Index</a>", "left", 0));
|
||||
}
|
||||
|
||||
public function display_blotter_page($entries): void
|
||||
/**
|
||||
* @param BlotterEntry[] $entries
|
||||
*/
|
||||
public function display_blotter_page(array $entries): void
|
||||
{
|
||||
global $page;
|
||||
$html = $this->get_html_for_blotter_page($entries);
|
||||
|
@ -25,6 +34,9 @@ class BlotterTheme extends Themelet
|
|||
$page->add_block(new Block("Blotter Entries", $html, "main", 10));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlotterEntry[] $entries
|
||||
*/
|
||||
public function display_blotter(array $entries): void
|
||||
{
|
||||
global $page, $config;
|
||||
|
@ -33,6 +45,9 @@ class BlotterTheme extends Themelet
|
|||
$page->add_block(new Block(null, $html, $position, 20));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlotterEntry[] $entries
|
||||
*/
|
||||
private function get_html_for_blotter_editor(array $entries): string
|
||||
{
|
||||
global $user;
|
||||
|
@ -104,6 +119,9 @@ class BlotterTheme extends Themelet
|
|||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlotterEntry[] $entries
|
||||
*/
|
||||
private function get_html_for_blotter_page(array $entries): string
|
||||
{
|
||||
/**
|
||||
|
@ -135,25 +153,27 @@ class BlotterTheme extends Themelet
|
|||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlotterEntry[] $entries
|
||||
*/
|
||||
private function get_html_for_blotter(array $entries): string
|
||||
{
|
||||
global $config;
|
||||
$i_color = $config->get_string("blotter_color", "#FF0000");
|
||||
$position = $config->get_string("blotter_position", "subheading");
|
||||
$entries_list = "";
|
||||
$num_entries = count($entries);
|
||||
for ($i = 0 ; $i < $num_entries ; $i++) {
|
||||
foreach($entries as $entry) {
|
||||
/**
|
||||
* Blotter entries
|
||||
*/
|
||||
// Reset variables:
|
||||
$i_open = "";
|
||||
$i_close = "";
|
||||
//$id = $entries[$i]['id'];
|
||||
$messy_date = $entries[$i]['entry_date'];
|
||||
//$id = $entry['id'];
|
||||
$messy_date = $entry['entry_date'];
|
||||
$clean_date = date("m/d/y", strtotime($messy_date));
|
||||
$entry_text = $entries[$i]['entry_text'];
|
||||
if ($entries[$i]['important'] == 'Y') {
|
||||
$entry_text = $entry['entry_text'];
|
||||
if ($entry['important'] == 'Y') {
|
||||
$i_open = "<span style='color: #$i_color'>";
|
||||
$i_close = "</span>";
|
||||
}
|
||||
|
|
|
@ -13,10 +13,14 @@ class BulkActionException extends SCoreException
|
|||
}
|
||||
class BulkActionBlockBuildingEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var array<array{block:string,access_key:?string,confirmation_message:string,action:string,button_text:string,position:int}>
|
||||
*/
|
||||
public array $actions = [];
|
||||
/** @var string[] */
|
||||
public array $search_terms = [];
|
||||
|
||||
public function add_action(string $action, string $button_text, string $access_key = null, string $confirmation_message = "", string $block = "", int $position = 40)
|
||||
public function add_action(string $action, string $button_text, string $access_key = null, string $confirmation_message = "", string $block = "", int $position = 40): void
|
||||
{
|
||||
if (!empty($access_key)) {
|
||||
assert(strlen($access_key) == 1);
|
||||
|
@ -28,13 +32,13 @@ class BulkActionBlockBuildingEvent extends Event
|
|||
}
|
||||
|
||||
$this->actions[] = [
|
||||
"block" => $block,
|
||||
"access_key" => $access_key,
|
||||
"confirmation_message" => $confirmation_message,
|
||||
"action" => $action,
|
||||
"button_text" => $button_text,
|
||||
"position" => $position
|
||||
];
|
||||
"block" => $block,
|
||||
"access_key" => $access_key,
|
||||
"confirmation_message" => $confirmation_message,
|
||||
"action" => $action,
|
||||
"button_text" => $button_text,
|
||||
"position" => $position
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,29 +198,42 @@ class BulkActions extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $data
|
||||
* @return \Generator<Image>
|
||||
*/
|
||||
private function yield_items(array $data): \Generator
|
||||
{
|
||||
foreach ($data as $id) {
|
||||
if (is_numeric($id)) {
|
||||
$image = Image::by_id($id);
|
||||
if ($image != null) {
|
||||
yield $image;
|
||||
}
|
||||
$image = Image::by_id($id);
|
||||
if ($image != null) {
|
||||
yield $image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Generator<Image>
|
||||
*/
|
||||
private function yield_search_results(string $query): \Generator
|
||||
{
|
||||
$tags = Tag::explode($query);
|
||||
return Search::find_images_iterable(0, null, $tags);
|
||||
}
|
||||
|
||||
private function sort_blocks($a, $b)
|
||||
/**
|
||||
* @param array{position: int} $a
|
||||
* @param array{position: int} $b
|
||||
*/
|
||||
private function sort_blocks(array $a, array $b): int
|
||||
{
|
||||
return $a["position"] - $b["position"];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<Image> $posts
|
||||
* @return array{0: int, 1: int}
|
||||
*/
|
||||
private function delete_posts(iterable $posts): array
|
||||
{
|
||||
global $page;
|
||||
|
@ -240,6 +257,9 @@ class BulkActions extends Extension
|
|||
return [$total, $size];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<Image> $items
|
||||
*/
|
||||
private function tag_items(iterable $items, string $tags, bool $replace): int
|
||||
{
|
||||
$tags = Tag::explode($tags);
|
||||
|
@ -280,6 +300,9 @@ class BulkActions extends Extension
|
|||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<Image> $items
|
||||
*/
|
||||
private function set_source(iterable $items, string $source): int
|
||||
{
|
||||
global $page;
|
||||
|
|
|
@ -6,6 +6,9 @@ namespace Shimmie2;
|
|||
|
||||
class BulkActionsTheme extends Themelet
|
||||
{
|
||||
/**
|
||||
* @param array<array{block:string,access_key:?string,confirmation_message:string,action:string,button_text:string,position:int}> $actions
|
||||
*/
|
||||
public function display_selector(Page $page, array $actions, string $query): void
|
||||
{
|
||||
$body = "<input type='hidden' name='bulk_selected_ids' id='bulk_selected_ids' />
|
||||
|
|
|
@ -50,8 +50,10 @@ class BulkAddCSV extends Extension
|
|||
|
||||
/**
|
||||
* Generate the necessary DataUploadEvent for a given image and tags.
|
||||
*
|
||||
* @param string[] $tags
|
||||
*/
|
||||
private function add_image(string $tmpname, string $filename, array $tags, string $source, string $rating, string $thumbfile)
|
||||
private function add_image(string $tmpname, string $filename, array $tags, string $source, string $rating, string $thumbfile): void
|
||||
{
|
||||
global $database;
|
||||
$database->with_savepoint(function () use ($tmpname, $filename, $tags, $source, $rating, $thumbfile) {
|
||||
|
@ -72,7 +74,7 @@ class BulkAddCSV extends Extension
|
|||
});
|
||||
}
|
||||
|
||||
private function add_csv(string $csvfile)
|
||||
private function add_csv(string $csvfile): void
|
||||
{
|
||||
if (!file_exists($csvfile)) {
|
||||
$this->theme->add_status("Error", "$csvfile not found");
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Shimmie2;
|
|||
|
||||
class BulkAddCSVTheme extends Themelet
|
||||
{
|
||||
/** @var Block[] */
|
||||
private array $messages = [];
|
||||
|
||||
/*
|
||||
|
@ -44,7 +45,7 @@ class BulkAddCSVTheme extends Themelet
|
|||
$page->add_block(new Block("Bulk Add CSV", $html));
|
||||
}
|
||||
|
||||
public function add_status($title, $body)
|
||||
public function add_status(string $title, string $body): void
|
||||
{
|
||||
$this->messages[] = new Block($title, $body);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Shimmie2;
|
|||
class BulkExportEvent extends Event
|
||||
{
|
||||
public Image $image;
|
||||
/** @var array<string,mixed> */
|
||||
public array $fields = [];
|
||||
|
||||
public function __construct(Image $image)
|
||||
|
@ -20,9 +21,13 @@ class BulkExportEvent extends Event
|
|||
class BulkImportEvent extends Event
|
||||
{
|
||||
public Image $image;
|
||||
/** @var array<string,mixed> */
|
||||
public array $fields = [];
|
||||
|
||||
public function __construct(Image $image, $fields)
|
||||
/**
|
||||
* @param array<string,mixed> $fields
|
||||
*/
|
||||
public function __construct(Image $image, array $fields)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->image = $image;
|
||||
|
|
|
@ -155,6 +155,9 @@ class BulkImportExport extends DataHandlerExtension
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
*/
|
||||
private function get_export_data(\ZipArchive $zip): ?array
|
||||
{
|
||||
$info = $zip->getStream(self::EXPORT_INFO_FILE_NAME);
|
||||
|
|
|
@ -63,7 +63,10 @@ class Comment
|
|||
#[Field]
|
||||
public string $posted;
|
||||
|
||||
public function __construct($row)
|
||||
/**
|
||||
* @param array<string,mixed> $row
|
||||
*/
|
||||
public function __construct(array $row)
|
||||
{
|
||||
$this->owner = null;
|
||||
$this->owner_id = (int)$row['user_id'];
|
||||
|
@ -96,6 +99,9 @@ class Comment
|
|||
return $this->owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Comment[]
|
||||
*/
|
||||
#[Field(extends: "Post", name: "comments", type: "[Comment!]!")]
|
||||
public static function get_comments(Image $post): array
|
||||
{
|
||||
|
@ -223,7 +229,7 @@ class CommentList extends Extension
|
|||
$event->add_disallow("comment");
|
||||
}
|
||||
|
||||
private function onPageRequest_add()
|
||||
private function onPageRequest_add(): void
|
||||
{
|
||||
global $user, $page;
|
||||
if (isset($_POST['image_id']) && isset($_POST['comment'])) {
|
||||
|
@ -238,7 +244,7 @@ class CommentList extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function onPageRequest_delete(PageRequestEvent $event)
|
||||
private function onPageRequest_delete(PageRequestEvent $event): void
|
||||
{
|
||||
global $user, $page;
|
||||
if ($user->can(Permissions::DELETE_COMMENT)) {
|
||||
|
@ -254,7 +260,7 @@ class CommentList extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function onPageRequest_bulk_delete()
|
||||
private function onPageRequest_bulk_delete(): void
|
||||
{
|
||||
global $user, $database, $page;
|
||||
if ($user->can(Permissions::DELETE_COMMENT) && !empty($_POST["ip"])) {
|
||||
|
@ -279,7 +285,7 @@ class CommentList extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function onPageRequest_list(PageRequestEvent $event)
|
||||
private function onPageRequest_list(PageRequestEvent $event): void
|
||||
{
|
||||
global $cache, $config, $database, $user;
|
||||
|
||||
|
@ -332,7 +338,7 @@ class CommentList extends Extension
|
|||
$this->theme->display_comment_list($images, $current_page + 1, $total_pages, $user->can(Permissions::CREATE_COMMENT));
|
||||
}
|
||||
|
||||
private function onPageRequest_beta_search(PageRequestEvent $event)
|
||||
private function onPageRequest_beta_search(PageRequestEvent $event): void
|
||||
{
|
||||
$search = $event->get_arg(1);
|
||||
$page_num = $event->try_page_num(2);
|
||||
|
@ -448,6 +454,7 @@ class CommentList extends Extension
|
|||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $args
|
||||
* @return Comment[]
|
||||
*/
|
||||
private static function get_generic_comments(string $query, array $args): array
|
||||
|
@ -603,7 +610,7 @@ class CommentList extends Extension
|
|||
}
|
||||
// do some checks
|
||||
|
||||
private function add_comment_wrapper(int $image_id, User $user, string $comment)
|
||||
private function add_comment_wrapper(int $image_id, User $user, string $comment): void
|
||||
{
|
||||
global $database, $page;
|
||||
|
||||
|
@ -628,7 +635,7 @@ class CommentList extends Extension
|
|||
log_info("comment", "Comment #$cid added to >>$image_id: $snippet");
|
||||
}
|
||||
|
||||
private function comment_checks(int $image_id, User $user, string $comment)
|
||||
private function comment_checks(int $image_id, User $user, string $comment): void
|
||||
{
|
||||
global $config, $page;
|
||||
|
||||
|
|
|
@ -8,10 +8,13 @@ class CommentListTheme extends Themelet
|
|||
{
|
||||
private bool $show_anon_id = false;
|
||||
private int $anon_id = 1;
|
||||
/** @var array<string,int> */
|
||||
private array $anon_map = [];
|
||||
|
||||
/**
|
||||
* Display a page with a list of images, and for each image, the image's comments.
|
||||
*
|
||||
* @param array<array{0: Image, 1: Comment[]}> $images
|
||||
*/
|
||||
public function display_comment_list(array $images, int $page_number, int $total_pages, bool $can_post): void
|
||||
{
|
||||
|
@ -164,6 +167,9 @@ class CommentListTheme extends Themelet
|
|||
$page->add_block(new Block("Comments", $html, "left", 70, "comment-list-user"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Comment[] $comments
|
||||
*/
|
||||
public function display_all_user_comments(array $comments, int $page_number, int $total_pages, User $user): void
|
||||
{
|
||||
global $page;
|
||||
|
|
|
@ -139,7 +139,7 @@ class CronUploader extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function restage_folder(string $folder)
|
||||
private function restage_folder(string $folder): void
|
||||
{
|
||||
global $page;
|
||||
if (empty($folder)) {
|
||||
|
@ -196,7 +196,7 @@ class CronUploader extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function clear_folder($folder)
|
||||
private function clear_folder(string $folder): void
|
||||
{
|
||||
global $page, $user_config;
|
||||
$path = join_path($user_config->get_string(CronUploaderConfig::DIR), $folder);
|
||||
|
@ -414,7 +414,7 @@ class CronUploader extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function move_uploaded(string $path, string $filename, string $output_subdir, bool $corrupt = false)
|
||||
private function move_uploaded(string $path, string $filename, string $output_subdir, bool $corrupt = false): void
|
||||
{
|
||||
global $user_config;
|
||||
|
||||
|
@ -454,6 +454,8 @@ class CronUploader extends Extension
|
|||
|
||||
/**
|
||||
* Generate the necessary DataUploadEvent for a given image and tags.
|
||||
*
|
||||
* @param string[] $tags
|
||||
*/
|
||||
private function add_image(string $tmpname, string $filename, array $tags): DataUploadEvent
|
||||
{
|
||||
|
|
|
@ -17,6 +17,12 @@ use function MicroHTML\emptyHTML;
|
|||
|
||||
class CronUploaderTheme extends Themelet
|
||||
{
|
||||
/**
|
||||
* @param array{path:string,total_files:int,total_mb:string} $queue_dirinfo
|
||||
* @param array{path:string,total_files:int,total_mb:string} $uploaded_dirinfo
|
||||
* @param array{path:string,total_files:int,total_mb:string} $failed_dirinfo
|
||||
* @param array<array{date_sent:string,message:string}>|null $log_entries
|
||||
*/
|
||||
public function display_documentation(
|
||||
bool $running,
|
||||
array $queue_dirinfo,
|
||||
|
@ -25,7 +31,7 @@ class CronUploaderTheme extends Themelet
|
|||
string $cron_cmd,
|
||||
string $cron_url,
|
||||
?array $log_entries
|
||||
) {
|
||||
): void {
|
||||
global $page, $config, $user_config;
|
||||
|
||||
$info_html = "";
|
||||
|
@ -159,6 +165,9 @@ class CronUploaderTheme extends Themelet
|
|||
return (string)$html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $failed_dirs
|
||||
*/
|
||||
public function display_form(array $failed_dirs): void
|
||||
{
|
||||
global $page;
|
||||
|
|
|
@ -38,7 +38,7 @@ class CustomHtmlHeaders extends Extension
|
|||
$this->handle_modified_page_title();
|
||||
}
|
||||
|
||||
private function handle_custom_html_headers()
|
||||
private function handle_custom_html_headers(): void
|
||||
{
|
||||
global $config, $page;
|
||||
|
||||
|
@ -48,7 +48,7 @@ class CustomHtmlHeaders extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function handle_modified_page_title()
|
||||
private function handle_modified_page_title(): void
|
||||
{
|
||||
global $config, $page;
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ namespace Shimmie2;
|
|||
|
||||
class EmoticonListTheme extends Themelet
|
||||
{
|
||||
/**
|
||||
* @param string[] $list
|
||||
*/
|
||||
public function display_emotes(array $list): void
|
||||
{
|
||||
global $page;
|
||||
|
|
|
@ -53,6 +53,8 @@ class ET extends Extension
|
|||
|
||||
/**
|
||||
* Collect the information and return it in a keyed array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_info(): array
|
||||
{
|
||||
|
@ -135,6 +137,9 @@ class ET extends Extension
|
|||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $info
|
||||
*/
|
||||
private function to_yaml(array $info): string
|
||||
{
|
||||
$data = "";
|
||||
|
|
|
@ -13,10 +13,8 @@ class ETTheme extends Themelet
|
|||
{
|
||||
/*
|
||||
* Create a page showing info
|
||||
*
|
||||
* $info = an array of ($name => $value)
|
||||
*/
|
||||
public function display_info_page($yaml): void
|
||||
public function display_info_page(string $yaml): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
@ -26,7 +24,7 @@ class ETTheme extends Themelet
|
|||
$page->add_block(new Block("Information:", $this->build_data_form($yaml)));
|
||||
}
|
||||
|
||||
protected function build_data_form($yaml): \MicroHTML\HTMLElement
|
||||
protected function build_data_form(string $yaml): \MicroHTML\HTMLElement
|
||||
{
|
||||
return FORM(
|
||||
["action" => "https://shimmie.shishnet.org/register.php", "method" => "POST"],
|
||||
|
|
|
@ -116,7 +116,10 @@ class ExtManager extends Extension
|
|||
return $extensions;
|
||||
}
|
||||
|
||||
private function set_things($settings)
|
||||
/**
|
||||
* @param array<string, bool> $settings
|
||||
*/
|
||||
private function set_things(array $settings): void
|
||||
{
|
||||
$core = ExtensionInfo::get_core_extensions();
|
||||
$extras = [];
|
||||
|
@ -133,7 +136,7 @@ class ExtManager extends Extension
|
|||
/**
|
||||
* @param string[] $extras
|
||||
*/
|
||||
private function write_config(array $extras)
|
||||
private function write_config(array $extras): void
|
||||
{
|
||||
file_put_contents(
|
||||
"data/config/extensions.conf.php",
|
||||
|
|
|
@ -238,7 +238,7 @@ class Favorites extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function add_vote(int $image_id, int $user_id, bool $do_set)
|
||||
private function add_vote(int $image_id, int $user_id, bool $do_set): void
|
||||
{
|
||||
global $database;
|
||||
if ($do_set) {
|
||||
|
|
|
@ -22,6 +22,9 @@ class FavoritesTheme extends Themelet
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $username_array
|
||||
*/
|
||||
public function display_people(array $username_array): void
|
||||
{
|
||||
global $page;
|
||||
|
|
|
@ -206,6 +206,9 @@ class Forum extends Extension
|
|||
return (int)ceil($result["count"] / $config->get_int("forumPostsPerPage"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function sanity_check_new_thread(): array
|
||||
{
|
||||
$errors = [];
|
||||
|
@ -226,6 +229,9 @@ class Forum extends Extension
|
|||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function sanity_check_new_post(): array
|
||||
{
|
||||
$errors = [];
|
||||
|
|
|
@ -8,9 +8,16 @@ use MicroHTML\HTMLElement;
|
|||
|
||||
use function MicroHTML\{INPUT, LABEL, SMALL, TEXTAREA, TR, TD, TABLE, TH, TBODY, THEAD, DIV, A, BR, emptyHTML, SUP, rawHTML};
|
||||
|
||||
/**
|
||||
* @phpstan-type Thread array{id:int,title:string,sticky:bool,user_name:string,uptodate:string,response_count:int}
|
||||
* @phpstan-type Post array{id:int,user_name:string,user_class:string,date:string,message:string}
|
||||
*/
|
||||
class ForumTheme extends Themelet
|
||||
{
|
||||
public function display_thread_list(Page $page, $threads, $showAdminOptions, $pageNumber, $totalPages): void
|
||||
/**
|
||||
* @param Thread[] $threads
|
||||
*/
|
||||
public function display_thread_list(Page $page, array $threads, bool $showAdminOptions, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
if (count($threads) == 0) {
|
||||
$html = "There are no threads to show.";
|
||||
|
@ -27,7 +34,7 @@ class ForumTheme extends Themelet
|
|||
|
||||
|
||||
|
||||
public function display_new_thread_composer(Page $page, $threadText = null, $threadTitle = null): void
|
||||
public function display_new_thread_composer(Page $page, string $threadText = null, string $threadTitle = null): void
|
||||
{
|
||||
global $config, $user;
|
||||
$max_characters = $config->get_int('forumMaxCharsPerPost');
|
||||
|
@ -73,9 +80,7 @@ class ForumTheme extends Themelet
|
|||
$page->add_block(new Block($blockTitle, $html, "main", 120));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function display_new_post_composer(Page $page, $threadID): void
|
||||
public function display_new_post_composer(Page $page, int $threadID): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
@ -108,8 +113,10 @@ class ForumTheme extends Themelet
|
|||
}
|
||||
|
||||
|
||||
|
||||
public function display_thread($posts, $showAdminOptions, $threadTitle, $threadID, $pageNumber, $totalPages): void
|
||||
/**
|
||||
* @param array<Post> $posts
|
||||
*/
|
||||
public function display_thread(array $posts, bool $showAdminOptions, string $threadTitle, int $threadID, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
global $config, $page/*, $user*/;
|
||||
|
||||
|
@ -189,13 +196,16 @@ class ForumTheme extends Themelet
|
|||
$page->add_block(new Block($threadTitle, $html, "main", 20));
|
||||
}
|
||||
|
||||
public function add_actions_block(Page $page, $threadID)
|
||||
public function add_actions_block(Page $page, int $threadID): void
|
||||
{
|
||||
$html = A(["href" => make_link("forum/nuke/".$threadID)], "Delete this thread and its posts.");
|
||||
$page->add_block(new Block("Admin Actions", $html, "main", 140));
|
||||
}
|
||||
|
||||
private function make_thread_list($threads, $showAdminOptions): HTMLElement
|
||||
/**
|
||||
* @param Thread[] $threads
|
||||
*/
|
||||
private function make_thread_list(array $threads, bool $showAdminOptions): HTMLElement
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@ class FourOhFour extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function count_main($blocks): int
|
||||
/**
|
||||
* @param Block[] $blocks
|
||||
*/
|
||||
private function count_main(array $blocks): int
|
||||
{
|
||||
$n = 0;
|
||||
foreach ($blocks as $block) {
|
||||
|
|
|
@ -115,6 +115,9 @@ class GraphQL extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{error?:string,results?:array<array{error?:string,image_ids?:int[]}>}
|
||||
*/
|
||||
private static function handle_uploads(): array
|
||||
{
|
||||
global $user;
|
||||
|
@ -135,7 +138,7 @@ class GraphQL extends Extension
|
|||
break;
|
||||
}
|
||||
try {
|
||||
$results[] = self::handle_upload($n, $common_tags, $common_source);
|
||||
$results[] = ["image_ids" => self::handle_upload($n, $common_tags, $common_source)];
|
||||
} catch(\Exception $e) {
|
||||
$results[] = ["error" => $e->getMessage()];
|
||||
}
|
||||
|
@ -143,10 +146,14 @@ class GraphQL extends Extension
|
|||
return ["results" => $results];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
private static function handle_upload(int $n, string $common_tags, string $common_source): array
|
||||
{
|
||||
global $database;
|
||||
if (!empty($_POST["url$n"])) {
|
||||
throw new \Exception("URLs not handled yet");
|
||||
throw new UploadException("URLs not handled yet");
|
||||
} else {
|
||||
$ec = $_FILES["data$n"]["error"];
|
||||
switch($ec) {
|
||||
|
@ -155,9 +162,9 @@ class GraphQL extends Extension
|
|||
$filename = $_FILES["data$n"]["name"];
|
||||
break;
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
return ["error" => "File larger than PHP can handle"];
|
||||
throw new UploadException("File larger than PHP can handle");
|
||||
default:
|
||||
return ["error" => "Mystery error: $ec"];
|
||||
throw new UploadException("Mystery error: $ec");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,13 +173,15 @@ class GraphQL extends Extension
|
|||
if (!empty($_POST["source$n"])) {
|
||||
$source = $_POST["source$n"];
|
||||
}
|
||||
$event = send_event(new DataUploadEvent($tmpname, [
|
||||
'filename' => $filename,
|
||||
'tags' => Tag::explode($tags),
|
||||
'source' => $source,
|
||||
]));
|
||||
$event = $database->with_savepoint(function () use ($tmpname, $filename, $tags, $source) {
|
||||
return send_event(new DataUploadEvent($tmpname, [
|
||||
'filename' => $filename,
|
||||
'tags' => Tag::explode($tags),
|
||||
'source' => $source,
|
||||
]));
|
||||
});
|
||||
|
||||
return ["image_ids" => array_map(fn ($im) => $im->id, $event->images)];
|
||||
return array_map(fn ($im) => $im->id, $event->images);
|
||||
}
|
||||
|
||||
public function onCliGen(CliGenEvent $event): void
|
||||
|
|
|
@ -107,7 +107,10 @@ class MiniSVGParser
|
|||
xml_parser_free($xml_parser);
|
||||
}
|
||||
|
||||
public function startElement($parser, $name, $attrs): void
|
||||
/**
|
||||
* @param array<string, mixed> $attrs
|
||||
*/
|
||||
public function startElement(mixed $parser, string $name, array $attrs): void
|
||||
{
|
||||
if ($name == "SVG" && $this->xml_depth == 0) {
|
||||
$this->width = int_escape($attrs["WIDTH"]);
|
||||
|
@ -116,7 +119,7 @@ class MiniSVGParser
|
|||
$this->xml_depth++;
|
||||
}
|
||||
|
||||
public function endElement($parser, $name): void
|
||||
public function endElement(mixed $parser, string $name): void
|
||||
{
|
||||
$this->xml_depth--;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ class VideoFileHandler extends DataHandlerExtension
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private function get_options(): array
|
||||
{
|
||||
$output = [];
|
||||
|
|
|
@ -6,9 +6,10 @@ namespace Shimmie2;
|
|||
|
||||
class HelpPageListBuildingEvent extends Event
|
||||
{
|
||||
/** @var array<string,string> */
|
||||
public array $pages = [];
|
||||
|
||||
public function add_page(string $key, string $name)
|
||||
public function add_page(string $key, string $name): void
|
||||
{
|
||||
$this->pages[$key] = $name;
|
||||
}
|
||||
|
@ -17,6 +18,7 @@ class HelpPageListBuildingEvent extends Event
|
|||
class HelpPageBuildingEvent extends Event
|
||||
{
|
||||
public string $key;
|
||||
/** @var array<string,array<Block>> */
|
||||
public array $blocks = [];
|
||||
|
||||
public function __construct(string $key)
|
||||
|
@ -25,7 +27,7 @@ class HelpPageBuildingEvent extends Event
|
|||
$this->key = $key;
|
||||
}
|
||||
|
||||
public function add_block(Block $block, int $position = 50)
|
||||
public function add_block(Block $block, int $position = 50): void
|
||||
{
|
||||
if (!array_key_exists("$position", $this->blocks)) {
|
||||
$this->blocks["$position"] = [];
|
||||
|
|
|
@ -6,6 +6,9 @@ namespace Shimmie2;
|
|||
|
||||
class HelpPagesTheme extends Themelet
|
||||
{
|
||||
/**
|
||||
* @param array<string,string> $pages
|
||||
*/
|
||||
public function display_list_page(array $pages): void
|
||||
{
|
||||
global $page;
|
||||
|
|
|
@ -29,7 +29,7 @@ EOD
|
|||
);
|
||||
}
|
||||
|
||||
public function build_body(string $sitename, string $main_links, string $main_text, string $contact_link, $num_comma, string $counter_text): string
|
||||
public function build_body(string $sitename, string $main_links, string $main_text, string $contact_link, string $num_comma, string $counter_text): string
|
||||
{
|
||||
$main_links_html = empty($main_links) ? "" : "<div class='space' id='links'>$main_links</div>";
|
||||
$message_html = empty($main_text) ? "" : "<div class='space' id='message'>$main_text</div>";
|
||||
|
|
|
@ -215,7 +215,7 @@ class ImageIO extends Extension
|
|||
$event->replace("\\n", "\n");
|
||||
}
|
||||
|
||||
private function send_file(int $image_id, string $type)
|
||||
private function send_file(int $image_id, string $type): void
|
||||
{
|
||||
global $config, $page;
|
||||
|
||||
|
|
|
@ -4,25 +4,27 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shimmie2;
|
||||
|
||||
use function MicroHTML\INPUT;
|
||||
use MicroHTML\HTMLElement;
|
||||
|
||||
use function MicroHTML\{INPUT,emptyHTML};
|
||||
|
||||
class ImageBanTheme extends Themelet
|
||||
{
|
||||
/*
|
||||
* Show all the bans
|
||||
*/
|
||||
public function display_bans(Page $page, $table, $paginator): void
|
||||
public function display_bans(Page $page, HTMLElement $table, HTMLElement $paginator): void
|
||||
{
|
||||
$page->set_title("Post Bans");
|
||||
$page->set_heading("Post Bans");
|
||||
$page->add_block(new NavBlock());
|
||||
$page->add_block(new Block("Edit Post Bans", $table . $paginator));
|
||||
$page->add_block(new Block("Edit Post Bans", emptyHTML($table, $paginator)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a link to delete an image
|
||||
*/
|
||||
public function get_buttons_html(Image $image): \MicroHTML\HTMLElement
|
||||
public function get_buttons_html(Image $image): HTMLElement
|
||||
{
|
||||
return SHM_SIMPLE_FORM(
|
||||
"image_hash_ban/add",
|
||||
|
|
|
@ -9,7 +9,7 @@ class ImageViewCounterTheme extends Themelet
|
|||
/**
|
||||
* @param Image[] $images
|
||||
*/
|
||||
public function view_popular(array $images)
|
||||
public function view_popular(array $images): void
|
||||
{
|
||||
global $page, $config;
|
||||
$pop_images = "";
|
||||
|
|
|
@ -21,6 +21,9 @@ class SearchTermParseEvent extends Event
|
|||
public array $tag_conditions = [];
|
||||
public ?string $order = null;
|
||||
|
||||
/**
|
||||
* @param string[] $context
|
||||
*/
|
||||
public function __construct(int $id, string $term = null, array $context = [])
|
||||
{
|
||||
parent::__construct();
|
||||
|
@ -41,17 +44,17 @@ class SearchTermParseEvent extends Event
|
|||
$this->context = $context;
|
||||
}
|
||||
|
||||
public function add_querylet(Querylet $q)
|
||||
public function add_querylet(Querylet $q): void
|
||||
{
|
||||
$this->add_img_condition(new ImgCondition($q, $this->positive));
|
||||
}
|
||||
|
||||
public function add_img_condition(ImgCondition $c)
|
||||
public function add_img_condition(ImgCondition $c): void
|
||||
{
|
||||
$this->img_conditions[] = $c;
|
||||
}
|
||||
|
||||
public function add_tag_condition(TagCondition $c)
|
||||
public function add_tag_condition(TagCondition $c): void
|
||||
{
|
||||
$this->tag_conditions[] = $c;
|
||||
}
|
||||
|
@ -63,7 +66,9 @@ class SearchTermParseException extends SCoreException
|
|||
|
||||
class PostListBuildingEvent extends Event
|
||||
{
|
||||
/** @var string[] */
|
||||
public array $search_terms = [];
|
||||
/** @var array<int,string> */
|
||||
public array $parts = [];
|
||||
|
||||
/**
|
||||
|
@ -75,7 +80,7 @@ class PostListBuildingEvent extends Event
|
|||
$this->search_terms = $search;
|
||||
}
|
||||
|
||||
public function add_control(string $html, int $position = 50)
|
||||
public function add_control(string $html, int $position = 50): void
|
||||
{
|
||||
while (isset($this->parts[$position])) {
|
||||
$position++;
|
||||
|
|
|
@ -13,9 +13,13 @@ class IndexTheme extends Themelet
|
|||
{
|
||||
protected int $page_number;
|
||||
protected int $total_pages;
|
||||
/** @var string[] */
|
||||
protected array $search_terms;
|
||||
|
||||
public function set_page(int $page_number, int $total_pages, array $search_terms)
|
||||
/**
|
||||
* @param string[] $search_terms
|
||||
*/
|
||||
public function set_page(int $page_number, int $total_pages, array $search_terms): void
|
||||
{
|
||||
$this->page_number = $page_number;
|
||||
$this->total_pages = $total_pages;
|
||||
|
@ -109,7 +113,7 @@ and of course start organising your images :-)
|
|||
return $table;
|
||||
}
|
||||
|
||||
protected function display_shortwiki(Page $page)
|
||||
protected function display_shortwiki(Page $page): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
@ -141,7 +145,7 @@ and of course start organising your images :-)
|
|||
/**
|
||||
* @param Image[] $images
|
||||
*/
|
||||
protected function display_page_header(Page $page, array $images)
|
||||
protected function display_page_header(Page $page, array $images): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
@ -167,7 +171,7 @@ and of course start organising your images :-)
|
|||
/**
|
||||
* @param Image[] $images
|
||||
*/
|
||||
protected function display_page_images(Page $page, array $images)
|
||||
protected function display_page_images(Page $page, array $images): void
|
||||
{
|
||||
if (count($this->search_terms) > 0) {
|
||||
if ($this->page_number > 3) {
|
||||
|
|
|
@ -130,7 +130,7 @@ class IPBan extends Extension
|
|||
|
||||
// Check if our current IP is in either of the ban lists
|
||||
$active_ban_id = (
|
||||
$this->find_active_ban($ips, get_real_ip(), $networks)
|
||||
$this->find_active_ban(get_real_ip(), $ips, $networks)
|
||||
);
|
||||
|
||||
// If an active ban is found, act on it
|
||||
|
@ -355,11 +355,12 @@ class IPBan extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
public function find_active_ban($ips, $remote, $networks)
|
||||
/**
|
||||
* @param array<string,int> $ips
|
||||
* @param array<string,int> $networks
|
||||
*/
|
||||
public function find_active_ban(string $remote, array $ips, array $networks): ?int
|
||||
{
|
||||
if (!$remote) {
|
||||
return null;
|
||||
}
|
||||
$active_ban_id = null;
|
||||
if (isset($ips[$remote])) {
|
||||
$active_ban_id = $ips[$remote];
|
||||
|
|
|
@ -4,9 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shimmie2;
|
||||
|
||||
use MicroHTML\HTMLElement;
|
||||
|
||||
use function MicroHTML\emptyHTML;
|
||||
|
||||
class IPBanTheme extends Themelet
|
||||
{
|
||||
public function display_bans(Page $page, $table, $paginator): void
|
||||
public function display_bans(Page $page, HTMLElement $table, HTMLElement $paginator): void
|
||||
{
|
||||
$html = "
|
||||
<a href='".make_link("ip_ban/list", "r__size=1000000")."'>Show All Active</a> /
|
||||
|
|
|
@ -27,6 +27,9 @@ class LinkImage extends Extension
|
|||
$config->set_default_string("ext_link-img_text-link_format", '$title - $id ($ext $size $filesize)');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{thumb_src: string, image_src: string, post_link: string, text_link: string}
|
||||
*/
|
||||
private function data(Image $image): array
|
||||
{
|
||||
global $config;
|
||||
|
@ -38,6 +41,7 @@ class LinkImage extends Extension
|
|||
'thumb_src' => make_http($image->get_thumb_link()),
|
||||
'image_src' => make_http($image->get_image_link()),
|
||||
'post_link' => make_http(make_link("post/view/{$image->id}")),
|
||||
'text_link' => $text_link];
|
||||
'text_link' => $text_link
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,16 @@ namespace Shimmie2;
|
|||
|
||||
class LinkImageTheme extends Themelet
|
||||
{
|
||||
public function links_block(Page $page, $data)
|
||||
/**
|
||||
* @param array{thumb_src:string,image_src:string,post_link:string,text_link:string} $data
|
||||
*/
|
||||
public function links_block(Page $page, array $data): void
|
||||
{
|
||||
$thumb_src = $data['thumb_src'];
|
||||
$image_src = $data['image_src'];
|
||||
$post_link = $data['post_link'];
|
||||
$text_link = $data['text_link'];
|
||||
|
||||
|
||||
$page->add_block(new Block(
|
||||
"Link to Post",
|
||||
"
|
||||
|
@ -93,7 +95,7 @@ class LinkImageTheme extends Themelet
|
|||
return $text;
|
||||
}
|
||||
|
||||
protected function link_code(string $label, string $content, $id = null): string
|
||||
protected function link_code(string $label, string $content, string $id): string
|
||||
{
|
||||
return "
|
||||
<tr>
|
||||
|
|
|
@ -26,6 +26,9 @@ class LinkScan extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
private function scan(string $text): array
|
||||
{
|
||||
$ids = [];
|
||||
|
|
|
@ -48,7 +48,7 @@ class LiveFeed extends Extension
|
|||
return 99;
|
||||
}
|
||||
|
||||
private function msg(string $data)
|
||||
private function msg(string $data): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class LogConsole extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function log(LogEvent $event)
|
||||
private function log(LogEvent $event): void
|
||||
{
|
||||
global $config, $user;
|
||||
// TODO: colour based on event->priority
|
||||
|
|
|
@ -42,7 +42,7 @@ class ShortDateTimeColumn extends DateTimeColumn
|
|||
|
||||
class ActorColumn extends Column
|
||||
{
|
||||
public function __construct($name, $title)
|
||||
public function __construct(string $name, string $title)
|
||||
{
|
||||
parent::__construct($name, $title);
|
||||
$this->sortable = false;
|
||||
|
@ -78,6 +78,9 @@ class ActorColumn extends Column
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: string, 1: string}
|
||||
*/
|
||||
public function modify_input_for_read(string|array $input): array
|
||||
{
|
||||
list($un, $ip) = $input;
|
||||
|
@ -90,7 +93,10 @@ class ActorColumn extends Column
|
|||
return [$un, $ip];
|
||||
}
|
||||
|
||||
public function display($row): HTMLElement
|
||||
/**
|
||||
* @param array{username: string, address: string} $row
|
||||
*/
|
||||
public function display(array $row): HTMLElement
|
||||
{
|
||||
$ret = emptyHTML();
|
||||
if ($row['username'] != "Anonymous") {
|
||||
|
@ -189,7 +195,7 @@ class MessageColumn extends Column
|
|||
return SPAN(["style" => "color: $c"], rawHTML($this->scan_entities($row[$this->name])));
|
||||
}
|
||||
|
||||
protected function scan_entities(string $line)
|
||||
protected function scan_entities(string $line): string
|
||||
{
|
||||
$line = preg_replace_callback("/Image #(\d+)/s", [$this, "link_image"], $line);
|
||||
$line = preg_replace_callback("/Post #(\d+)/s", [$this, "link_image"], $line);
|
||||
|
@ -197,7 +203,10 @@ class MessageColumn extends Column
|
|||
return $line;
|
||||
}
|
||||
|
||||
protected function link_image($id)
|
||||
/**
|
||||
* @param array{1: string} $id
|
||||
*/
|
||||
protected function link_image(array $id): string
|
||||
{
|
||||
$iid = int_escape($id[1]);
|
||||
return "<a href='".make_link("post/view/$iid")."'>>>$iid</a>";
|
||||
|
|
|
@ -4,14 +4,18 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shimmie2;
|
||||
|
||||
use MicroHTML\HTMLElement;
|
||||
|
||||
use function MicroHTML\emptyHTML;
|
||||
|
||||
class LogDatabaseTheme extends Themelet
|
||||
{
|
||||
public function display_events($table, $paginator): void
|
||||
public function display_events(HTMLElement $table, HTMLElement $paginator): void
|
||||
{
|
||||
global $page;
|
||||
$page->set_title("Event Log");
|
||||
$page->set_heading("Event Log");
|
||||
$page->add_block(new NavBlock());
|
||||
$page->add_block(new Block("Events", $table . $paginator));
|
||||
$page->add_block(new Block("Events", emptyHTML($table, $paginator)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,10 @@ class LogLogstash extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function send_data($data)
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
private function send_data(array $data): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ class LogNet extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function msg($data)
|
||||
private function msg(string $data): void
|
||||
{
|
||||
global $config;
|
||||
$host = $config->get_string("log_net_host");
|
||||
|
|
|
@ -298,7 +298,7 @@ class Media extends Extension
|
|||
* The factor of 2.5 is simply a rough guideline.
|
||||
* https://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize
|
||||
*
|
||||
* @param array $info The output of getimagesize() for the source file in question.
|
||||
* @param array{0:int,1:int,2:int,bits?:int,channels?:int} $info The output of getimagesize() for the source file in question.
|
||||
* @return int The number of bytes an image resize operation is estimated to use.
|
||||
*/
|
||||
public static function calc_memory_use(array $info): int
|
||||
|
@ -368,8 +368,10 @@ class Media extends Extension
|
|||
return $ok;
|
||||
}
|
||||
|
||||
|
||||
public static function get_ffprobe_data($filename): array
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function get_ffprobe_data(string $filename): array
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
@ -410,7 +412,7 @@ class Media extends Extension
|
|||
return $ext;
|
||||
}
|
||||
|
||||
// private static function image_save_imagick(Imagick $image, string $path, string $format, int $output_quality = 80, bool $minimize)
|
||||
// private static function image_save_imagick(Imagick $image, string $path, string $format, int $output_quality = 80, bool $minimize): void
|
||||
// {
|
||||
// switch ($format) {
|
||||
// case FileExtension::PNG:
|
||||
|
@ -638,7 +640,7 @@ class Media extends Extension
|
|||
* Performs a resize operation on an image file using GD.
|
||||
*
|
||||
* @param string $image_filename The source file to be resized.
|
||||
* @param array $info The output of getimagesize() for the source file.
|
||||
* @param array{0:int,1:int,2:int} $info The output of getimagesize() for the source file.
|
||||
* @param int $new_width
|
||||
* @param int $new_height
|
||||
* @param string $output_filename
|
||||
|
@ -658,7 +660,7 @@ class Media extends Extension
|
|||
string $resize_type = self::RESIZE_TYPE_FIT,
|
||||
int $output_quality = 80,
|
||||
bool $allow_upscale = true
|
||||
) {
|
||||
): void {
|
||||
$width = $info[0];
|
||||
$height = $info[1];
|
||||
|
||||
|
@ -785,9 +787,6 @@ class Media extends Extension
|
|||
}
|
||||
|
||||
$background_color = Media::hex_color_allocate($new_image, $alpha_color);
|
||||
if ($background_color === false) {
|
||||
throw new ImageTranscodeException("Could not allocate background color");
|
||||
}
|
||||
if (imagefilledrectangle($new_image, 0, 0, $width, $height, $background_color) === false) {
|
||||
throw new ImageTranscodeException("Could not fill background color");
|
||||
}
|
||||
|
@ -839,7 +838,7 @@ class Media extends Extension
|
|||
* Determines the dimensions of a video file using ffmpeg.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return array [width, height]
|
||||
* @return array{0: int, 1: int}
|
||||
*/
|
||||
public static function video_size(string $filename): array
|
||||
{
|
||||
|
@ -939,12 +938,14 @@ class Media extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
public static function hex_color_allocate($im, $hex)
|
||||
public static function hex_color_allocate(mixed $im, string $hex): int
|
||||
{
|
||||
$hex = ltrim($hex, '#');
|
||||
$a = hexdec(substr($hex, 0, 2));
|
||||
$b = hexdec(substr($hex, 2, 2));
|
||||
$c = hexdec(substr($hex, 4, 2));
|
||||
return imagecolorallocate($im, $a, $b, $c);
|
||||
$col = imagecolorallocate($im, $a, $b, $c);
|
||||
assert($col !== false);
|
||||
return $col;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,8 @@ class FileExtension
|
|||
|
||||
/**
|
||||
* Returns all the file extension associated with the specified mimetype.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_all_for_mime(string $mime): array
|
||||
{
|
||||
|
|
|
@ -235,6 +235,9 @@ class MimeMap
|
|||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* @return array{name: string, ext: string[], mime: string[]}
|
||||
*/
|
||||
public static function get_for_extension(string $ext): ?array
|
||||
{
|
||||
$ext = strtolower($ext);
|
||||
|
@ -247,6 +250,9 @@ class MimeMap
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{name: string, ext: string[], mime: string[]}
|
||||
*/
|
||||
public static function get_for_mime(string $mime): ?array
|
||||
{
|
||||
$mime = strtolower(MimeType::remove_parameters($mime));
|
||||
|
|
|
@ -100,6 +100,9 @@ class MimeType
|
|||
return $mime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $mime_array
|
||||
*/
|
||||
public static function matches_array(string $mime, array $mime_array, bool $exact = false): bool
|
||||
{
|
||||
// If there's an exact match, find it and that's it
|
||||
|
@ -151,6 +154,9 @@ class MimeType
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array<int|null> $comparison
|
||||
*/
|
||||
private static function compare_file_bytes(string $file_name, array $comparison): bool
|
||||
{
|
||||
$size = filesize($file_name);
|
||||
|
|
|
@ -65,7 +65,7 @@ class NotATag extends Extension
|
|||
/**
|
||||
* @param string[] $tags_mixed
|
||||
*/
|
||||
private function scan(array $tags_mixed)
|
||||
private function scan(array $tags_mixed): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
@ -86,6 +86,7 @@ class NotATag extends Extension
|
|||
|
||||
/**
|
||||
* @param string[] $tags
|
||||
* @return string[]
|
||||
*/
|
||||
private function strip(array $tags): array
|
||||
{
|
||||
|
|
|
@ -4,13 +4,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace Shimmie2;
|
||||
|
||||
use MicroHTML\HTMLElement;
|
||||
|
||||
use function MicroHTML\emptyHTML;
|
||||
|
||||
class NotATagTheme extends Themelet
|
||||
{
|
||||
public function display_untags(Page $page, $table, $paginator): void
|
||||
public function display_untags(Page $page, HTMLElement $table, HTMLElement $paginator): void
|
||||
{
|
||||
$page->set_title("UnTags");
|
||||
$page->set_heading("UnTags");
|
||||
$page->add_block(new NavBlock());
|
||||
$page->add_block(new Block("Edit UnTags", $table . $paginator));
|
||||
$page->add_block(new Block("Edit UnTags", emptyHTML($table, $paginator)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,6 +233,8 @@ class Notes extends Extension
|
|||
|
||||
/**
|
||||
* HERE WE GET ALL NOTES FOR DISPLAYED IMAGE.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_notes(int $imageID): array
|
||||
{
|
||||
|
@ -293,7 +295,7 @@ class Notes extends Extension
|
|||
return $noteID;
|
||||
}
|
||||
|
||||
private function add_note_request()
|
||||
private function add_note_request(): void
|
||||
{
|
||||
global $database, $user;
|
||||
|
||||
|
@ -312,7 +314,7 @@ class Notes extends Extension
|
|||
log_info("notes", "Note requested {$resultID} by {$user->name}");
|
||||
}
|
||||
|
||||
private function update_note()
|
||||
private function update_note(): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
@ -331,7 +333,7 @@ class Notes extends Extension
|
|||
$this->add_history(1, $note['note_id'], $note['image_id'], $note['x1'], $note['y1'], $note['height'], $note['width'], $note['note']);
|
||||
}
|
||||
|
||||
private function delete_note()
|
||||
private function delete_note(): void
|
||||
{
|
||||
global $user, $database;
|
||||
|
||||
|
@ -344,7 +346,7 @@ class Notes extends Extension
|
|||
log_info("notes", "Note deleted {$note["note_id"]} by {$user->name}");
|
||||
}
|
||||
|
||||
private function nuke_notes()
|
||||
private function nuke_notes(): void
|
||||
{
|
||||
global $database, $user;
|
||||
$image_id = int_escape($_POST["image_id"]);
|
||||
|
@ -352,7 +354,7 @@ class Notes extends Extension
|
|||
log_info("notes", "Notes deleted from {$image_id} by {$user->name}");
|
||||
}
|
||||
|
||||
private function nuke_requests()
|
||||
private function nuke_requests(): void
|
||||
{
|
||||
global $database, $user;
|
||||
$image_id = int_escape($_POST["image_id"]);
|
||||
|
@ -362,7 +364,7 @@ class Notes extends Extension
|
|||
log_info("notes", "Requests deleted from {$image_id} by {$user->name}");
|
||||
}
|
||||
|
||||
private function get_notes_list(PageRequestEvent $event)
|
||||
private function get_notes_list(PageRequestEvent $event): void
|
||||
{
|
||||
global $database, $config;
|
||||
|
||||
|
@ -380,7 +382,7 @@ class Notes extends Extension
|
|||
['enable' => 1, 'offset' => $pageNumber * $notesPerPage, 'limit' => $notesPerPage]
|
||||
);
|
||||
|
||||
$totalPages = ceil($database->get_one("SELECT COUNT(DISTINCT image_id) FROM notes") / $notesPerPage);
|
||||
$totalPages = (int)ceil($database->get_one("SELECT COUNT(DISTINCT image_id) FROM notes") / $notesPerPage);
|
||||
|
||||
$images = [];
|
||||
while ($row = $result->fetch()) {
|
||||
|
@ -390,7 +392,7 @@ class Notes extends Extension
|
|||
$this->theme->display_note_list($images, $pageNumber + 1, $totalPages);
|
||||
}
|
||||
|
||||
private function get_notes_requests(PageRequestEvent $event)
|
||||
private function get_notes_requests(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $database;
|
||||
|
||||
|
@ -398,10 +400,8 @@ class Notes extends Extension
|
|||
|
||||
$requestsPerPage = $config->get_int('notesRequestsPerPage');
|
||||
|
||||
|
||||
//$result = $database->get_all("SELECT * FROM pool_images WHERE pool_id=:pool_id", ['pool_id'=>$poolID]);
|
||||
|
||||
|
||||
$result = $database->execute(
|
||||
"
|
||||
SELECT DISTINCT image_id
|
||||
|
@ -410,7 +410,7 @@ class Notes extends Extension
|
|||
["offset" => $pageNumber * $requestsPerPage, "limit" => $requestsPerPage]
|
||||
);
|
||||
|
||||
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_request") / $requestsPerPage);
|
||||
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_request") / $requestsPerPage);
|
||||
|
||||
$images = [];
|
||||
while ($row = $result->fetch()) {
|
||||
|
@ -420,7 +420,7 @@ class Notes extends Extension
|
|||
$this->theme->display_note_requests($images, $pageNumber + 1, $totalPages);
|
||||
}
|
||||
|
||||
private function add_history($noteEnable, $noteID, $imageID, $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText)
|
||||
private function add_history(int $noteEnable, int $noteID, int $imageID, int $noteX1, int $noteY1, int $noteHeight, int $noteWidth, string $noteText): void
|
||||
{
|
||||
global $user, $database;
|
||||
|
||||
|
@ -437,7 +437,7 @@ class Notes extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
private function get_histories(PageRequestEvent $event)
|
||||
private function get_histories(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $database;
|
||||
|
||||
|
@ -455,12 +455,12 @@ class Notes extends Extension
|
|||
['offset' => $pageNumber * $historiesPerPage, 'limit' => $historiesPerPage]
|
||||
);
|
||||
|
||||
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_histories") / $historiesPerPage);
|
||||
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_histories") / $historiesPerPage);
|
||||
|
||||
$this->theme->display_histories($histories, $pageNumber + 1, $totalPages);
|
||||
}
|
||||
|
||||
private function get_history(PageRequestEvent $event)
|
||||
private function get_history(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $database;
|
||||
|
||||
|
@ -479,7 +479,7 @@ class Notes extends Extension
|
|||
['note_id' => $noteID, 'offset' => $pageNumber * $historiesPerPage, 'limit' => $historiesPerPage]
|
||||
);
|
||||
|
||||
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = :note_id", ['note_id' => $noteID]) / $historiesPerPage);
|
||||
$totalPages = (int)ceil($database->get_one("SELECT COUNT(*) FROM note_histories WHERE note_id = :note_id", ['note_id' => $noteID]) / $historiesPerPage);
|
||||
|
||||
$this->theme->display_history($histories, $pageNumber + 1, $totalPages);
|
||||
}
|
||||
|
@ -487,7 +487,7 @@ class Notes extends Extension
|
|||
/**
|
||||
* HERE GO BACK IN HISTORY AND SET THE OLD NOTE. IF WAS REMOVED WE RE-ADD IT.
|
||||
*/
|
||||
private function revert_history(int $noteID, int $reviewID)
|
||||
private function revert_history(int $noteID, int $reviewID): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
|
|
@ -8,6 +8,10 @@ use MicroHTML\HTMLElement;
|
|||
|
||||
use function MicroHTML\INPUT;
|
||||
|
||||
/**
|
||||
* @phpstan-type NoteHistory array{image_id:int,note_id:int,review_id:int,user_name:string,note:string,date:string}
|
||||
* @phpstan-type Note array{id:int,x1:int,y1:int,height:int,width:int,note:string}
|
||||
*/
|
||||
class NotesTheme extends Themelet
|
||||
{
|
||||
public function note_button(int $image_id): HTMLElement
|
||||
|
@ -52,6 +56,9 @@ class NotesTheme extends Themelet
|
|||
}
|
||||
|
||||
// check action POST on form
|
||||
/**
|
||||
* @param Note[] $recovered_notes
|
||||
*/
|
||||
public function display_note_system(Page $page, int $image_id, array $recovered_notes, bool $adminOptions): void
|
||||
{
|
||||
$to_json = [];
|
||||
|
@ -73,8 +80,10 @@ class NotesTheme extends Themelet
|
|||
</script>");
|
||||
}
|
||||
|
||||
|
||||
public function display_note_list($images, $pageNumber, $totalPages): void
|
||||
/**
|
||||
* @param array<array{0:Image}> $images
|
||||
*/
|
||||
public function display_note_list(array $images, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
global $page;
|
||||
$pool_images = '';
|
||||
|
@ -94,7 +103,10 @@ class NotesTheme extends Themelet
|
|||
$page->add_block(new Block("Notes", $pool_images, "main", 20));
|
||||
}
|
||||
|
||||
public function display_note_requests($images, $pageNumber, $totalPages): void
|
||||
/**
|
||||
* @param array<array{0:Image}> $images
|
||||
*/
|
||||
public function display_note_requests(array $images, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
@ -115,6 +127,9 @@ class NotesTheme extends Themelet
|
|||
$page->add_block(new Block("Note Requests", $pool_images, "main", 20));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NoteHistory[] $histories
|
||||
*/
|
||||
private function get_history(array $histories): string
|
||||
{
|
||||
global $user;
|
||||
|
@ -157,7 +172,10 @@ class NotesTheme extends Themelet
|
|||
return $html;
|
||||
}
|
||||
|
||||
public function display_histories($histories, $pageNumber, $totalPages): void
|
||||
/**
|
||||
* @param NoteHistory[] $histories
|
||||
*/
|
||||
public function display_histories(array $histories, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
@ -170,7 +188,10 @@ class NotesTheme extends Themelet
|
|||
$this->display_paginator($page, "note/updated", null, $pageNumber, $totalPages);
|
||||
}
|
||||
|
||||
public function display_history($histories, $pageNumber, $totalPages): void
|
||||
/**
|
||||
* @param NoteHistory[] $histories
|
||||
*/
|
||||
public function display_history(array $histories, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
|
|
@ -33,8 +33,8 @@ class NumericScoreVote
|
|||
public static function score(Image $post): int
|
||||
{
|
||||
global $database;
|
||||
if ($post->score ?? null) {
|
||||
return $post->score;
|
||||
if ($post['score'] ?? null) {
|
||||
return $post['score'];
|
||||
}
|
||||
return $database->get_one(
|
||||
"SELECT sum(score) FROM numeric_score_votes WHERE image_id=:image_id",
|
||||
|
@ -42,6 +42,9 @@ class NumericScoreVote
|
|||
) ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NumericScoreVote[]
|
||||
*/
|
||||
#[Field(extends: "Post", type: "[NumericScoreVote!]!")]
|
||||
public static function votes(Image $post): array
|
||||
{
|
||||
|
@ -253,7 +256,7 @@ class NumericScore extends Extension
|
|||
$this->delete_votes_by($event->id);
|
||||
}
|
||||
|
||||
public function delete_votes_by(int $user_id)
|
||||
public function delete_votes_by(int $user_id): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
@ -405,7 +408,7 @@ class NumericScore extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function add_vote(int $image_id, int $user_id, int $score)
|
||||
private function add_vote(int $image_id, int $user_id, int $score): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute(
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Shimmie2;
|
|||
|
||||
class NumericScoreTheme extends Themelet
|
||||
{
|
||||
public function get_voter(Image $image)
|
||||
public function get_voter(Image $image): void
|
||||
{
|
||||
global $user, $page;
|
||||
$i_image_id = $image->id;
|
||||
|
@ -55,7 +55,7 @@ class NumericScoreTheme extends Themelet
|
|||
$page->add_block(new Block("Post Score", $html, "left", 20));
|
||||
}
|
||||
|
||||
public function get_nuller(User $duser)
|
||||
public function get_nuller(User $duser): void
|
||||
{
|
||||
global $user, $page;
|
||||
$html = "
|
||||
|
@ -68,7 +68,11 @@ class NumericScoreTheme extends Themelet
|
|||
$page->add_block(new Block("Votes", $html, "main", 80));
|
||||
}
|
||||
|
||||
public function view_popular($images, $dte)
|
||||
/**
|
||||
* @param Image[] $images
|
||||
* @param string[] $dte
|
||||
*/
|
||||
public function view_popular(array $images, array $dte): void
|
||||
{
|
||||
global $page, $config;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ class _SafeOuroborosImage
|
|||
* Post Meta
|
||||
*/
|
||||
public ?int $change = null;
|
||||
/** @var array{n:int,s:int,json_class:string} */
|
||||
public ?array $created_at = null;
|
||||
public ?int $id = null;
|
||||
public ?int $parent_id = null;
|
||||
|
@ -103,7 +104,8 @@ class _SafeOuroborosImage
|
|||
|
||||
class OuroborosPost extends _SafeOuroborosImage
|
||||
{
|
||||
public array $file = [];
|
||||
/** @var array{tmp_name:string,name:string} */
|
||||
public ?array $file = null;
|
||||
public bool $is_rating_locked = false;
|
||||
public bool $is_note_locked = false;
|
||||
|
||||
|
@ -111,6 +113,8 @@ class OuroborosPost extends _SafeOuroborosImage
|
|||
* Initialize an OuroborosPost for creation
|
||||
* Mainly just acts as a wrapper and validation layer
|
||||
* @noinspection PhpMissingParentConstructorInspection
|
||||
*
|
||||
* @param array<string,mixed> $post
|
||||
*/
|
||||
public function __construct(array $post)
|
||||
{
|
||||
|
@ -184,6 +188,9 @@ class _SafeOuroborosTag
|
|||
public string $name = '';
|
||||
public int $type = 0;
|
||||
|
||||
/**
|
||||
* @param array{id:int,tag:string,count:int} $tag
|
||||
*/
|
||||
public function __construct(array $tag)
|
||||
{
|
||||
$this->count = $tag['count'];
|
||||
|
@ -319,7 +326,7 @@ class OuroborosAPI extends Extension
|
|||
/**
|
||||
* Wrapper for post creation
|
||||
*/
|
||||
protected function postCreate(OuroborosPost $post, ?string $md5 = '')
|
||||
protected function postCreate(OuroborosPost $post, ?string $md5 = ''): void
|
||||
{
|
||||
global $config, $database;
|
||||
$handler = $config->get_string(ImageConfig::UPLOAD_COLLISION_HANDLER);
|
||||
|
@ -397,7 +404,7 @@ class OuroborosAPI extends Extension
|
|||
/**
|
||||
* Wrapper for getting a single post
|
||||
*/
|
||||
protected function postShow(int $id = null)
|
||||
protected function postShow(int $id = null): void
|
||||
{
|
||||
if (!is_null($id)) {
|
||||
$post = new _SafeOuroborosImage(Image::by_id($id));
|
||||
|
@ -411,7 +418,7 @@ class OuroborosAPI extends Extension
|
|||
* Wrapper for getting a list of posts
|
||||
* @param string[] $tags
|
||||
*/
|
||||
protected function postIndex(int $limit, int $page, array $tags)
|
||||
protected function postIndex(int $limit, int $page, array $tags): void
|
||||
{
|
||||
$start = ($page - 1) * $limit;
|
||||
$results = Search::find_images(max($start, 0), min($limit, 100), $tags);
|
||||
|
@ -429,7 +436,7 @@ class OuroborosAPI extends Extension
|
|||
* Tag
|
||||
*/
|
||||
|
||||
protected function tagIndex(int $limit, int $page, string $order, int $id, int $after_id, string $name, string $name_pattern)
|
||||
protected function tagIndex(int $limit, int $page, string $order, int $id, int $after_id, string $name, string $name_pattern): void
|
||||
{
|
||||
global $database, $config;
|
||||
$start = ($page - 1) * $limit;
|
||||
|
@ -476,7 +483,7 @@ class OuroborosAPI extends Extension
|
|||
/**
|
||||
* Sends a simple {success,reason} message to browser
|
||||
*/
|
||||
private function sendResponse(int $code = 200, string $reason = '', bool $location = false)
|
||||
private function sendResponse(int $code = 200, string $reason = '', bool $location = false): void
|
||||
{
|
||||
global $page;
|
||||
if ($code == 200) {
|
||||
|
@ -529,7 +536,10 @@ class OuroborosAPI extends Extension
|
|||
$page->set_data($response);
|
||||
}
|
||||
|
||||
private function sendData(string $type = '', array $data = [], int $offset = 0)
|
||||
/**
|
||||
* @param list<_SafeOuroborosTag>|list<_SafeOuroborosImage> $data
|
||||
*/
|
||||
private function sendData(string $type = '', array $data = [], int $offset = 0): void
|
||||
{
|
||||
global $page;
|
||||
$response = '';
|
||||
|
@ -539,22 +549,20 @@ class OuroborosAPI extends Extension
|
|||
$xml = new \XMLWriter();
|
||||
$xml->openMemory();
|
||||
$xml->startDocument('1.0', 'utf-8');
|
||||
if (array_key_exists(0, $data)) {
|
||||
$xml->startElement($type . 's');
|
||||
if ($type == 'post') {
|
||||
$xml->writeAttribute('count', (string)count($data));
|
||||
$xml->writeAttribute('offset', (string)$offset);
|
||||
}
|
||||
if ($type == 'tag') {
|
||||
$xml->writeAttribute('type', 'array');
|
||||
}
|
||||
foreach ($data as $item) {
|
||||
$this->createItemXML($xml, $type, $item);
|
||||
}
|
||||
$xml->endElement();
|
||||
} else {
|
||||
$this->createItemXML($xml, $type, $data);
|
||||
|
||||
$xml->startElement($type . 's');
|
||||
if ($type == 'post') {
|
||||
$xml->writeAttribute('count', (string)count($data));
|
||||
$xml->writeAttribute('offset', (string)$offset);
|
||||
}
|
||||
if ($type == 'tag') {
|
||||
$xml->writeAttribute('type', 'array');
|
||||
}
|
||||
foreach ($data as $item) {
|
||||
$this->createItemXML($xml, $type, $item);
|
||||
}
|
||||
$xml->endElement();
|
||||
|
||||
$xml->endDocument();
|
||||
$response = $xml->outputMemory(true);
|
||||
unset($xml);
|
||||
|
@ -562,10 +570,10 @@ class OuroborosAPI extends Extension
|
|||
$page->set_data($response);
|
||||
}
|
||||
|
||||
private function createItemXML(\XMLWriter $xml, string $type, $item)
|
||||
private function createItemXML(\XMLWriter $xml, string $type, _SafeOuroborosTag|_SafeOuroborosImage $item): void
|
||||
{
|
||||
$xml->startElement($type);
|
||||
foreach ($item as $key => $val) {
|
||||
foreach (json_decode(json_encode($item)) as $key => $val) {
|
||||
if ($key == 'created_at' && $type == 'post') {
|
||||
$xml->writeAttribute($key, $val['s']);
|
||||
} else {
|
||||
|
@ -584,7 +592,7 @@ class OuroborosAPI extends Extension
|
|||
* Currently checks for either user & session in request or cookies
|
||||
* and initializes a global User
|
||||
*/
|
||||
private function tryAuth()
|
||||
private function tryAuth(): void
|
||||
{
|
||||
global $config, $user;
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ class PM
|
|||
$this->is_read = $is_read;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
*/
|
||||
public static function from_row(array $row): PM
|
||||
{
|
||||
$pm = new PM(
|
||||
|
@ -85,6 +88,9 @@ class PM
|
|||
return $pm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PM[]|null
|
||||
*/
|
||||
#[Field(extends: "User", name: "private_messages", type: "[PrivateMessage!]")]
|
||||
public static function get_pms(User $duser): ?array
|
||||
{
|
||||
|
@ -299,7 +305,7 @@ class PrivMsg extends Extension
|
|||
log_info("pm", "Sent PM to User #{$event->pm->to_id}");
|
||||
}
|
||||
|
||||
private function count_pms(User $user)
|
||||
private function count_pms(User $user): int
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
|
|
@ -6,7 +6,10 @@ namespace Shimmie2;
|
|||
|
||||
class PrivMsgTheme extends Themelet
|
||||
{
|
||||
public function display_pms(Page $page, $pms): void
|
||||
/**
|
||||
* @param PM[] $pms
|
||||
*/
|
||||
public function display_pms(Page $page, array $pms): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -58,7 +61,7 @@ class PrivMsgTheme extends Themelet
|
|||
$page->add_block(new Block("Private Messages", $html, "main", 40, "private-messages"));
|
||||
}
|
||||
|
||||
public function display_composer(Page $page, User $from, User $to, $subject = ""): void
|
||||
public function display_composer(Page $page, User $from, User $to, string $subject = ""): void
|
||||
{
|
||||
global $user;
|
||||
$post_url = make_link("pm/send");
|
||||
|
|
|
@ -26,8 +26,12 @@ class PoolCreationException extends SCoreException
|
|||
class PoolAddPostsEvent extends Event
|
||||
{
|
||||
public int $pool_id;
|
||||
/** @var int[] */
|
||||
public array $posts = [];
|
||||
|
||||
/**
|
||||
* @param int[] $posts
|
||||
*/
|
||||
public function __construct(int $pool_id, array $posts)
|
||||
{
|
||||
parent::__construct();
|
||||
|
@ -82,6 +86,9 @@ class Pool
|
|||
public string $date;
|
||||
public int $posts;
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $row
|
||||
*/
|
||||
public function __construct(array $row)
|
||||
{
|
||||
$this->id = (int)$row['id'];
|
||||
|
@ -94,12 +101,15 @@ class Pool
|
|||
$this->posts = (int)$row['posts'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $row
|
||||
*/
|
||||
public static function makePool(array $row): Pool
|
||||
{
|
||||
return new Pool($row);
|
||||
}
|
||||
|
||||
public static function get_pool_id_by_title($poolTitle): ?int
|
||||
public static function get_pool_id_by_title(string $poolTitle): ?int
|
||||
{
|
||||
global $database;
|
||||
$row = $database->get_row("SELECT * FROM pools WHERE title=:title", ["title" => $poolTitle]);
|
||||
|
@ -632,7 +642,7 @@ class Pools extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
private function list_pools(Page $page, int $pageNumber, $search)
|
||||
private function list_pools(Page $page, int $pageNumber, ?string $search): void
|
||||
{
|
||||
global $config, $database;
|
||||
|
||||
|
@ -767,46 +777,43 @@ class Pools extends Extension
|
|||
/**
|
||||
* Gets the previous and next successive images from a pool, given a pool ID and an image ID.
|
||||
*
|
||||
* @return int[] Array returning two elements (prev, next) in 1 dimension. Each returns ImageID or NULL if none.
|
||||
* @return array{prev:?int,next:?int} Array returning two elements (prev, next) in 1 dimension. Each returns ImageID or NULL if none.
|
||||
*/
|
||||
private function get_nav_posts(Pool $pool, int $imageID): ?array
|
||||
private function get_nav_posts(Pool $pool, int $imageID): array
|
||||
{
|
||||
global $database;
|
||||
|
||||
if (empty($imageID)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $database->get_row(
|
||||
"
|
||||
SELECT (
|
||||
SELECT image_id
|
||||
FROM pool_images
|
||||
WHERE pool_id = :pid
|
||||
AND image_order < (
|
||||
SELECT image_order
|
||||
FROM pool_images
|
||||
WHERE pool_id = :pid
|
||||
AND image_id = :iid
|
||||
LIMIT 1
|
||||
)
|
||||
ORDER BY image_order DESC LIMIT 1
|
||||
) AS prev,
|
||||
(
|
||||
SELECT image_id
|
||||
FROM pool_images
|
||||
WHERE pool_id = :pid
|
||||
AND image_order > (
|
||||
SELECT image_order
|
||||
FROM pool_images
|
||||
WHERE pool_id = :pid
|
||||
AND image_id = :iid
|
||||
LIMIT 1
|
||||
)
|
||||
ORDER BY image_order ASC LIMIT 1
|
||||
) AS next
|
||||
SELECT (
|
||||
SELECT image_id
|
||||
FROM pool_images
|
||||
WHERE pool_id = :pid
|
||||
AND image_order < (
|
||||
SELECT image_order
|
||||
FROM pool_images
|
||||
WHERE pool_id = :pid
|
||||
AND image_id = :iid
|
||||
LIMIT 1
|
||||
)
|
||||
ORDER BY image_order DESC LIMIT 1
|
||||
) AS prev,
|
||||
(
|
||||
SELECT image_id
|
||||
FROM pool_images
|
||||
WHERE pool_id = :pid
|
||||
AND image_order > (
|
||||
SELECT image_order
|
||||
FROM pool_images
|
||||
WHERE pool_id = :pid
|
||||
AND image_id = :iid
|
||||
LIMIT 1
|
||||
)
|
||||
ORDER BY image_order ASC LIMIT 1
|
||||
) AS next
|
||||
|
||||
LIMIT 1",
|
||||
LIMIT 1
|
||||
",
|
||||
["pid" => $pool->id, "iid" => $imageID]
|
||||
);
|
||||
}
|
||||
|
@ -814,7 +821,7 @@ class Pools extends Extension
|
|||
/**
|
||||
* Retrieve all the images in a pool, given a pool ID.
|
||||
*/
|
||||
private function get_posts(PageRequestEvent $event, int $poolID)
|
||||
private function get_posts(PageRequestEvent $event, int $poolID): void
|
||||
{
|
||||
global $config, $user, $database;
|
||||
|
||||
|
@ -885,7 +892,7 @@ class Pools extends Extension
|
|||
*
|
||||
* $action Action=1 (one) MEANS ADDED, Action=0 (zero) MEANS REMOVED
|
||||
*/
|
||||
private function add_history(int $poolID, int $action, string $images, int $count)
|
||||
private function add_history(int $poolID, int $action, string $images, int $count): void
|
||||
{
|
||||
global $user, $database;
|
||||
|
||||
|
@ -897,7 +904,7 @@ class Pools extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
private function get_history(int $pageNumber)
|
||||
private function get_history(int $pageNumber): void
|
||||
{
|
||||
global $config, $database;
|
||||
|
||||
|
@ -923,7 +930,7 @@ class Pools extends Extension
|
|||
/**
|
||||
* HERE GO BACK IN HISTORY AND ADD OR REMOVE POSTS TO POOL.
|
||||
*/
|
||||
private function revert_history(int $historyID)
|
||||
private function revert_history(int $historyID): void
|
||||
{
|
||||
global $database;
|
||||
$status = $database->get_all("SELECT * FROM pool_history WHERE id=:hid", ["hid" => $historyID]);
|
||||
|
@ -1009,7 +1016,7 @@ class Pools extends Extension
|
|||
return true;
|
||||
}
|
||||
|
||||
private function update_count(int $pool_id)
|
||||
private function update_count(int $pool_id): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute(
|
||||
|
|
|
@ -31,6 +31,9 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
$this->assert_title("Error");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: int, 1: array{0: int, 1: int}}
|
||||
*/
|
||||
public function testCreate(): array
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
|
@ -53,7 +56,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testCreate')]
|
||||
public function testOnViewImage($args): void
|
||||
public function testOnViewImage(): void
|
||||
{
|
||||
[$pool_id, $image_ids] = $this->testCreate();
|
||||
|
||||
|
@ -67,7 +70,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testCreate')]
|
||||
public function testSearch($args): void
|
||||
public function testSearch(): void
|
||||
{
|
||||
[$pool_id, $image_ids] = $this->testCreate();
|
||||
|
||||
|
@ -79,7 +82,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testCreate')]
|
||||
public function testList($args): void
|
||||
public function testList(): void
|
||||
{
|
||||
$this->testCreate();
|
||||
$this->get_page("pool/list");
|
||||
|
@ -87,7 +90,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testCreate')]
|
||||
public function testView($args): void
|
||||
public function testView(): void
|
||||
{
|
||||
[$pool_id, $image_ids] = $this->testCreate();
|
||||
|
||||
|
@ -96,7 +99,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testCreate')]
|
||||
public function testHistory($args): void
|
||||
public function testHistory(): void
|
||||
{
|
||||
[$pool_id, $image_ids] = $this->testCreate();
|
||||
|
||||
|
@ -105,7 +108,7 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testCreate')]
|
||||
public function testImport($args): void
|
||||
public function testImport(): void
|
||||
{
|
||||
[$pool_id, $image_ids] = $this->testCreate();
|
||||
|
||||
|
@ -116,8 +119,11 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
$this->assert_text("Pool");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: int, 1: array{0: int, 1:int}}
|
||||
*/
|
||||
#[Depends('testCreate')]
|
||||
public function testRemovePosts($args): array
|
||||
public function testRemovePosts(): array
|
||||
{
|
||||
[$pool_id, $image_ids] = $this->testCreate();
|
||||
|
||||
|
@ -131,9 +137,9 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testRemovePosts')]
|
||||
public function testAddPosts($args): void
|
||||
public function testAddPosts(): void
|
||||
{
|
||||
[$pool_id, $image_ids] = $this->testRemovePosts(null);
|
||||
[$pool_id, $image_ids] = $this->testRemovePosts();
|
||||
|
||||
$page = $this->post_page("pool/add_posts", [
|
||||
"pool_id" => $pool_id,
|
||||
|
@ -142,8 +148,11 @@ class PoolsTest extends ShimmiePHPUnitTestCase
|
|||
$this->assertEquals(PageMode::REDIRECT, $page->mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: int, 1: array{0: int, 1:int}}
|
||||
*/
|
||||
#[Depends('testCreate')]
|
||||
public function testEditDescription($args): array
|
||||
public function testEditDescription(): array
|
||||
{
|
||||
[$pool_id, $image_ids] = $this->testCreate();
|
||||
|
||||
|
|
|
@ -10,13 +10,18 @@ use function MicroHTML\emptyHTML;
|
|||
use function MicroHTML\rawHTML;
|
||||
use function MicroHTML\{A,BR,DIV,INPUT,P,SCRIPT,SPAN,TABLE,TBODY,TD,TEXTAREA,TH,THEAD,TR};
|
||||
|
||||
/**
|
||||
* @phpstan-type PoolHistory array{id:int,pool_id:int,title:string,user_name:string,action:string,images:string,count:int,date:string}
|
||||
*/
|
||||
class PoolsTheme extends Themelet
|
||||
{
|
||||
/**
|
||||
* Adds a block to the panel with information on the pool(s) the image is in.
|
||||
* $navIDs = Multidimensional array containing pool id, info & nav IDs.
|
||||
*
|
||||
* @param array<int,array{nav:array{prev:?int,next:?int},info:Pool}> $navIDs
|
||||
*/
|
||||
public function pool_info(array $navIDs)
|
||||
public function pool_info(array $navIDs): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
@ -25,13 +30,11 @@ class PoolsTheme extends Themelet
|
|||
foreach ($navIDs as $poolID => $poolInfo) {
|
||||
$div = DIV(SHM_A("pool/view/" . $poolID, $poolInfo["info"]->title));
|
||||
|
||||
if (!empty($poolInfo["nav"])) {
|
||||
if (!empty($poolInfo["nav"]["prev"])) {
|
||||
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["prev"], "Prev", class: "pools_prev_img"));
|
||||
}
|
||||
if (!empty($poolInfo["nav"]["next"])) {
|
||||
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["next"], "Next", class: "pools_next_img"));
|
||||
}
|
||||
if (!empty($poolInfo["nav"]["prev"])) {
|
||||
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["prev"], "Prev", class: "pools_prev_img"));
|
||||
}
|
||||
if (!empty($poolInfo["nav"]["next"])) {
|
||||
$div->appendChild(SHM_A("post/view/" . $poolInfo["nav"]["next"], "Next", class: "pools_next_img"));
|
||||
}
|
||||
|
||||
$linksPools->appendChild($div);
|
||||
|
@ -42,6 +45,9 @@ class PoolsTheme extends Themelet
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $pools
|
||||
*/
|
||||
public function get_adder_html(Image $image, array $pools): HTMLElement
|
||||
{
|
||||
return SHM_SIMPLE_FORM(
|
||||
|
@ -54,8 +60,10 @@ class PoolsTheme extends Themelet
|
|||
|
||||
/**
|
||||
* HERE WE SHOWS THE LIST OF POOLS.
|
||||
*
|
||||
* @param Pool[] $pools
|
||||
*/
|
||||
public function list_pools(Page $page, array $pools, string $search, int $pageNumber, int $totalPages)
|
||||
public function list_pools(Page $page, array $pools, string $search, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
// Build up the list of pools.
|
||||
$pool_rows = [];
|
||||
|
@ -95,7 +103,7 @@ class PoolsTheme extends Themelet
|
|||
/*
|
||||
* HERE WE DISPLAY THE NEW POOL COMPOSER
|
||||
*/
|
||||
public function new_pool_composer(Page $page)
|
||||
public function new_pool_composer(Page $page): void
|
||||
{
|
||||
$form = SHM_SIMPLE_FORM("pool/create", TABLE(
|
||||
TR(TD("Title:"), TD(INPUT(["type" => "text", "name" => "title"]))),
|
||||
|
@ -108,7 +116,7 @@ class PoolsTheme extends Themelet
|
|||
$page->add_block(new Block("Create Pool", $form, position: 20));
|
||||
}
|
||||
|
||||
private function display_top(?Pool $pool, string $heading, bool $check_all = false)
|
||||
private function display_top(?Pool $pool, string $heading, bool $check_all = false): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
|
@ -146,8 +154,10 @@ class PoolsTheme extends Themelet
|
|||
|
||||
/**
|
||||
* HERE WE DISPLAY THE POOL WITH TITLE DESCRIPTION AND IMAGES WITH PAGINATION.
|
||||
*
|
||||
* @param Image[] $images
|
||||
*/
|
||||
public function view_pool(Pool $pool, array $images, int $pageNumber, int $totalPages)
|
||||
public function view_pool(Pool $pool, array $images, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
@ -166,7 +176,7 @@ class PoolsTheme extends Themelet
|
|||
/**
|
||||
* HERE WE DISPLAY THE POOL OPTIONS ON SIDEBAR BUT WE HIDE REMOVE OPTION IF THE USER IS NOT THE OWNER OR ADMIN.
|
||||
*/
|
||||
public function sidebar_options(Page $page, Pool $pool, bool $check_all)
|
||||
public function sidebar_options(Page $page, Pool $pool, bool $check_all): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
@ -246,8 +256,10 @@ class PoolsTheme extends Themelet
|
|||
|
||||
/**
|
||||
* HERE WE DISPLAY THE RESULT OF THE SEARCH ON IMPORT.
|
||||
*
|
||||
* @param Image[] $images
|
||||
*/
|
||||
public function pool_result(Page $page, array $images, Pool $pool)
|
||||
public function pool_result(Page $page, array $images, Pool $pool): void
|
||||
{
|
||||
$this->display_top($pool, "Importing Posts", true);
|
||||
|
||||
|
@ -283,8 +295,10 @@ class PoolsTheme extends Themelet
|
|||
/**
|
||||
* HERE WE DISPLAY THE POOL ORDERER.
|
||||
* WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH A TEXT INPUT TO SET A NUMBER AND CHANGE THE ORDER
|
||||
*
|
||||
* @param Image[] $images
|
||||
*/
|
||||
public function edit_order(Page $page, Pool $pool, array $images)
|
||||
public function edit_order(Page $page, Pool $pool, array $images): void
|
||||
{
|
||||
$this->display_top($pool, "Sorting Pool");
|
||||
|
||||
|
@ -293,7 +307,7 @@ class PoolsTheme extends Themelet
|
|||
$form->appendChild(SPAN(
|
||||
["class" => "thumb"],
|
||||
$this->build_thumb_html($image),
|
||||
INPUT(["type" => "number", "name" => "imgs[$i][]", "value" => $image->image_order, "style" => "max-width: 50px;"]),
|
||||
INPUT(["type" => "number", "name" => "imgs[$i][]", "value" => $image['image_order'], "style" => "max-width: 50px;"]),
|
||||
INPUT(["type" => "hidden", "name" => "imgs[$i][]", "value" => $image->id])
|
||||
));
|
||||
}
|
||||
|
@ -311,8 +325,10 @@ class PoolsTheme extends Themelet
|
|||
*
|
||||
* WE LIST ALL IMAGES ON POOL WITHOUT PAGINATION AND WITH
|
||||
* A CHECKBOX TO SELECT WHICH IMAGE WE WANT TO REMOVE
|
||||
*
|
||||
* @param Image[] $images
|
||||
*/
|
||||
public function edit_pool(Page $page, Pool $pool, array $images)
|
||||
public function edit_pool(Page $page, Pool $pool, array $images): void
|
||||
{
|
||||
$_input_id = INPUT(["type" => "hidden", "name" => "pool_id", "value" => $pool->id]);
|
||||
|
||||
|
@ -347,8 +363,10 @@ class PoolsTheme extends Themelet
|
|||
|
||||
/**
|
||||
* HERE WE DISPLAY THE HISTORY LIST.
|
||||
*
|
||||
* @param PoolHistory[] $histories
|
||||
*/
|
||||
public function show_history(array $histories, int $pageNumber, int $totalPages)
|
||||
public function show_history(array $histories, int $pageNumber, int $totalPages): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
@ -397,11 +415,17 @@ class PoolsTheme extends Themelet
|
|||
$this->display_paginator($page, "pool/updated", null, $pageNumber, $totalPages);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int,string> $options
|
||||
*/
|
||||
public function get_bulk_pool_selector(array $options): HTMLElement
|
||||
{
|
||||
return SHM_SELECT("bulk_pool_select", $options, required: true, empty_option: true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $search_terms
|
||||
*/
|
||||
public function get_bulk_pool_input(array $search_terms): HTMLElement
|
||||
{
|
||||
return INPUT(
|
||||
|
@ -410,7 +434,7 @@ class PoolsTheme extends Themelet
|
|||
"name" => "bulk_pool_new",
|
||||
"placeholder" => "New Pool",
|
||||
"required" => "",
|
||||
"value" => implode(" ", $search_terms)
|
||||
"value" => Tag::implode($search_terms)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ class PostPeekInfo extends ExtensionInfo
|
|||
public string $key = self::KEY;
|
||||
public string $name = "Post Peek";
|
||||
public string $url = self::SHIMMIE_URL;
|
||||
public array $authors = ["Matthew Barbour"];
|
||||
public array $authors = ["Matthew Barbour" => "matthew@darkholme.net"];
|
||||
public string $license = self::LICENSE_WTFPL;
|
||||
public string $description = "Peek at posts";
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ class PostTitles extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function set_title(int $image_id, string $title)
|
||||
private function set_title(int $image_id, string $title): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("UPDATE images SET title=:title WHERE id=:id", ['title' => $title, 'id' => $image_id]);
|
||||
|
|
|
@ -190,7 +190,9 @@ class PrivateImage extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string[] $context
|
||||
*/
|
||||
private function no_private_query(array $context): bool
|
||||
{
|
||||
foreach ($context as $term) {
|
||||
|
@ -201,7 +203,7 @@ class PrivateImage extends Extension
|
|||
return true;
|
||||
}
|
||||
|
||||
public static function privatize_image($image_id)
|
||||
public static function privatize_image(int $image_id): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
@ -211,7 +213,7 @@ class PrivateImage extends Extension
|
|||
);
|
||||
}
|
||||
|
||||
public static function publicize_image($image_id)
|
||||
public static function publicize_image(int $image_id): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Shimmie2;
|
|||
|
||||
class QRImageTheme extends Themelet
|
||||
{
|
||||
public function links_block(string $link)
|
||||
public function links_block(string $link): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
|
|
@ -6,12 +6,13 @@ namespace Shimmie2;
|
|||
|
||||
class RandomListTheme extends Themelet
|
||||
{
|
||||
/** @var string[] */
|
||||
protected array $search_terms;
|
||||
|
||||
/**
|
||||
* @param string[] $search_terms
|
||||
*/
|
||||
public function set_page(array $search_terms)
|
||||
public function set_page(array $search_terms): void
|
||||
{
|
||||
$this->search_terms = $search_terms;
|
||||
}
|
||||
|
@ -42,6 +43,9 @@ class RandomListTheme extends Themelet
|
|||
$page->add_block(new Block("Navigation", $nav, "left", 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $search_terms
|
||||
*/
|
||||
protected function build_navigation(array $search_terms): string
|
||||
{
|
||||
$h_search_string = html_escape(Tag::implode($search_terms));
|
||||
|
|
|
@ -410,6 +410,9 @@ class Ratings extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ImageRating[]
|
||||
*/
|
||||
public static function get_sorted_ratings(): array
|
||||
{
|
||||
global $_shm_ratings;
|
||||
|
@ -421,6 +424,10 @@ class Ratings extends Extension
|
|||
return $ratings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ImageRating[]|null $ratings
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function get_ratings_dict(array $ratings = null): array
|
||||
{
|
||||
if (!isset($ratings)) {
|
||||
|
@ -464,6 +471,9 @@ class Ratings extends Extension
|
|||
return array_intersect($available, $selected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $privs
|
||||
*/
|
||||
public static function privs_to_sql(array $privs): string
|
||||
{
|
||||
$arr = [];
|
||||
|
@ -566,7 +576,7 @@ class Ratings extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function set_rating(int $image_id, string $rating, string $old_rating)
|
||||
private function set_rating(int $image_id, string $rating, string $old_rating): void
|
||||
{
|
||||
global $database;
|
||||
if ($old_rating != $rating) {
|
||||
|
|
|
@ -11,6 +11,10 @@ use function MicroHTML\{A,P,TABLE,TD,TH,TR};
|
|||
|
||||
class RatingsTheme extends Themelet
|
||||
{
|
||||
/**
|
||||
* @param array<string, ImageRating> $ratings
|
||||
* @param string[] $selected_options
|
||||
*/
|
||||
public function get_selection_rater_html(string $name = "rating", array $ratings = [], array $selected_options = []): HTMLElement
|
||||
{
|
||||
return SHM_SELECT($name, !empty($ratings) ? $ratings : Ratings::get_ratings_dict(), required: true, selected_options: $selected_options);
|
||||
|
@ -25,6 +29,9 @@ class RatingsTheme extends Themelet
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ImageRating[] $current_ratings
|
||||
*/
|
||||
public function display_form(array $current_ratings): void
|
||||
{
|
||||
global $page;
|
||||
|
@ -39,6 +46,9 @@ class RatingsTheme extends Themelet
|
|||
$page->add_block(new Block("Update Ratings", SHM_SIMPLE_FORM("admin/update_ratings", $table)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ImageRating[] $ratings
|
||||
*/
|
||||
public function get_help_html(array $ratings): HTMLElement
|
||||
{
|
||||
$rating_rows = [TR(TH("Name"), TH("Search Term"), TH("Abbreviation"))];
|
||||
|
|
|
@ -169,6 +169,9 @@ class Relationships extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Image[]
|
||||
*/
|
||||
public static function get_children(Image $image, int $omit = null): array
|
||||
{
|
||||
global $database;
|
||||
|
@ -183,7 +186,7 @@ class Relationships extends Extension
|
|||
return $output;
|
||||
}
|
||||
|
||||
private function remove_parent(int $imageID)
|
||||
private function remove_parent(int $imageID): void
|
||||
{
|
||||
global $database;
|
||||
$parentID = $database->get_one("SELECT parent_id FROM images WHERE id = :iid", ["iid" => $imageID]);
|
||||
|
@ -194,7 +197,7 @@ class Relationships extends Extension
|
|||
}
|
||||
}
|
||||
|
||||
private function set_has_children(int $parent_id)
|
||||
private function set_has_children(int $parent_id): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
// Set by box
|
||||
//=================================================================
|
||||
|
||||
/**
|
||||
* @return array{0: Image, 1: Image, 2: Image}
|
||||
*/
|
||||
public function testNoParent(): array
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
|
@ -34,8 +37,11 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
return [$image_1, $image_2, $image_3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:Image, 1:Image, 2:Image}
|
||||
*/
|
||||
#[Depends('testNoParent')]
|
||||
public function testSetParent($imgs): array
|
||||
public function testSetParent(): array
|
||||
{
|
||||
[$image_1, $image_2, $image_3] = $this->testNoParent();
|
||||
|
||||
|
@ -56,10 +62,13 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
return [$image_1, $image_2, $image_3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:Image, 1:Image, 2:Image}
|
||||
*/
|
||||
#[Depends('testSetParent')]
|
||||
public function testChangeParent($imgs): array
|
||||
public function testChangeParent(): array
|
||||
{
|
||||
[$image_1, $image_2, $image_3] = $this->testSetParent(null);
|
||||
[$image_1, $image_2, $image_3] = $this->testSetParent();
|
||||
send_event(new ImageRelationshipSetEvent($image_2->id, $image_3->id));
|
||||
|
||||
// refresh data from database
|
||||
|
@ -78,9 +87,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testSetParent')]
|
||||
public function testSearch($imgs): void
|
||||
public function testSearch(): void
|
||||
{
|
||||
[$image_1, $image_2, $image_3] = $this->testSetParent(null);
|
||||
[$image_1, $image_2, $image_3] = $this->testSetParent();
|
||||
|
||||
$this->assert_search_results(["parent:any"], [$image_2->id]);
|
||||
$this->assert_search_results(["parent:none"], [$image_3->id, $image_1->id]);
|
||||
|
@ -91,9 +100,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testChangeParent')]
|
||||
public function testRemoveParent($imgs): void
|
||||
public function testRemoveParent(): void
|
||||
{
|
||||
[$image_1, $image_2, $image_3] = $this->testChangeParent(null);
|
||||
[$image_1, $image_2, $image_3] = $this->testChangeParent();
|
||||
|
||||
global $database;
|
||||
$database->execute(
|
||||
|
@ -119,6 +128,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
// Set by tag
|
||||
//=================================================================
|
||||
|
||||
/**
|
||||
* @return array{0:Image, 1:Image, 2:Image}
|
||||
*/
|
||||
public function testSetParentByTagBase(): array
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
|
@ -140,8 +152,11 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
return [$image_1, $image_2, $image_3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:Image, 1:Image, 2:Image}
|
||||
*/
|
||||
#[Depends('testSetParentByTagBase')]
|
||||
public function testSetParentByTag($imgs): array
|
||||
public function testSetParentByTag(): array
|
||||
{
|
||||
[$image_1, $image_2, $image_3] = $this->testSetParentByTagBase();
|
||||
|
||||
|
@ -163,10 +178,13 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
return [$image_1, $image_2, $image_3];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:Image, 1:Image, 2:Image}
|
||||
*/
|
||||
#[Depends('testSetParentByTag')]
|
||||
public function testSetChildByTag($imgs): array
|
||||
public function testSetChildByTag(): array
|
||||
{
|
||||
[$image_1, $image_2, $image_3] = $this->testSetParentByTag(null);
|
||||
[$image_1, $image_2, $image_3] = $this->testSetParentByTag();
|
||||
|
||||
send_event(new TagSetEvent($image_3, ["pbx", "child:{$image_1->id}"]));
|
||||
|
||||
|
@ -187,10 +205,9 @@ class RelationshipsTest extends ShimmiePHPUnitTestCase
|
|||
}
|
||||
|
||||
#[Depends('testSetChildByTag')]
|
||||
public function testRemoveParentByTag($imgs): void
|
||||
public function testRemoveParentByTag(): void
|
||||
{
|
||||
[$image_1, $image_2, $image_3] = $this->testSetChildByTag(null);
|
||||
assert(!is_null($image_3));
|
||||
[$image_1, $image_2, $image_3] = $this->testSetChildByTag();
|
||||
|
||||
// check parent is set
|
||||
$this->assertEquals($image_2['parent_id'], $image_1->id);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue