just fix all extensions except home just so we can maintain the characters on the post counter
This commit is contained in:
@@ -4,6 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\{InputInterface,InputArgument};
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Sent when the admin page is ready to be added to
|
||||
*/
|
||||
@@ -41,7 +45,7 @@ class AdminPage extends Extension
|
||||
/** @var AdminPageTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $database, $page, $user;
|
||||
|
||||
@@ -64,7 +68,7 @@ class AdminPage extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onCommand(CommandEvent $event)
|
||||
public function onCliGen(CliGenEvent $event): void
|
||||
{
|
||||
$event->app->register('page:get')
|
||||
->addArgument('query', InputArgument::REQUIRED)
|
||||
@@ -151,17 +155,17 @@ class AdminPage extends Extension
|
||||
$this->theme->display_page();
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($event->parent==="system") {
|
||||
if ($event->parent === "system") {
|
||||
if ($user->can(Permissions::MANAGE_ADMINTOOLS)) {
|
||||
$event->add_nav_link("admin", new Link('admin'), "Board Admin");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::MANAGE_ADMINTOOLS)) {
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class AdminPageTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testAuth()
|
||||
public function testAuth(): void
|
||||
{
|
||||
$this->log_out();
|
||||
$this->assertException(PermissionDenied::class, function () {
|
||||
|
||||
@@ -9,7 +9,7 @@ class AdminPageTheme extends Themelet
|
||||
/*
|
||||
* Show the basics of a page, for other extensions to add to
|
||||
*/
|
||||
public function display_page()
|
||||
public function display_page(): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ class AliasTable extends Table
|
||||
$this->size = 100;
|
||||
$this->limit = 1000000;
|
||||
$this->set_columns([
|
||||
new TextColumn("oldtag", "Old Tag"),
|
||||
new TextColumn("newtag", "New Tag"),
|
||||
new AutoCompleteColumn("oldtag", "Old Tag"),
|
||||
new AutoCompleteColumn("newtag", "New Tag"),
|
||||
new ActionColumn("oldtag"),
|
||||
]);
|
||||
$this->order_by = ["oldtag"];
|
||||
$this->table_attrs = ["class" => "zebra"];
|
||||
$this->table_attrs = ["class" => "zebra form"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class AliasEditor extends Extension
|
||||
/** @var AliasEditorTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $database, $page, $user;
|
||||
|
||||
@@ -108,13 +108,13 @@ class AliasEditor extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onAddAlias(AddAliasEvent $event)
|
||||
public function onAddAlias(AddAliasEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
$row = $database->get_row(
|
||||
"SELECT * FROM aliases WHERE lower(oldtag)=lower(:oldtag)",
|
||||
["oldtag"=>$event->oldtag]
|
||||
["oldtag" => $event->oldtag]
|
||||
);
|
||||
if ($row) {
|
||||
throw new AddAliasException("{$row['oldtag']} is already an alias for {$row['newtag']}");
|
||||
@@ -135,21 +135,21 @@ class AliasEditor extends Extension
|
||||
log_info("alias_editor", "Added alias for {$event->oldtag} -> {$event->newtag}", "Added alias");
|
||||
}
|
||||
|
||||
public function onDeleteAlias(DeleteAliasEvent $event)
|
||||
public function onDeleteAlias(DeleteAliasEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", ["oldtag" => $event->oldtag]);
|
||||
log_info("alias_editor", "Deleted alias for {$event->oldtag}", "Deleted alias");
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
if ($event->parent=="tags") {
|
||||
if ($event->parent == "tags") {
|
||||
$event->add_nav_link("aliases", new Link('alias/list'), "Aliases", NavLink::is_active(["alias"]));
|
||||
}
|
||||
}
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::MANAGE_ALIAS_LIST)) {
|
||||
@@ -162,6 +162,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;
|
||||
|
||||
@@ -6,14 +6,14 @@ namespace Shimmie2;
|
||||
|
||||
class AliasEditorTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testAliasList()
|
||||
public function testAliasList(): void
|
||||
{
|
||||
$this->get_page('alias/list');
|
||||
$this->assert_response(200);
|
||||
$this->assert_title("Alias List");
|
||||
}
|
||||
|
||||
public function testAliasListReadOnly()
|
||||
public function testAliasListReadOnly(): void
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
$this->get_page('alias/list');
|
||||
@@ -26,7 +26,7 @@ class AliasEditorTest extends ShimmiePHPUnitTestCase
|
||||
$this->assert_no_text("Add");
|
||||
}
|
||||
|
||||
public function testAliasOneToOne()
|
||||
public function testAliasOneToOne(): void
|
||||
{
|
||||
$this->log_in_as_admin();
|
||||
|
||||
@@ -54,7 +54,7 @@ class AliasEditorTest extends ShimmiePHPUnitTestCase
|
||||
$this->assert_no_text("test1");
|
||||
}
|
||||
|
||||
public function testAliasOneToMany()
|
||||
public function testAliasOneToMany(): void
|
||||
{
|
||||
$this->log_in_as_admin();
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ class AliasEditorTheme extends Themelet
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
$html = emptyHTML($table, BR(), $paginator, BR(), SHM_A("alias/export/aliases.csv", "Download as CSV", args: ["download"=>"aliases.csv"]));
|
||||
$html = emptyHTML($table, BR(), $paginator, BR(), SHM_A("alias/export/aliases.csv", "Download as CSV", args: ["download" => "aliases.csv"]));
|
||||
|
||||
$bulk_form = SHM_FORM("alias/import", multipart: true);
|
||||
$bulk_form->appendChild(
|
||||
INPUT(["type"=>"file", "name"=>"alias_file"]),
|
||||
INPUT(["type" => "file", "name" => "alias_file"]),
|
||||
SHM_SUBMIT("Upload List")
|
||||
);
|
||||
$bulk_html = emptyHTML($bulk_form);
|
||||
|
||||
@@ -10,7 +10,7 @@ class ApprovalInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Approval";
|
||||
public array $authors = ["Matthew Barbour"=>"matthew@darkholme.net"];
|
||||
public array $authors = ["Matthew Barbour" => "matthew@darkholme.net"];
|
||||
public string $license = self::LICENSE_WTFPL;
|
||||
public ExtensionCategory $category = ExtensionCategory::MODERATION;
|
||||
public string $description = "Adds an approval step to the upload/import process.";
|
||||
|
||||
@@ -16,17 +16,18 @@ class Approval extends Extension
|
||||
/** @var ApprovalTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
$config->set_default_bool(ApprovalConfig::IMAGES, false);
|
||||
$config->set_default_bool(ApprovalConfig::COMMENTS, false);
|
||||
|
||||
Image::$bool_props[] = "approved";
|
||||
Image::$prop_types["approved"] = ImagePropType::BOOL;
|
||||
Image::$prop_types["approved_by_id"] = ImagePropType::INT;
|
||||
}
|
||||
|
||||
public function onImageAddition(ImageAdditionEvent $event)
|
||||
public function onImageAddition(ImageAdditionEvent $event): void
|
||||
{
|
||||
global $user, $config;
|
||||
|
||||
@@ -35,7 +36,7 @@ class Approval extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
@@ -54,18 +55,18 @@ class Approval extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Approval");
|
||||
$sb->add_bool_option(ApprovalConfig::IMAGES, "Posts: ");
|
||||
}
|
||||
|
||||
public function onAdminBuilding(AdminBuildingEvent $event)
|
||||
public function onAdminBuilding(AdminBuildingEvent $event): void
|
||||
{
|
||||
$this->theme->display_admin_form();
|
||||
}
|
||||
|
||||
public function onAdminAction(AdminActionEvent $event)
|
||||
public function onAdminAction(AdminActionEvent $event): void
|
||||
{
|
||||
global $database, $user;
|
||||
|
||||
@@ -78,14 +79,14 @@ class Approval extends Extension
|
||||
$database->set_timeout(null); // These updates can take a little bit
|
||||
$database->execute(
|
||||
"UPDATE images SET approved = :true, approved_by_id = :approved_by_id WHERE approved = :false",
|
||||
["approved_by_id"=>$user->id, "true"=>true, "false"=>false]
|
||||
["approved_by_id" => $user->id, "true" => true, "false" => false]
|
||||
);
|
||||
break;
|
||||
case "disapprove_all":
|
||||
$database->set_timeout(null); // These updates can take a little bit
|
||||
$database->execute(
|
||||
"UPDATE images SET approved = :false, approved_by_id = NULL WHERE approved = :true",
|
||||
["true"=>true, "false"=>false]
|
||||
["true" => true, "false" => false]
|
||||
);
|
||||
break;
|
||||
default:
|
||||
@@ -94,36 +95,36 @@ class Approval extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onDisplayingImage(DisplayingImageEvent $event)
|
||||
public function onDisplayingImage(DisplayingImageEvent $event): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
if (!$this->check_permissions($event->image)) {
|
||||
$page->set_mode(PageMode::REDIRECT);
|
||||
$page->set_redirect(make_link("post/list"));
|
||||
$page->set_redirect(make_link());
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($event->parent=="posts") {
|
||||
if ($event->parent == "posts") {
|
||||
if ($user->can(Permissions::APPROVE_IMAGE)) {
|
||||
$event->add_nav_link("posts_unapproved", new Link('/post/list/approved%3Ano/1'), "Pending Approval", null, 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::APPROVE_IMAGE)) {
|
||||
$event->add_link("Pending Approval", make_link("/post/list/approved%3Ano/1"), 60);
|
||||
$event->add_link("Pending Approval", search_link(["approved:no"]), 60);
|
||||
}
|
||||
}
|
||||
|
||||
public const SEARCH_REGEXP = "/^approved:(yes|no)/";
|
||||
public function onSearchTermParse(SearchTermParseEvent $event)
|
||||
public function onSearchTermParse(SearchTermParseEvent $event): void
|
||||
{
|
||||
global $user, $config;
|
||||
|
||||
@@ -131,7 +132,7 @@ class Approval extends Extension
|
||||
$matches = [];
|
||||
|
||||
if (is_null($event->term) && $this->no_approval_query($event->context)) {
|
||||
$event->add_querylet(new Querylet("approved = :true", ["true"=>true]));
|
||||
$event->add_querylet(new Querylet("approved = :true", ["true" => true]));
|
||||
}
|
||||
|
||||
if (is_null($event->term)) {
|
||||
@@ -139,25 +140,27 @@ class Approval extends Extension
|
||||
}
|
||||
if (preg_match(self::SEARCH_REGEXP, strtolower($event->term), $matches)) {
|
||||
if ($user->can(Permissions::APPROVE_IMAGE) && $matches[1] == "no") {
|
||||
$event->add_querylet(new Querylet("approved != :true", ["true"=>true]));
|
||||
$event->add_querylet(new Querylet("approved != :true", ["true" => true]));
|
||||
} else {
|
||||
$event->add_querylet(new Querylet("approved = :true", ["true"=>true]));
|
||||
$event->add_querylet(new Querylet("approved = :true", ["true" => true]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onHelpPageBuilding(HelpPageBuildingEvent $event)
|
||||
public function onHelpPageBuilding(HelpPageBuildingEvent $event): void
|
||||
{
|
||||
global $user, $config;
|
||||
if ($event->key===HelpPages::SEARCH) {
|
||||
if ($event->key === HelpPages::SEARCH) {
|
||||
if ($user->can(Permissions::APPROVE_IMAGE) && $config->get_bool(ApprovalConfig::IMAGES)) {
|
||||
$event->add_block(new Block("Approval", $this->theme->get_help_html()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string[] $context
|
||||
*/
|
||||
private function no_approval_query(array $context): bool
|
||||
{
|
||||
foreach ($context as $term) {
|
||||
@@ -168,23 +171,23 @@ 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;
|
||||
|
||||
$database->execute(
|
||||
"UPDATE images SET approved = :true, approved_by_id = :approved_by_id WHERE id = :id AND approved = :false",
|
||||
["approved_by_id"=>$user->id, "id"=>$image_id, "true"=>true, "false"=>false]
|
||||
["approved_by_id" => $user->id, "id" => $image_id, "true" => true, "false" => false]
|
||||
);
|
||||
}
|
||||
|
||||
public static function disapprove_image($image_id)
|
||||
public static function disapprove_image(int $image_id): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
$database->execute(
|
||||
"UPDATE images SET approved = :false, approved_by_id = NULL WHERE id = :id AND approved = :true",
|
||||
["id"=>$image_id, "true"=>true, "false"=>false]
|
||||
["id" => $image_id, "true" => true, "false" => false]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -192,13 +195,13 @@ class Approval extends Extension
|
||||
{
|
||||
global $user, $config;
|
||||
|
||||
if ($config->get_bool(ApprovalConfig::IMAGES) && $image->approved===false && !$user->can(Permissions::APPROVE_IMAGE) && $user->id!==$image->owner_id) {
|
||||
if ($config->get_bool(ApprovalConfig::IMAGES) && $image['approved'] === false && !$user->can(Permissions::APPROVE_IMAGE) && $user->id !== $image->owner_id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onImageDownloading(ImageDownloadingEvent $event)
|
||||
public function onImageDownloading(ImageDownloadingEvent $event): void
|
||||
{
|
||||
/**
|
||||
* Deny images upon insufficient permissions.
|
||||
@@ -208,7 +211,7 @@ class Approval extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
|
||||
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user, $config;
|
||||
if ($user->can(Permissions::APPROVE_IMAGE) && $config->get_bool(ApprovalConfig::IMAGES)) {
|
||||
@@ -221,11 +224,11 @@ class Approval extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event)
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user, $config;
|
||||
|
||||
if ($user->can(Permissions::APPROVE_IMAGE)&& $config->get_bool(ApprovalConfig::IMAGES)) {
|
||||
if ($user->can(Permissions::APPROVE_IMAGE) && $config->get_bool(ApprovalConfig::IMAGES)) {
|
||||
if (in_array("approved:no", $event->search_terms)) {
|
||||
$event->add_action("bulk_approve_image", "Approve", "a");
|
||||
} else {
|
||||
@@ -234,7 +237,7 @@ class Approval extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onBulkAction(BulkActionEvent $event)
|
||||
public function onBulkAction(BulkActionEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
@@ -262,7 +265,7 @@ class Approval extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ class ApprovalTheme extends Themelet
|
||||
|
||||
$form = SHM_SIMPLE_FORM(
|
||||
"admin/approval",
|
||||
BUTTON(["name"=>'approval_action', "value"=>'approve_all'], "Approve All Posts"),
|
||||
BUTTON(["name" => 'approval_action', "value" => 'approve_all'], "Approve All Posts"),
|
||||
" ",
|
||||
BUTTON(["name"=>'approval_action', "value"=>'disapprove_all'], "Disapprove All Posts"),
|
||||
BUTTON(["name" => 'approval_action', "value" => 'disapprove_all'], "Disapprove All Posts"),
|
||||
);
|
||||
|
||||
$page->add_block(new Block("Approval", $form));
|
||||
|
||||
@@ -11,7 +11,7 @@ class ArtistsInfo extends ExtensionInfo
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Artists System";
|
||||
public string $url = self::SHIMMIE_URL;
|
||||
public array $authors = ["Sein Kraft"=>"mail@seinkraft.info","Alpha"=>"alpha@furries.com.ar"];
|
||||
public array $authors = ["Sein Kraft" => "mail@seinkraft.info","Alpha" => "alpha@furries.com.ar"];
|
||||
public string $license = self::LICENSE_GPLV2;
|
||||
public ExtensionCategory $category = ExtensionCategory::METADATA;
|
||||
public string $description = "Simple artists extension";
|
||||
|
||||
@@ -19,12 +19,23 @@ class AuthorSetEvent extends Event
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Artists extends Extension
|
||||
{
|
||||
/** @var ArtistsTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onImageInfoSet(ImageInfoSetEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
Image::$prop_types["author"] = ImagePropType::STRING;
|
||||
}
|
||||
|
||||
public function onImageInfoSet(ImageInfoSetEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
$author = $event->get_param("author");
|
||||
@@ -33,7 +44,7 @@ class Artists extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event)
|
||||
public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
$artistName = $this->get_artistName_by_imageID($event->image->id);
|
||||
@@ -42,7 +53,7 @@ class Artists extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onSearchTermParse(SearchTermParseEvent $event)
|
||||
public function onSearchTermParse(SearchTermParseEvent $event): void
|
||||
{
|
||||
if (is_null($event->term)) {
|
||||
return;
|
||||
@@ -51,18 +62,18 @@ class Artists extends Extension
|
||||
$matches = [];
|
||||
if (preg_match("/^(author|artist)[=|:](.*)$/i", $event->term, $matches)) {
|
||||
$char = $matches[2];
|
||||
$event->add_querylet(new Querylet("author = :author_char", ["author_char"=>$char]));
|
||||
$event->add_querylet(new Querylet("author = :author_char", ["author_char" => $char]));
|
||||
}
|
||||
}
|
||||
|
||||
public function onHelpPageBuilding(HelpPageBuildingEvent $event)
|
||||
public function onHelpPageBuilding(HelpPageBuildingEvent $event): void
|
||||
{
|
||||
if ($event->key===HelpPages::SEARCH) {
|
||||
if ($event->key === HelpPages::SEARCH) {
|
||||
$event->add_block(new Block("Artist", $this->theme->get_help_html()));
|
||||
}
|
||||
}
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $config, $database;
|
||||
|
||||
@@ -114,7 +125,7 @@ class Artists extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onAuthorSet(AuthorSetEvent $event)
|
||||
public function onAuthorSet(AuthorSetEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
@@ -151,11 +162,11 @@ class Artists extends Extension
|
||||
|
||||
$database->execute(
|
||||
"UPDATE images SET author = :author WHERE id = :id",
|
||||
['author'=>$artistName, 'id'=>$event->image->id]
|
||||
['author' => $artistName, 'id' => $event->image->id]
|
||||
);
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
@@ -340,28 +351,28 @@ class Artists extends Extension
|
||||
private function get_artistName_by_imageID(int $imageID): string
|
||||
{
|
||||
global $database;
|
||||
$result = $database->get_row("SELECT author FROM images WHERE id = :id", ['id'=>$imageID]);
|
||||
$result = $database->get_row("SELECT author FROM images WHERE id = :id", ['id' => $imageID]);
|
||||
return $result['author'] ?? "";
|
||||
}
|
||||
|
||||
private function url_exists_by_url(string $url): bool
|
||||
{
|
||||
global $database;
|
||||
$result = $database->get_one("SELECT COUNT(1) FROM artist_urls WHERE url = :url", ['url'=>$url]);
|
||||
$result = $database->get_one("SELECT COUNT(1) FROM artist_urls WHERE url = :url", ['url' => $url]);
|
||||
return ($result != 0);
|
||||
}
|
||||
|
||||
private function member_exists_by_name(string $member): bool
|
||||
{
|
||||
global $database;
|
||||
$result = $database->get_one("SELECT COUNT(1) FROM artist_members WHERE name = :name", ['name'=>$member]);
|
||||
$result = $database->get_one("SELECT COUNT(1) FROM artist_members WHERE name = :name", ['name' => $member]);
|
||||
return ($result != 0);
|
||||
}
|
||||
|
||||
private function alias_exists_by_name(string $alias): bool
|
||||
{
|
||||
global $database;
|
||||
$result = $database->get_one("SELECT COUNT(1) FROM artist_alias WHERE alias = :alias", ['alias'=>$alias]);
|
||||
$result = $database->get_one("SELECT COUNT(1) FROM artist_alias WHERE alias = :alias", ['alias' => $alias]);
|
||||
return ($result != 0);
|
||||
}
|
||||
|
||||
@@ -370,7 +381,7 @@ class Artists extends Extension
|
||||
global $database;
|
||||
$result = $database->get_one(
|
||||
"SELECT COUNT(1) FROM artist_alias WHERE artist_id = :artist_id AND alias = :alias",
|
||||
['artist_id'=>$artistID, 'alias'=>$alias]
|
||||
['artist_id' => $artistID, 'alias' => $alias]
|
||||
);
|
||||
return ($result != 0);
|
||||
}
|
||||
@@ -411,43 +422,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]);
|
||||
$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]);
|
||||
$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]);
|
||||
$database->execute("DELETE FROM artist_members WHERE id = :id", ['id' => $memberID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArtistAlias
|
||||
*/
|
||||
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 $database->get_row("SELECT * FROM artist_alias WHERE id = :id", ['id' => $aliasID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArtistUrl
|
||||
*/
|
||||
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 $database->get_row("SELECT * FROM artist_urls WHERE id = :id", ['id' => $urlID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArtistMember
|
||||
*/
|
||||
private function get_member_by_id(int $memberID): array
|
||||
{
|
||||
global $database;
|
||||
return $database->get_row("SELECT * FROM artist_members WHERE id = :id", ['id'=>$memberID]);
|
||||
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([
|
||||
@@ -479,13 +499,13 @@ class Artists extends Extension
|
||||
global $database;
|
||||
$database->execute(
|
||||
"UPDATE artists SET name = :name, notes = :notes, updated = now(), user_id = :user_id WHERE id = :id",
|
||||
['name'=>$name, 'notes'=>$notes, 'user_id'=>$userID, 'id'=>$artistID]
|
||||
['name' => $name, 'notes' => $notes, 'user_id' => $userID, 'id' => $artistID]
|
||||
);
|
||||
|
||||
// ALIAS MATCHING SECTION
|
||||
$i = 0;
|
||||
$aliasesAsArray = is_null($aliasesAsString) ? [] : explode(" ", $aliasesAsString);
|
||||
$aliasesIDsAsArray = is_null($aliasesIDsAsString) ? [] : explode(" ", $aliasesIDsAsString);
|
||||
$aliasesIDsAsArray = is_null($aliasesIDsAsString) ? [] : array_map(fn ($n) => int_escape($n), explode(" ", $aliasesIDsAsString));
|
||||
while ($i < count($aliasesAsArray)) {
|
||||
// if an alias was updated
|
||||
if ($i < count($aliasesIDsAsArray)) {
|
||||
@@ -505,7 +525,7 @@ class Artists extends Extension
|
||||
// MEMBERS MATCHING SECTION
|
||||
$i = 0;
|
||||
$membersAsArray = is_null($membersAsString) ? [] : explode(" ", $membersAsString);
|
||||
$membersIDsAsArray = is_null($membersIDsAsString) ? [] : explode(" ", $membersIDsAsString);
|
||||
$membersIDsAsArray = is_null($membersIDsAsString) ? [] : array_map(fn ($n) => int_escape($n), explode(" ", $membersIDsAsString));
|
||||
while ($i < count($membersAsArray)) {
|
||||
// if a member was updated
|
||||
if ($i < count($membersIDsAsArray)) {
|
||||
@@ -524,10 +544,11 @@ class Artists extends Extension
|
||||
|
||||
// URLS MATCHING SECTION
|
||||
$i = 0;
|
||||
assert(is_string($urlsAsString));
|
||||
$urlsAsString = str_replace("\r\n", "\n", $urlsAsString);
|
||||
$urlsAsString = str_replace("\n\r", "\n", $urlsAsString);
|
||||
$urlsAsArray = is_null($urlsAsString) ? [] : explode("\n", $urlsAsString);
|
||||
$urlsIDsAsArray = is_null($urlsIDsAsString) ? [] : explode(" ", $urlsIDsAsString);
|
||||
$urlsAsArray = empty($urlsAsString) ? [] : explode("\n", $urlsAsString);
|
||||
$urlsIDsAsArray = is_null($urlsIDsAsString) ? [] : array_map(fn ($n) => int_escape($n), explode(" ", $urlsIDsAsString));
|
||||
while ($i < count($urlsAsArray)) {
|
||||
// if an URL was updated
|
||||
if ($i < count($urlsIDsAsArray)) {
|
||||
@@ -545,7 +566,7 @@ class Artists extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
private function update_alias()
|
||||
private function update_alias(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
@@ -555,16 +576,16 @@ 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(
|
||||
"UPDATE artist_alias SET alias = :alias, updated = now(), user_id = :user_id WHERE id = :id",
|
||||
['alias'=>$alias, 'user_id'=>$userID, 'id'=>$aliasID]
|
||||
['alias' => $alias, 'user_id' => $userID, 'id' => $aliasID]
|
||||
);
|
||||
}
|
||||
|
||||
private function update_url()
|
||||
private function update_url(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
@@ -574,16 +595,16 @@ 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(
|
||||
"UPDATE artist_urls SET url = :url, updated = now(), user_id = :user_id WHERE id = :id",
|
||||
['url'=>$url, 'user_id'=>$userID, 'id'=>$urlID]
|
||||
['url' => $url, 'user_id' => $userID, 'id' => $urlID]
|
||||
);
|
||||
}
|
||||
|
||||
private function update_member()
|
||||
private function update_member(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
@@ -593,12 +614,12 @@ 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(
|
||||
"UPDATE artist_members SET name = :name, updated = now(), user_id = :user_id WHERE id = :id",
|
||||
['name'=>$memberName, 'user_id'=>$userID, 'id'=>$memberID]
|
||||
['name' => $memberName, 'user_id' => $userID, 'id' => $memberID]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -654,6 +675,7 @@ class Artists extends Extension
|
||||
}
|
||||
|
||||
if (!is_null($urls)) {
|
||||
assert(is_string($urls));
|
||||
//delete double "separators"
|
||||
$urls = str_replace("\r\n", "\n", $urls);
|
||||
$urls = str_replace("\n\r", "\n", $urls);
|
||||
@@ -674,7 +696,7 @@ class Artists extends Extension
|
||||
$database->execute("
|
||||
INSERT INTO artists (user_id, name, notes, created, updated)
|
||||
VALUES (:user_id, :name, :notes, now(), now())
|
||||
", ['user_id'=>$user->id, 'name'=>$name, 'notes'=>$notes]);
|
||||
", ['user_id' => $user->id, 'name' => $name, 'notes' => $notes]);
|
||||
return $database->get_last_insert_id('artists_id_seq');
|
||||
}
|
||||
|
||||
@@ -683,17 +705,20 @@ class Artists extends Extension
|
||||
global $database;
|
||||
$result = $database->get_one(
|
||||
"SELECT COUNT(1) FROM artists WHERE name = :name",
|
||||
['name'=>$name]
|
||||
['name' => $name]
|
||||
);
|
||||
return ($result != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArtistArtist
|
||||
*/
|
||||
private function get_artist(int $artistID): array
|
||||
{
|
||||
global $database;
|
||||
$result = $database->get_row(
|
||||
"SELECT * FROM artists WHERE id = :id",
|
||||
['id'=>$artistID]
|
||||
['id' => $artistID]
|
||||
);
|
||||
|
||||
$result["name"] = stripslashes($result["name"]);
|
||||
@@ -702,12 +727,15 @@ class Artists extends Extension
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArtistMember[]
|
||||
*/
|
||||
private function get_members(int $artistID): array
|
||||
{
|
||||
global $database;
|
||||
$result = $database->get_all(
|
||||
"SELECT * FROM artist_members WHERE artist_id = :artist_id",
|
||||
['artist_id'=>$artistID]
|
||||
['artist_id' => $artistID]
|
||||
);
|
||||
|
||||
$num = count($result);
|
||||
@@ -718,12 +746,15 @@ class Artists extends Extension
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArtistUrl[]
|
||||
*/
|
||||
private function get_urls(int $artistID): array
|
||||
{
|
||||
global $database;
|
||||
$result = $database->get_all(
|
||||
"SELECT id, url FROM artist_urls WHERE artist_id = :artist_id",
|
||||
['artist_id'=>$artistID]
|
||||
['artist_id' => $artistID]
|
||||
);
|
||||
|
||||
$num = count($result);
|
||||
@@ -739,7 +770,7 @@ class Artists extends Extension
|
||||
global $database;
|
||||
return (int) $database->get_one(
|
||||
"SELECT id FROM artists WHERE name = :name",
|
||||
['name'=>$name]
|
||||
['name' => $name]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -749,16 +780,16 @@ class Artists extends Extension
|
||||
|
||||
return (int) $database->get_one(
|
||||
"SELECT artist_id FROM artist_alias WHERE alias = :alias",
|
||||
['alias'=>$alias]
|
||||
['alias' => $alias]
|
||||
);
|
||||
}
|
||||
|
||||
private function delete_artist(int $artistID)
|
||||
private function delete_artist(int $artistID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute(
|
||||
"DELETE FROM artists WHERE id = :id",
|
||||
['id'=>$artistID]
|
||||
['id' => $artistID]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -820,8 +851,8 @@ class Artists extends Extension
|
||||
LIMIT :offset, :limit
|
||||
",
|
||||
[
|
||||
"offset"=>$pageNumber * $artistsPerPage,
|
||||
"limit"=>$artistsPerPage
|
||||
"offset" => $pageNumber * $artistsPerPage,
|
||||
"limit" => $artistsPerPage
|
||||
]
|
||||
);
|
||||
|
||||
@@ -867,17 +898,17 @@ 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;
|
||||
|
||||
$database->execute(
|
||||
"INSERT INTO artist_urls (artist_id, created, updated, url, user_id) VALUES (:artist_id, now(), now(), :url, :user_id)",
|
||||
['artist'=>$artistID, 'url'=>$url, 'user_id'=>$userID]
|
||||
['artist' => $artistID, 'url' => $url, 'user_id' => $userID]
|
||||
);
|
||||
}
|
||||
|
||||
private function add_alias()
|
||||
private function add_alias(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
@@ -894,17 +925,17 @@ 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;
|
||||
|
||||
$database->execute(
|
||||
"INSERT INTO artist_alias (artist_id, created, updated, alias, user_id) VALUES (:artist_id, now(), now(), :alias, :user_id)",
|
||||
['artist_id'=>$artistID, 'alias'=>$alias, 'user_id'=>$userID]
|
||||
['artist_id' => $artistID, 'alias' => $alias, 'user_id' => $userID]
|
||||
);
|
||||
}
|
||||
|
||||
private function add_members()
|
||||
private function add_members(): void
|
||||
{
|
||||
global $user;
|
||||
$inputs = validate_input([
|
||||
@@ -921,13 +952,13 @@ 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;
|
||||
|
||||
$database->execute(
|
||||
"INSERT INTO artist_members (artist_id, name, created, updated, user_id) VALUES (:artist_id, :name, now(), now(), :user_id)",
|
||||
['artist'=>$artistID, 'name'=>$member, 'user_id'=>$userID]
|
||||
['artist' => $artistID, 'name' => $member, 'user_id' => $userID]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -937,7 +968,7 @@ class Artists extends Extension
|
||||
|
||||
$result = $database->get_one(
|
||||
"SELECT COUNT(1) FROM artist_members WHERE artist_id = :artist_id AND name = :name",
|
||||
['artist_id'=>$artistID, 'name'=>$member]
|
||||
['artist_id' => $artistID, 'name' => $member]
|
||||
);
|
||||
return ($result != 0);
|
||||
}
|
||||
@@ -948,13 +979,15 @@ class Artists extends Extension
|
||||
|
||||
$result = $database->get_one(
|
||||
"SELECT COUNT(1) FROM artist_urls WHERE artist_id = :artist_id AND url = :url",
|
||||
['artist_id'=>$artistID, 'url'=>$url]
|
||||
['artist_id' => $artistID, 'url' => $url]
|
||||
);
|
||||
return ($result != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* HERE WE GET THE INFO OF THE ALIAS
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_alias(int $artistID): array
|
||||
{
|
||||
@@ -965,7 +998,7 @@ class Artists extends Extension
|
||||
FROM artist_alias
|
||||
WHERE artist_id = :artist_id
|
||||
ORDER BY alias ASC
|
||||
", ['artist_id'=>$artistID]);
|
||||
", ['artist_id' => $artistID]);
|
||||
|
||||
$rc = count($result);
|
||||
for ($i = 0; $i < $rc; $i++) {
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class ArtistsTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testSearch()
|
||||
public function testSearch(): void
|
||||
{
|
||||
global $user;
|
||||
$this->log_in_as_user();
|
||||
|
||||
@@ -7,11 +7,17 @@ namespace Shimmie2;
|
||||
use MicroHTML\HTMLElement;
|
||||
|
||||
use function MicroHTML\emptyHTML;
|
||||
use function MicroHTML\{INPUT,P,SPAN,TD,TH,TR};
|
||||
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): string
|
||||
public function get_author_editor_html(string $author): HTMLElement
|
||||
{
|
||||
return SHM_POST_INFO(
|
||||
"Author",
|
||||
@@ -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;
|
||||
|
||||
@@ -70,7 +76,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;
|
||||
|
||||
@@ -105,7 +117,7 @@ class ArtistsTheme extends Themelet
|
||||
$urlsString .= $url["url"]."\n";
|
||||
$urlsIDsString .= $url["id"]." ";
|
||||
}
|
||||
$urlsString = substr($urlsString, 0, strlen($urlsString) -1);
|
||||
$urlsString = substr($urlsString, 0, strlen($urlsString) - 1);
|
||||
$urlsIDsString = rtrim($urlsIDsString);
|
||||
|
||||
$html = make_form(make_link("artist/edited/".$artist['id'])).'
|
||||
@@ -128,7 +140,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;
|
||||
|
||||
@@ -148,7 +160,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;
|
||||
|
||||
@@ -227,7 +242,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;
|
||||
|
||||
@@ -244,7 +259,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;
|
||||
|
||||
@@ -261,7 +276,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;
|
||||
|
||||
@@ -278,7 +293,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;
|
||||
|
||||
@@ -294,7 +312,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;
|
||||
|
||||
@@ -310,7 +331,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;
|
||||
|
||||
@@ -326,11 +350,18 @@ 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;
|
||||
|
||||
$artist_link = "<a href='".make_link("post/list/".$artist['name']."/1")."'>".str_replace("_", " ", $artist['name'])."</a>";
|
||||
$artist_link = "<a href='".search_link([$artist['name']])."'>".str_replace("_", " ", $artist['name'])."</a>";
|
||||
|
||||
$html = "<table id='poolsList' class='zebra'>
|
||||
<thead>
|
||||
@@ -394,6 +425,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 = "";
|
||||
@@ -440,6 +474,9 @@ class ArtistsTheme extends Themelet
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArtistMember[] $members
|
||||
*/
|
||||
private function render_members(array $members, bool $userIsLogged, bool $userIsAdmin): string
|
||||
{
|
||||
$html = "";
|
||||
@@ -484,6 +521,9 @@ class ArtistsTheme extends Themelet
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArtistUrl[] $urls
|
||||
*/
|
||||
private function render_urls(array $urls, bool $userIsLogged, bool $userIsAdmin): string
|
||||
{
|
||||
$html = "";
|
||||
|
||||
@@ -10,7 +10,7 @@ class AutoTaggerInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Auto-Tagger";
|
||||
public array $authors = ["Matthew Barbour"=>"matthew@darkholme.net"];
|
||||
public array $authors = ["Matthew Barbour" => "matthew@darkholme.net"];
|
||||
public string $license = self::LICENSE_WTFPL;
|
||||
public ExtensionCategory $category = ExtensionCategory::METADATA;
|
||||
public string $description = "Provides several automatic tagging functions";
|
||||
|
||||
@@ -21,12 +21,12 @@ class AutoTaggerTable extends Table
|
||||
$this->size = 100;
|
||||
$this->limit = 1000000;
|
||||
$this->set_columns([
|
||||
new TextColumn("tag", "Tag"),
|
||||
new TextColumn("additional_tags", "Additional Tags"),
|
||||
new AutoCompleteColumn("tag", "Tag"),
|
||||
new AutoCompleteColumn("additional_tags", "Additional Tags"),
|
||||
new ActionColumn("tag"),
|
||||
]);
|
||||
$this->order_by = ["tag"];
|
||||
$this->table_attrs = ["class" => "zebra"];
|
||||
$this->table_attrs = ["class" => "zebra form"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ class AutoTagger extends Extension
|
||||
/** @var AutoTaggerTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $database, $page, $user;
|
||||
|
||||
@@ -114,14 +114,14 @@ class AutoTagger extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
if ($event->parent=="tags") {
|
||||
if ($event->parent == "tags") {
|
||||
$event->add_nav_link("auto_tag", new Link('auto_tag/list'), "Auto-Tag", NavLink::is_active(["auto_tag"]));
|
||||
}
|
||||
}
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
@@ -141,27 +141,27 @@ class AutoTagger extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onTagSet(TagSetEvent $event)
|
||||
public function onTagSet(TagSetEvent $event): void
|
||||
{
|
||||
$results = $this->apply_auto_tags($event->tags);
|
||||
$results = $this->apply_auto_tags($event->new_tags);
|
||||
if (!empty($results)) {
|
||||
$event->tags = $results;
|
||||
$event->new_tags = $results;
|
||||
}
|
||||
}
|
||||
|
||||
public function onAddAutoTag(AddAutoTagEvent $event)
|
||||
public function onAddAutoTag(AddAutoTagEvent $event): void
|
||||
{
|
||||
global $page;
|
||||
$this->add_auto_tag($event->tag, $event->additional_tags);
|
||||
$page->flash("Added Auto-Tag");
|
||||
}
|
||||
|
||||
public function onDeleteAutoTag(DeleteAutoTagEvent $event)
|
||||
public function onDeleteAutoTag(DeleteAutoTagEvent $event): void
|
||||
{
|
||||
$this->remove_auto_tag($event->tag);
|
||||
}
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::MANAGE_AUTO_TAG)) {
|
||||
@@ -174,6 +174,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;
|
||||
@@ -193,10 +194,10 @@ 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]);
|
||||
$existing_tags = $database->get_one("SELECT additional_tags FROM auto_tag WHERE LOWER(tag)=LOWER(:tag)", ["tag" => $tag]);
|
||||
if (!is_null($existing_tags)) {
|
||||
// Auto Tags already exist, so we will append new tags to the existing one
|
||||
$tag = Tag::sanitize($tag);
|
||||
@@ -210,7 +211,7 @@ class AutoTagger extends Extension
|
||||
|
||||
$database->execute(
|
||||
"UPDATE auto_tag set additional_tags=:existing_tags where tag=:tag",
|
||||
["tag"=>$tag, "existing_tags"=>Tag::implode($existing_tags)]
|
||||
["tag" => $tag, "existing_tags" => Tag::implode($existing_tags)]
|
||||
);
|
||||
log_info(
|
||||
AutoTaggerInfo::KEY,
|
||||
@@ -222,7 +223,7 @@ class AutoTagger extends Extension
|
||||
|
||||
$database->execute(
|
||||
"INSERT INTO auto_tag(tag, additional_tags) VALUES(:tag, :additional_tags)",
|
||||
["tag"=>$tag, "additional_tags"=>Tag::implode($additional_tags)]
|
||||
["tag" => $tag, "additional_tags" => Tag::implode($additional_tags)]
|
||||
);
|
||||
|
||||
log_info(
|
||||
@@ -234,12 +235,12 @@ 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]);
|
||||
$tag_id = $database->get_one("SELECT id FROM tags WHERE LOWER(tag) = LOWER(:tag)", ["tag" => $tag]);
|
||||
if (!empty($tag_id)) {
|
||||
$image_ids = $database->get_col_iterable("SELECT image_id FROM image_tags WHERE tag_id = :tag_id", ["tag_id"=>$tag_id]);
|
||||
$image_ids = $database->get_col_iterable("SELECT image_id FROM image_tags WHERE tag_id = :tag_id", ["tag_id" => $tag_id]);
|
||||
foreach ($image_ids as $image_id) {
|
||||
$image_id = (int) $image_id;
|
||||
$image = Image::by_id_ex($image_id);
|
||||
@@ -248,7 +249,7 @@ class AutoTagger extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
private function remove_auto_tag(String $tag)
|
||||
private function remove_auto_tag(string $tag): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
@@ -256,9 +257,10 @@ class AutoTagger extends Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* #param string[] $tags_mixed
|
||||
* @param string[] $tags_mixed
|
||||
* @return string[]
|
||||
*/
|
||||
private function apply_auto_tags(array $tags_mixed): ?array
|
||||
private function apply_auto_tags(array $tags_mixed): array
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@ namespace Shimmie2;
|
||||
|
||||
class AutoTaggerTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testAutoTaggerList()
|
||||
public function testAutoTaggerList(): void
|
||||
{
|
||||
$this->get_page('auto_tag/list');
|
||||
$this->assert_response(200);
|
||||
$this->assert_title("Auto-Tag");
|
||||
}
|
||||
|
||||
public function testAutoTaggerListReadOnly()
|
||||
public function testAutoTaggerListReadOnly(): void
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
$this->get_page('auto_tag/list');
|
||||
@@ -26,7 +26,7 @@ class AutoTaggerTest extends ShimmiePHPUnitTestCase
|
||||
$this->assert_no_text("value=\"Add\"");
|
||||
}
|
||||
|
||||
public function testAutoTagger()
|
||||
public function testAutoTagger(): void
|
||||
{
|
||||
$this->log_in_as_admin();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@ class AutoCompleteInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Autocomplete";
|
||||
public array $authors = ["Daku"=>"admin@codeanimu.net"];
|
||||
public array $authors = ["Daku" => "admin@codeanimu.net"];
|
||||
public string $description = "Adds autocomplete to search & tagging.";
|
||||
}
|
||||
|
||||
@@ -6,15 +6,12 @@ namespace Shimmie2;
|
||||
|
||||
class AutoComplete extends Extension
|
||||
{
|
||||
/** @var AutoCompleteTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function get_priority(): int
|
||||
{
|
||||
return 30;
|
||||
} // before Home
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
@@ -28,8 +25,6 @@ class AutoComplete extends Extension
|
||||
$page->set_mime(MimeType::JSON);
|
||||
$page->set_data(\Safe\json_encode($res));
|
||||
}
|
||||
|
||||
$this->theme->build_autocomplete($page);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,10 +34,6 @@ class AutoComplete extends Extension
|
||||
{
|
||||
global $cache, $database;
|
||||
|
||||
if (!$search) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$search = strtolower($search);
|
||||
if (
|
||||
$search == '' ||
|
||||
@@ -54,15 +45,17 @@ class AutoComplete extends Extension
|
||||
}
|
||||
|
||||
# memcache keys can't contain spaces
|
||||
$cache_key = "autocomplete:" . md5($search);
|
||||
$cache_key = "autocomplete:$limit:" . md5($search);
|
||||
$limitSQL = "";
|
||||
$search = str_replace('_', '\_', $search);
|
||||
$search = str_replace('%', '\%', $search);
|
||||
$SQLarr = ["search"=>"$search%"]; #, "cat_search"=>"%:$search%"];
|
||||
$SQLarr = [
|
||||
"search" => "$search%",
|
||||
"cat_search" => Extension::is_enabled(TagCategoriesInfo::KEY) ? "%:$search%" : "",
|
||||
];
|
||||
if ($limit !== 0) {
|
||||
$limitSQL = "LIMIT :limit";
|
||||
$SQLarr['limit'] = $limit;
|
||||
$cache_key .= "-" . $limit;
|
||||
}
|
||||
|
||||
return cache_get_or_set($cache_key, function () use ($database, $limitSQL, $SQLarr) {
|
||||
|
||||
@@ -201,37 +201,36 @@ function setCompletion(element, new_word) {
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
var metatags = ['order:id', 'order:width', 'order:height', 'order:filesize', 'order:filename', 'order:favorites'];
|
||||
// Find all elements with class 'autocomplete_tags'
|
||||
document.querySelectorAll('.autocomplete_tags').forEach((element) => {
|
||||
// set metadata
|
||||
element.completions = {};
|
||||
element.selected_completion = -1;
|
||||
element.completer_timeout = null;
|
||||
|
||||
$('.autocomplete_tags').tagit({
|
||||
singleFieldDelimiter: ' ',
|
||||
beforeTagAdded: function(event, ui) {
|
||||
if(metatags.indexOf(ui.tagLabel) !== -1) {
|
||||
ui.tag.addClass('tag-metatag');
|
||||
} else {
|
||||
console.log(ui.tagLabel);
|
||||
// give special class to negative tags
|
||||
if(ui.tagLabel[0] === '-') {
|
||||
ui.tag.addClass('tag-negative');
|
||||
}else{
|
||||
ui.tag.addClass('tag-positive');
|
||||
}
|
||||
// disable built-in autocomplete
|
||||
element.setAttribute('autocomplete', 'off');
|
||||
|
||||
// safari treats spellcheck as a form of autocomplete
|
||||
element.setAttribute('spellcheck', 'off');
|
||||
|
||||
// when element is focused, add completion block
|
||||
element.addEventListener('focus', () => {
|
||||
updateCompletions(element);
|
||||
});
|
||||
|
||||
// when element is blurred, remove completion block
|
||||
element.addEventListener('blur', () => {
|
||||
hideCompletions();
|
||||
});
|
||||
|
||||
// when cursor is moved, change current completion
|
||||
document.addEventListener('selectionchange', () => {
|
||||
// if element is focused
|
||||
if(document.activeElement === element) {
|
||||
updateCompletions(element);
|
||||
}
|
||||
},
|
||||
autocomplete : ({
|
||||
source: function (request, response) {
|
||||
var ac_metatags = $.map(
|
||||
$.grep(metatags, function(s) {
|
||||
// Only show metatags for strings longer than one character
|
||||
return (request.term.length > 1 && s.indexOf(request.term) === 0);
|
||||
}),
|
||||
function(item) {
|
||||
return {
|
||||
label : item + ' [metatag]',
|
||||
value : item
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
element.addEventListener('keydown', (event) => {
|
||||
// up / down should select previous / next completion
|
||||
@@ -256,57 +255,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
|
||||
$('#tag_editor,[name="bulk_tags"]').tagit({
|
||||
singleFieldDelimiter: ' ',
|
||||
autocomplete : ({
|
||||
source: function (request, response) {
|
||||
$.ajax({
|
||||
url: base_href + '/api/internal/autocomplete',
|
||||
data: {'s': request.term},
|
||||
dataType : 'json',
|
||||
type : 'GET',
|
||||
success : function (data) {
|
||||
response(
|
||||
$.map(data, function (count, item) {
|
||||
return {
|
||||
label : item + ' ('+count+')',
|
||||
value : item
|
||||
};
|
||||
})
|
||||
);
|
||||
},
|
||||
error : function (request, status, error) {
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
minLength: 1
|
||||
})
|
||||
});
|
||||
|
||||
$('.ui-autocomplete-input').keydown(function(e) {
|
||||
var keyCode = e.keyCode || e.which;
|
||||
|
||||
//Stop tags containing space.
|
||||
if(keyCode === 32) {
|
||||
e.preventDefault();
|
||||
var el = $('.ui-widget-content:focus');
|
||||
|
||||
//Find the correct element in a page with multiple tagit input boxes.
|
||||
$('.autocomplete_tags').each(function(_,n){
|
||||
if (n.parentNode.contains(el[0])){
|
||||
$(n.parentNode).find('.autocomplete_tags').tagit('createTag', el.val());
|
||||
}
|
||||
});
|
||||
$(this).autocomplete('close');
|
||||
} else if (keyCode === 9) {
|
||||
e.preventDefault();
|
||||
|
||||
var tag = $('.tagit-autocomplete[style*=\"display: block\"] > li:focus, .tagit-autocomplete[style*=\"display: block\"] > li:first').first();
|
||||
if(tag.length){
|
||||
$(tag).click();
|
||||
$('.ui-autocomplete-input').val(''); //If tag already exists, make sure to remove duplicate.
|
||||
}
|
||||
}
|
||||
// on change, update completions
|
||||
element.addEventListener('input', () => {
|
||||
updateCompletions(element);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
#Navigationleft .blockbody { overflow: visible; }
|
||||
|
||||
.tagit { background: white !important; border: 1px solid grey !important; cursor: text; }
|
||||
.tagit-choice { cursor: initial; }
|
||||
input[name=search] ~ input[type=submit] { display: inline-block !important; }
|
||||
|
||||
.tag-negative { background: #ff8080 !important; }
|
||||
.tag-positive { background: #40bf40 !important; }
|
||||
.tag-metatag { background: #eaa338 !important; }
|
||||
.autocomplete_completions {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
border: 1px solid #ccc;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
padding: 5px;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
}
|
||||
.autocomplete_completions LI {
|
||||
padding: 0.15em;
|
||||
}
|
||||
.autocomplete_completions .selected {
|
||||
background-color: #ccc;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@ namespace Shimmie2;
|
||||
|
||||
class AutoCompleteTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testAuth()
|
||||
public function testAuth(): void
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "link");
|
||||
send_event(new AddAliasEvent("prince_zelda", "link"));
|
||||
|
||||
send_event(new UserLoginEvent(User::by_name(self::$anon_name)));
|
||||
$page = $this->get_page('api/internal/autocomplete', ["s"=>"not-a-tag"]);
|
||||
$page = $this->get_page('api/internal/autocomplete', ["s" => "not-a-tag"]);
|
||||
$this->assertEquals(200, $page->code);
|
||||
$this->assertEquals(PageMode::DATA, $page->mode);
|
||||
$this->assertEquals("[]", $page->data);
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class BanWords extends Extension
|
||||
{
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_string('banned_words', "
|
||||
@@ -39,7 +39,7 @@ xanax
|
||||
");
|
||||
}
|
||||
|
||||
public function onCommentPosting(CommentPostingEvent $event)
|
||||
public function onCommentPosting(CommentPostingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if (!$user->can(Permissions::BYPASS_COMMENT_CHECKS)) {
|
||||
@@ -47,17 +47,17 @@ xanax
|
||||
}
|
||||
}
|
||||
|
||||
public function onSourceSet(SourceSetEvent $event)
|
||||
public function onSourceSet(SourceSetEvent $event): void
|
||||
{
|
||||
$this->test_text($event->source, new UserError("Source contains banned terms"));
|
||||
}
|
||||
|
||||
public function onTagSet(TagSetEvent $event)
|
||||
public function onTagSet(TagSetEvent $event): void
|
||||
{
|
||||
$this->test_text(Tag::implode($event->new_tags), new UserError("Tags contain banned terms"));
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Banned Phrases");
|
||||
$sb->add_label("One per line, lines that start with slashes are treated as regex<br/>");
|
||||
@@ -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 {
|
||||
@@ -17,7 +17,7 @@ class BanWordsTest extends ShimmiePHPUnitTestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testWordBan()
|
||||
public function testWordBan(): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_string("banned_words", "viagra\nporn\n\n/http:.*\.cn\//");
|
||||
|
||||
@@ -7,6 +7,12 @@ namespace Shimmie2;
|
||||
class BBCode extends FormatterExtension
|
||||
{
|
||||
public function format(string $text): string
|
||||
{
|
||||
$text = $this->_format($text);
|
||||
return "<span class='bbcode'>$text</span>";
|
||||
}
|
||||
|
||||
public function _format(string $text): string
|
||||
{
|
||||
$text = $this->extract_code($text);
|
||||
foreach ([
|
||||
@@ -97,8 +103,8 @@ class BBCode extends FormatterExtension
|
||||
}
|
||||
|
||||
$beginning = substr($text, 0, $start);
|
||||
$middle = str_rot13(substr($text, $start+$l1, ($end-$start-$l1)));
|
||||
$ending = substr($text, $end + $l2, (strlen($text)-$end+$l2));
|
||||
$middle = str_rot13(substr($text, $start + $l1, ($end - $start - $l1)));
|
||||
$ending = substr($text, $end + $l2, (strlen($text) - $end + $l2));
|
||||
|
||||
$text = $beginning . $middle . $ending;
|
||||
}
|
||||
@@ -131,8 +137,8 @@ class BBCode extends FormatterExtension
|
||||
}
|
||||
|
||||
$beginning = substr($text, 0, $start);
|
||||
$middle = base64_encode(substr($text, $start+$l1, ($end-$start-$l1)));
|
||||
$ending = substr($text, $end + $l2, (strlen($text)-$end+$l2));
|
||||
$middle = base64_encode(substr($text, $start + $l1, ($end - $start - $l1)));
|
||||
$ending = substr($text, $end + $l2, (strlen($text) - $end + $l2));
|
||||
|
||||
$text = $beginning . "[code!]" . $middle . "[/code!]" . $ending;
|
||||
}
|
||||
@@ -155,10 +161,10 @@ class BBCode extends FormatterExtension
|
||||
}
|
||||
|
||||
$beginning = substr($text, 0, $start);
|
||||
$middle = base64_decode(substr($text, $start+$l1, ($end-$start-$l1)));
|
||||
$ending = substr($text, $end + $l2, (strlen($text)-$end+$l2));
|
||||
$middle = base64_decode(substr($text, $start + $l1, ($end - $start - $l1)));
|
||||
$ending = substr($text, $end + $l2, (strlen($text) - $end + $l2));
|
||||
|
||||
$text = $beginning . "<pre>" . $middle . "</pre>" . $ending;
|
||||
$text = $beginning . "<pre class='code'>" . $middle . "</pre>" . $ending;
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
$(".shm-clink").each(function(idx, elm) {
|
||||
var target_id = $(elm).data("clink-sel");
|
||||
if(target_id && $(target_id).length > 0) {
|
||||
document.querySelectorAll(".shm-clink").forEach(function(el) {
|
||||
var target_id = el.getAttribute("data-clink-sel");
|
||||
if(target_id && document.querySelectorAll(target_id).length > 0) {
|
||||
// if the target comment is already on this page, don't bother
|
||||
// switching pages
|
||||
$(elm).attr("href", target_id);
|
||||
el.setAttribute("href", target_id);
|
||||
|
||||
// highlight it when clicked
|
||||
$(elm).click(function(e) {
|
||||
el.addEventListener("click", function(e) {
|
||||
// This needs jQuery UI
|
||||
$(target_id).highlight();
|
||||
});
|
||||
|
||||
// vanilla target name should already be in the URL tag, but this
|
||||
// will include the anon ID as displayed on screen
|
||||
$(elm).html("@"+$(target_id+" .username").html());
|
||||
el.innerHTML = "@"+document.querySelector(target_id+" .username").innerHTML;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
|
||||
CODE {
|
||||
background: #DEDEDE;
|
||||
font-size: 0.8em;
|
||||
.bbcode PRE.code {
|
||||
background: #DEDEDE;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
BLOCKQUOTE {
|
||||
.bbcode BLOCKQUOTE {
|
||||
border: 1px solid black;
|
||||
padding: 8px;
|
||||
background: #DDD;
|
||||
}
|
||||
.anchor A.alink {
|
||||
.bbcode .anchor A.alink {
|
||||
visibility: hidden;
|
||||
}
|
||||
.anchor:hover A.alink {
|
||||
.bbcode .anchor:hover A.alink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testBasics()
|
||||
public function testBasics(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
"<b>bold</b><i>italic</i>",
|
||||
@@ -14,7 +14,7 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testStacking()
|
||||
public function testStacking(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
"<b>B</b><i>I</i><b>B</b>",
|
||||
@@ -26,7 +26,7 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testFailure()
|
||||
public function testFailure(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
"[b]bold[i]italic",
|
||||
@@ -34,15 +34,15 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testCode()
|
||||
public function testCode(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
"<pre>[b]bold[/b]</pre>",
|
||||
"<pre class='code'>[b]bold[/b]</pre>",
|
||||
$this->filter("[code][b]bold[/b][/code]")
|
||||
);
|
||||
}
|
||||
|
||||
public function testNestedList()
|
||||
public function testNestedList(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
"<ul><li>a<ul><li>a<li>b</ul><li>b</ul>",
|
||||
@@ -54,7 +54,7 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testSpoiler()
|
||||
public function testSpoiler(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
"<span style=\"background-color:#000; color:#000;\">ShishNet</span>",
|
||||
@@ -69,7 +69,7 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
# "[spoiler]ShishNet");
|
||||
}
|
||||
|
||||
public function testURL()
|
||||
public function testURL(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
"<a href=\"https://shishnet.org\">https://shishnet.org</a>",
|
||||
@@ -85,7 +85,7 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testEmailURL()
|
||||
public function testEmailURL(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
"<a href=\"mailto:spam@shishnet.org\">spam@shishnet.org</a>",
|
||||
@@ -93,7 +93,7 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testAnchor()
|
||||
public function testAnchor(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
'<span class="anchor">Rules <a class="alink" href="#bb-rules" name="bb-rules" title="link to this anchor"> ¶ </a></span>',
|
||||
@@ -101,19 +101,19 @@ class BBCodeTest extends ShimmiePHPUnitTestCase
|
||||
);
|
||||
}
|
||||
|
||||
private function filter($in): string
|
||||
private function filter(string $in): string
|
||||
{
|
||||
$bb = new BBCode();
|
||||
return $bb->format($in);
|
||||
return $bb->_format($in);
|
||||
}
|
||||
|
||||
private function strip($in): string
|
||||
private function strip(string $in): string
|
||||
{
|
||||
$bb = new BBCode();
|
||||
return $bb->strip($in);
|
||||
}
|
||||
|
||||
public function testSiteLinks()
|
||||
public function testSiteLinks(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
'<a class="shm-clink" data-clink-sel="" href="/test/post/view/123">>>123</a>',
|
||||
|
||||
@@ -9,7 +9,7 @@ class Biography extends Extension
|
||||
/** @var BiographyTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onUserPageBuilding(UserPageBuildingEvent $event)
|
||||
public function onUserPageBuilding(UserPageBuildingEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
$duser = $event->display_user;
|
||||
@@ -23,7 +23,7 @@ class Biography extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $user, $user_config;
|
||||
if ($event->page_matches("biography", method: "POST")) {
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace Shimmie2;
|
||||
|
||||
class BiographyTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testBio()
|
||||
public function testBio(): void
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
$this->post_page("biography", ["biography"=>"My bio goes here"]);
|
||||
$this->post_page("biography", ["biography" => "My bio goes here"]);
|
||||
$this->get_page("user/" . self::$user_name);
|
||||
$this->assert_text("My bio goes here");
|
||||
|
||||
|
||||
@@ -8,12 +8,12 @@ use function MicroHTML\TEXTAREA;
|
||||
|
||||
class BiographyTheme extends Themelet
|
||||
{
|
||||
public function display_biography(Page $page, string $bio)
|
||||
public function display_biography(Page $page, string $bio): void
|
||||
{
|
||||
$page->add_block(new Block("About Me", format_text($bio), "main", 30, "about-me"));
|
||||
}
|
||||
|
||||
public function display_composer(Page $page, string $bio)
|
||||
public function display_composer(Page $page, string $bio): void
|
||||
{
|
||||
$html = SHM_SIMPLE_FORM(
|
||||
"biography",
|
||||
|
||||
@@ -9,7 +9,7 @@ class Blocks extends Extension
|
||||
/** @var BlocksTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
if ($this->get_version("ext_blocks_version") < 1) {
|
||||
@@ -31,17 +31,17 @@ class Blocks extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($event->parent==="system") {
|
||||
if ($event->parent === "system") {
|
||||
if ($user->can(Permissions::MANAGE_BLOCKS)) {
|
||||
$event->add_nav_link("blocks", new Link('blocks/list'), "Blocks Editor");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::MANAGE_BLOCKS)) {
|
||||
@@ -49,15 +49,11 @@ class Blocks extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $cache, $database, $page, $user;
|
||||
|
||||
$blocks = $cache->get("blocks");
|
||||
if (is_null($blocks)) {
|
||||
$blocks = $database->get_all("SELECT * FROM blocks");
|
||||
$cache->set("blocks", $blocks, 600);
|
||||
}
|
||||
$blocks = cache_get_or_set("blocks", fn () => $database->get_all("SELECT * FROM blocks"), 600);
|
||||
foreach ($blocks as $block) {
|
||||
$path = implode("/", $event->args);
|
||||
if (strlen($path) < 4000 && fnmatch($block['pages'], $path)) {
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class BlocksTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testBlocks()
|
||||
public function testBlocks(): void
|
||||
{
|
||||
$this->log_in_as_admin();
|
||||
$this->get_page("blocks/list");
|
||||
|
||||
@@ -16,35 +16,38 @@ use function MicroHTML\OPTION;
|
||||
|
||||
class BlocksTheme extends Themelet
|
||||
{
|
||||
public function display_blocks($blocks)
|
||||
/**
|
||||
* @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;
|
||||
|
||||
$html = TABLE(["class"=>"form", "style"=>"width: 100%;"]);
|
||||
$html = TABLE(["class" => "form", "style" => "width: 100%;"]);
|
||||
foreach ($blocks as $block) {
|
||||
$html->appendChild(SHM_SIMPLE_FORM(
|
||||
"blocks/update",
|
||||
TR(
|
||||
INPUT(["type"=>"hidden", "name"=>"id", "value"=>$block['id']]),
|
||||
INPUT(["type" => "hidden", "name" => "id", "value" => $block['id']]),
|
||||
TH("Title"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"title", "value"=>$block['title']])),
|
||||
TD(INPUT(["type" => "text", "name" => "title", "value" => $block['title']])),
|
||||
TH("Area"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"area", "value"=>$block['area']])),
|
||||
TD(INPUT(["type" => "text", "name" => "area", "value" => $block['area']])),
|
||||
TH("Priority"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"priority", "value"=>$block['priority']])),
|
||||
TD(INPUT(["type" => "text", "name" => "priority", "value" => $block['priority']])),
|
||||
TH("User Class"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"userclass", "value"=>$block['userclass']])),
|
||||
TD(INPUT(["type" => "text", "name" => "userclass", "value" => $block['userclass']])),
|
||||
TH("Pages"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"pages", "value"=>$block['pages']])),
|
||||
TD(INPUT(["type" => "text", "name" => "pages", "value" => $block['pages']])),
|
||||
TH("Delete"),
|
||||
TD(INPUT(["type"=>"checkbox", "name"=>"delete"])),
|
||||
TD(INPUT(["type"=>"submit", "value"=>"Save"]))
|
||||
TD(INPUT(["type" => "checkbox", "name" => "delete"])),
|
||||
TD(INPUT(["type" => "submit", "value" => "Save"]))
|
||||
),
|
||||
TR(
|
||||
TD(["colspan"=>"13"], TEXTAREA(["rows"=>"5", "name"=>"content"], $block['content']))
|
||||
TD(["colspan" => "13"], TEXTAREA(["rows" => "5", "name" => "content"], $block['content']))
|
||||
),
|
||||
TR(
|
||||
TD(["colspan"=>"13"], rawHTML(" "))
|
||||
TD(["colspan" => "13"], rawHTML(" "))
|
||||
),
|
||||
));
|
||||
}
|
||||
@@ -53,19 +56,19 @@ class BlocksTheme extends Themelet
|
||||
"blocks/add",
|
||||
TR(
|
||||
TH("Title"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"title", "value"=>""])),
|
||||
TD(INPUT(["type" => "text", "name" => "title", "value" => ""])),
|
||||
TH("Area"),
|
||||
TD(SELECT(["name"=>"area"], OPTION("left"), OPTION("main"))),
|
||||
TD(SELECT(["name" => "area"], OPTION("left"), OPTION("main"))),
|
||||
TH("Priority"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"priority", "value"=>'50'])),
|
||||
TD(INPUT(["type" => "text", "name" => "priority", "value" => '50'])),
|
||||
TH("User Class"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"userclass", "value"=>""])),
|
||||
TD(INPUT(["type" => "text", "name" => "userclass", "value" => ""])),
|
||||
TH("Pages"),
|
||||
TD(INPUT(["type"=>"text", "name"=>"pages", "value"=>'post/list*'])),
|
||||
TD(["colspan"=>'3'], INPUT(["type"=>"submit", "value"=>"Add"]))
|
||||
TD(INPUT(["type" => "text", "name" => "pages", "value" => 'post/list*'])),
|
||||
TD(["colspan" => '3'], INPUT(["type" => "submit", "value" => "Add"]))
|
||||
),
|
||||
TR(
|
||||
TD(["colspan"=>"13"], TEXTAREA(["rows"=>"5", "name"=>"content"]))
|
||||
TD(["colspan" => "13"], TEXTAREA(["rows" => "5", "name" => "content"]))
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
@@ -11,10 +11,8 @@ class BlotterInfo extends ExtensionInfo
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Blotter";
|
||||
public string $url = "http://seemslegit.com/";
|
||||
public array $authors = ["Zach Hall"=>"zach@sosguy.net"];
|
||||
public array $authors = ["Zach Hall" => "zach@sosguy.net"];
|
||||
public string $license = self::LICENSE_GPLV2;
|
||||
public string $description = "Displays brief updates about whatever you want on every page.
|
||||
Colors and positioning can be configured to match your site's design.
|
||||
|
||||
Development TODO at https://github.com/zshall/shimmie2/issues";
|
||||
public string $description = "Displays brief updates about whatever you want on every page.";
|
||||
public ?string $documentation = "Colors and positioning can be configured to match your site's design.<p>Development TODO at https://github.com/zshall/shimmie2/issues";
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ class Blotter extends Extension
|
||||
/** @var BlotterTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_int("blotter_recent", 5);
|
||||
@@ -17,7 +17,7 @@ class Blotter extends Extension
|
||||
$config->set_default_string("blotter_position", "subheading");
|
||||
}
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
@@ -31,7 +31,7 @@ class Blotter extends Extension
|
||||
// Insert sample data:
|
||||
$database->execute(
|
||||
"INSERT INTO blotter (entry_date, entry_text, important) VALUES (now(), :text, :important)",
|
||||
["text"=>"Installed the blotter extension!", "important"=>true]
|
||||
["text" => "Installed the blotter extension!", "important" => true]
|
||||
);
|
||||
log_info("blotter", "Installed tables for blotter extension.");
|
||||
$this->set_version("blotter_version", 2);
|
||||
@@ -42,7 +42,7 @@ class Blotter extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Blotter");
|
||||
$sb->add_int_option("blotter_recent", "<br />Number of recent entries to display: ");
|
||||
@@ -50,10 +50,10 @@ class Blotter extends Extension
|
||||
$sb->add_choice_option("blotter_position", ["Top of page" => "subheading", "In navigation bar" => "left"], "<br>Position: ");
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($event->parent==="system") {
|
||||
if ($event->parent === "system") {
|
||||
if ($user->can(Permissions::BLOTTER_ADMIN)) {
|
||||
$event->add_nav_link("blotter", new Link('blotter/editor'), "Blotter Editor");
|
||||
}
|
||||
@@ -61,7 +61,7 @@ class Blotter extends Extension
|
||||
}
|
||||
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::BLOTTER_ADMIN)) {
|
||||
@@ -69,7 +69,7 @@ class Blotter extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $database, $user;
|
||||
if ($event->page_matches("blotter/editor", method: "GET", permission: Permissions::BLOTTER_ADMIN)) {
|
||||
@@ -105,7 +105,7 @@ class Blotter extends Extension
|
||||
$this->display_blotter();
|
||||
}
|
||||
|
||||
private function display_blotter()
|
||||
private function display_blotter(): void
|
||||
{
|
||||
global $database, $config;
|
||||
$entries = $database->get_all(
|
||||
|
||||
@@ -4,14 +4,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
$(".shm-blotter2-toggle").click(function() {
|
||||
$(".shm-blotter2").slideToggle("slow", function() {
|
||||
if($(".shm-blotter2").is(":hidden")) {
|
||||
Cookies.set("ui-blotter2-hidden", 'true');
|
||||
shm_cookie_set("ui-blotter2-hidden", 'true');
|
||||
}
|
||||
else {
|
||||
Cookies.set("ui-blotter2-hidden", 'false');
|
||||
shm_cookie_set("ui-blotter2-hidden", 'false');
|
||||
}
|
||||
});
|
||||
});
|
||||
if(Cookies.get("ui-blotter2-hidden") === 'true') {
|
||||
if(shm_cookie_get("ui-blotter2-hidden") === 'true') {
|
||||
$(".shm-blotter2").hide();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class BlotterTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testDenial()
|
||||
public function testDenial(): void
|
||||
{
|
||||
$this->assertException(PermissionDenied::class, function () {
|
||||
$this->get_page("blotter/editor");
|
||||
@@ -19,7 +19,7 @@ class BlotterTest extends ShimmiePHPUnitTestCase
|
||||
});
|
||||
}
|
||||
|
||||
public function testAddViewRemove()
|
||||
public function testAddViewRemove(): void
|
||||
{
|
||||
$this->log_in_as_admin();
|
||||
|
||||
|
||||
@@ -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)
|
||||
/**
|
||||
* @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)
|
||||
/**
|
||||
* @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;
|
||||
@@ -103,6 +118,9 @@ class BlotterTheme extends Themelet
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlotterEntry[] $entries
|
||||
*/
|
||||
private function get_html_for_blotter_page(array $entries): string
|
||||
{
|
||||
/**
|
||||
@@ -126,7 +144,7 @@ class BlotterTheme extends Themelet
|
||||
$entry_text = $entries[$i]['entry_text'];
|
||||
if ($entries[$i]['important'] == 'Y') {
|
||||
$i_open = "<span style='color: #$i_color;'>";
|
||||
$i_close="</span>";
|
||||
$i_close = "</span>";
|
||||
}
|
||||
$html .= "{$i_open}{$clean_date} - {$entry_text}{$i_close}<br /><br />";
|
||||
}
|
||||
@@ -134,6 +152,9 @@ class BlotterTheme extends Themelet
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlotterEntry[] $entries
|
||||
*/
|
||||
private function get_html_for_blotter(array $entries): string
|
||||
{
|
||||
global $config;
|
||||
@@ -153,7 +174,7 @@ class BlotterTheme extends Themelet
|
||||
$entry_text = $entry['entry_text'];
|
||||
if ($entry['important'] == 'Y') {
|
||||
$i_open = "<span style='color: #$i_color'>";
|
||||
$i_close="</span>";
|
||||
$i_close = "</span>";
|
||||
}
|
||||
$entries_list .= "<li>{$i_open}{$clean_date} - {$entry_text}{$i_close}</li>";
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class BrowserSearchInfo extends ExtensionInfo
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Browser Search";
|
||||
public string $url = "http://atravelinggeek.com/";
|
||||
public array $authors = ["ATravelingGeek"=>"atg@atravelinggeek.com"];
|
||||
public array $authors = ["ATravelingGeek" => "atg@atravelinggeek.com"];
|
||||
public string $license = self::LICENSE_GPLV2;
|
||||
public ExtensionCategory $category = ExtensionCategory::INTEGRATION;
|
||||
public string $description = "Allows the user to add a browser 'plugin' to search the site with real-time suggestions";
|
||||
|
||||
@@ -6,13 +6,13 @@ namespace Shimmie2;
|
||||
|
||||
class BrowserSearch extends Extension
|
||||
{
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_string("search_suggestions_results_order", 'a');
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $database, $page;
|
||||
|
||||
@@ -26,7 +26,7 @@ class BrowserSearch extends Extension
|
||||
if ($event->page_matches("browser_search.xml")) {
|
||||
// First, we need to build all the variables we'll need
|
||||
$search_title = $config->get_string(SetupConfig::TITLE);
|
||||
$search_form_url = make_link('post/list/{searchTerms}');
|
||||
$search_form_url = search_link(['{searchTerms}']);
|
||||
$suggenton_url = make_link('browser_search/')."{searchTerms}";
|
||||
$icon_b64 = base64_encode(\Safe\file_get_contents("ext/static_files/static/favicon.ico"));
|
||||
|
||||
@@ -65,7 +65,7 @@ class BrowserSearch extends Extension
|
||||
}
|
||||
$tags = $database->get_col(
|
||||
"SELECT tag FROM tags WHERE tag LIKE :tag AND count > 0 ORDER BY $order LIMIT 30",
|
||||
['tag'=>$tag_search."%"]
|
||||
['tag' => $tag_search."%"]
|
||||
);
|
||||
|
||||
// And to do stuff with it. We want our output to look like:
|
||||
@@ -75,7 +75,7 @@ class BrowserSearch extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sort_by = [];
|
||||
$sort_by['Alphabetical'] = 'a';
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class BrowserSearchTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testBasic()
|
||||
public function testBasic(): void
|
||||
{
|
||||
$page = $this->get_page("browser_search.xml");
|
||||
$this->assertEquals(200, $page->code);
|
||||
|
||||
@@ -10,7 +10,7 @@ class BulkActionsInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Bulk Actions";
|
||||
public array $authors = ["Matthew Barbour"=>"matthew@darkholme.net"];
|
||||
public array $authors = ["Matthew Barbour" => "matthew@darkholme.net"];
|
||||
public string $license = self::LICENSE_WTFPL;
|
||||
public string $description = "Provides query and selection-based bulk action support";
|
||||
public ?string $documentation = "Provides bulk action section in list view. Allows performing actions against a set of posts based on query or manual selection. Based on Mass Tagger by <a href='mailto:walde.christian@googlemail.com'>Christian Walde</a>, contributions by Shish and Agasa.
|
||||
|
||||
@@ -10,13 +10,17 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
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);
|
||||
assert(strlen($access_key) == 1);
|
||||
foreach ($this->actions as $existing) {
|
||||
if ($existing["access_key"] == $access_key) {
|
||||
throw new UserError("Access key $access_key is already in use");
|
||||
@@ -24,14 +28,14 @@ class BulkActionBlockBuildingEvent extends Event
|
||||
}
|
||||
}
|
||||
|
||||
$this->actions[] =[
|
||||
"block" => $block,
|
||||
"access_key" => $access_key,
|
||||
"confirmation_message" => $confirmation_message,
|
||||
"action" => $action,
|
||||
"button_text" => $button_text,
|
||||
"position" => $position
|
||||
];
|
||||
$this->actions[] = [
|
||||
"block" => $block,
|
||||
"access_key" => $access_key,
|
||||
"confirmation_message" => $confirmation_message,
|
||||
"action" => $action,
|
||||
"button_text" => $button_text,
|
||||
"position" => $position
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +64,7 @@ class BulkActions extends Extension
|
||||
/** @var BulkActionsTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onPostListBuilding(PostListBuildingEvent $event)
|
||||
public function onPostListBuilding(PostListBuildingEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
@@ -80,7 +84,7 @@ class BulkActions extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event)
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
@@ -104,7 +108,7 @@ class BulkActions extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onCommand(CommandEvent $event)
|
||||
public function onCliGen(CliGenEvent $event): void
|
||||
{
|
||||
$event->app->register('bulk-action')
|
||||
->addArgument('action', InputArgument::REQUIRED)
|
||||
@@ -120,7 +124,7 @@ class BulkActions extends Extension
|
||||
});
|
||||
}
|
||||
|
||||
public function onBulkAction(BulkActionEvent $event)
|
||||
public function onBulkAction(BulkActionEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
@@ -142,7 +146,7 @@ class BulkActions extends Extension
|
||||
$replace = true;
|
||||
}
|
||||
|
||||
$i= $this->tag_items($event->items, $tags, $replace);
|
||||
$i = $this->tag_items($event->items, $tags, $replace);
|
||||
$page->flash("Tagged $i items");
|
||||
}
|
||||
break;
|
||||
@@ -159,7 +163,7 @@ class BulkActions extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
if ($event->page_matches("bulk_action", method: "POST", permission: Permissions::PERFORM_BULK_ACTIONS)) {
|
||||
@@ -188,29 +192,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 Image::find_images_iterable(0, null, $tags);
|
||||
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;
|
||||
@@ -218,7 +235,7 @@ class BulkActions extends Extension
|
||||
$size = 0;
|
||||
foreach ($posts as $post) {
|
||||
try {
|
||||
if (class_exists("Shimmie2\ImageBan") && isset($_POST['bulk_ban_reason'])) {
|
||||
if (Extension::is_enabled(ImageBanInfo::KEY) && isset($_POST['bulk_ban_reason'])) {
|
||||
$reason = $_POST['bulk_ban_reason'];
|
||||
if ($reason) {
|
||||
send_event(new AddImageHashBanEvent($post->hash, $reason));
|
||||
@@ -234,6 +251,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);
|
||||
@@ -274,7 +294,10 @@ class BulkActions extends Extension
|
||||
return $total;
|
||||
}
|
||||
|
||||
private function set_source(iterable $items, String $source): int
|
||||
/**
|
||||
* @param iterable<Image> $items
|
||||
*/
|
||||
private function set_source(iterable $items, string $source): int
|
||||
{
|
||||
global $page;
|
||||
$total = 0;
|
||||
|
||||
@@ -68,11 +68,11 @@ function get_selected_items() {
|
||||
}
|
||||
|
||||
function set_selected_items(items) {
|
||||
$(".shm-thumb").removeClass('selected');
|
||||
$(".shm-thumb").removeClass('bulk_selected');
|
||||
|
||||
$(items).each(
|
||||
function(index,item) {
|
||||
$('.shm-thumb[data-post-id="' + item + '"]').addClass('selected');
|
||||
$('.shm-thumb[data-post-id="' + item + '"]').addClass('bulk_selected');
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.selected {
|
||||
.bulk_selected {
|
||||
outline: 3px solid blue;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ namespace Shimmie2;
|
||||
|
||||
class BulkActionsTheme extends Themelet
|
||||
{
|
||||
public function display_selector(Page $page, array $actions, string $query)
|
||||
/**
|
||||
* @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' />
|
||||
<input id='bulk_selector_activate' type='button' onclick='activate_bulk_selector();' value='Activate (M)anual Select' accesskey='m'/>
|
||||
@@ -51,7 +54,7 @@ class BulkActionsTheme extends Themelet
|
||||
|
||||
public function render_ban_reason_input(): string
|
||||
{
|
||||
if (class_exists("Shimmie2\ImageBan")) {
|
||||
if (Extension::is_enabled(ImageBanInfo::KEY)) {
|
||||
return "<input type='text' name='bulk_ban_reason' placeholder='Ban reason (leave blank to not ban)' />";
|
||||
} else {
|
||||
return "";
|
||||
|
||||
@@ -4,9 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\{InputInterface,InputArgument};
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class BulkAddEvent extends Event
|
||||
{
|
||||
public string $dir;
|
||||
/** @var UploadResult[] */
|
||||
public array $results;
|
||||
|
||||
public function __construct(string $dir)
|
||||
@@ -22,7 +27,7 @@ class BulkAdd extends Extension
|
||||
/** @var BulkAddTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
if ($event->page_matches("bulk_add", method: "POST", permission: Permissions::BULK_ADD)) {
|
||||
@@ -33,7 +38,7 @@ class BulkAdd extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onCommand(CommandEvent $event)
|
||||
public function onCliGen(CliGenEvent $event): void
|
||||
{
|
||||
$event->app->register('bulk-add')
|
||||
->addArgument('directory', InputArgument::REQUIRED)
|
||||
@@ -52,18 +57,17 @@ class BulkAdd extends Extension
|
||||
});
|
||||
}
|
||||
|
||||
public function onAdminBuilding(AdminBuildingEvent $event)
|
||||
public function onAdminBuilding(AdminBuildingEvent $event): void
|
||||
{
|
||||
$this->theme->display_admin_block();
|
||||
}
|
||||
|
||||
public function onBulkAdd(BulkAddEvent $event)
|
||||
public function onBulkAdd(BulkAddEvent $event): void
|
||||
{
|
||||
if (is_dir($event->dir) && is_readable($event->dir)) {
|
||||
$event->results = add_dir($event->dir);
|
||||
} else {
|
||||
$h_dir = html_escape($event->dir);
|
||||
$event->results[] = "Error, $h_dir is not a readable directory";
|
||||
$event->results = [new UploadError($event->dir, "is not a readable directory")];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,14 @@ namespace Shimmie2;
|
||||
|
||||
class BulkAddTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testInvalidDir()
|
||||
public function testInvalidDir(): void
|
||||
{
|
||||
send_event(new UserLoginEvent(User::by_name(self::$admin_name)));
|
||||
$bae = send_event(new BulkAddEvent('asdf'));
|
||||
$this->assertContainsEquals(
|
||||
"Error, asdf is not a readable directory",
|
||||
$bae->results,
|
||||
implode("\n", $bae->results)
|
||||
);
|
||||
$this->assertTrue(is_a($bae->results[0], UploadError::class));
|
||||
}
|
||||
|
||||
public function testValidDir()
|
||||
public function testValidDir(): void
|
||||
{
|
||||
send_event(new UserLoginEvent(User::by_name(self::$admin_name)));
|
||||
send_event(new BulkAddEvent('tests'));
|
||||
|
||||
@@ -4,21 +4,27 @@ declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
|
||||
use function MicroHTML\{UL, LI};
|
||||
|
||||
class BulkAddTheme extends Themelet
|
||||
{
|
||||
private array $messages = [];
|
||||
|
||||
/*
|
||||
/**
|
||||
* Show a standard page for results to be put into
|
||||
*
|
||||
* @param UploadResult[] $results
|
||||
*/
|
||||
public function display_upload_results(Page $page)
|
||||
public function display_upload_results(Page $page, array $results): void
|
||||
{
|
||||
$page->set_title("Adding folder");
|
||||
$page->set_heading("Adding folder");
|
||||
$page->add_block(new NavBlock());
|
||||
$html = "";
|
||||
foreach ($this->messages as $block) {
|
||||
$html .= "<br/>" . $block->body;
|
||||
$html = UL();
|
||||
foreach ($results as $r) {
|
||||
if (is_a($r, UploadError::class)) {
|
||||
$html->appendChild(LI("{$r->name} failed: {$r->error}"));
|
||||
} else {
|
||||
$html->appendChild(LI("{$r->name} ok"));
|
||||
}
|
||||
}
|
||||
$page->add_block(new Block("Results", $html));
|
||||
}
|
||||
@@ -28,7 +34,7 @@ class BulkAddTheme extends Themelet
|
||||
* links to bulk_add with POST[dir] set to the name of a server-side
|
||||
* directory full of images
|
||||
*/
|
||||
public function display_admin_block()
|
||||
public function display_admin_block(): void
|
||||
{
|
||||
global $page;
|
||||
$html = "
|
||||
@@ -46,9 +52,4 @@ class BulkAddTheme extends Themelet
|
||||
";
|
||||
$page->add_block(new Block("Bulk Add", $html));
|
||||
}
|
||||
|
||||
public function add_status($title, $body)
|
||||
{
|
||||
$this->messages[] = new Block($title, $body);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class BulkDownloadInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Bulk Download";
|
||||
public array $authors = ["Matthew Barbour"=>"matthew@darkholme.net"];
|
||||
public array $authors = ["Matthew Barbour" => "matthew@darkholme.net"];
|
||||
public string $license = self::LICENSE_WTFPL;
|
||||
public ExtensionCategory $category = ExtensionCategory::FILE_HANDLING;
|
||||
public string $description = "Allows bulk downloading images.";
|
||||
|
||||
@@ -13,13 +13,13 @@ class BulkDownload extends Extension
|
||||
{
|
||||
private const DOWNLOAD_ACTION_NAME = "bulk_download";
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_int(BulkDownloadConfig::SIZE_LIMIT, parse_shorthand_int('100MB'));
|
||||
}
|
||||
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event)
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
@@ -28,7 +28,7 @@ class BulkDownload extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Bulk Download");
|
||||
|
||||
@@ -37,14 +37,14 @@ class BulkDownload extends Extension
|
||||
$sb->end_table();
|
||||
}
|
||||
|
||||
public function onBulkAction(BulkActionEvent $event)
|
||||
public function onBulkAction(BulkActionEvent $event): void
|
||||
{
|
||||
global $user, $page, $config;
|
||||
|
||||
if ($user->can(Permissions::BULK_DOWNLOAD)&&
|
||||
if ($user->can(Permissions::BULK_DOWNLOAD) &&
|
||||
($event->action == BulkDownload::DOWNLOAD_ACTION_NAME)) {
|
||||
$download_filename = $user->name . '-' . date('YmdHis') . '.zip';
|
||||
$zip_filename = tempnam(sys_get_temp_dir(), "shimmie_bulk_download");
|
||||
$zip_filename = shm_tempnam("bulk_download");
|
||||
$zip = new \ZipArchive();
|
||||
$size_total = 0;
|
||||
$max_size = $config->get_int(BulkDownloadConfig::SIZE_LIMIT);
|
||||
@@ -57,7 +57,6 @@ class BulkDownload extends Extension
|
||||
throw new UserError("Bulk download limited to ".human_filesize($max_size));
|
||||
}
|
||||
|
||||
|
||||
$filename = urldecode($image->get_nice_image_name());
|
||||
$filename = str_replace(":", ";", $filename);
|
||||
$zip->addFile($img_loc, $filename);
|
||||
|
||||
@@ -10,7 +10,7 @@ class BulkParentChildInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Bulk Parent Child";
|
||||
public array $authors = ["Flatty"=>""];
|
||||
public array $authors = ["Flatty" => ""];
|
||||
public string $license = self::LICENSE_WTFPL;
|
||||
public string $description = "Allows bulk setting of parent-child relationships, in order of manual selection";
|
||||
public array $dependencies = [BulkActionsInfo::KEY];
|
||||
|
||||
@@ -12,7 +12,7 @@ class BulkParentChild extends Extension
|
||||
{
|
||||
private const PARENT_CHILD_ACTION_NAME = "bulk_parent_child";
|
||||
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event)
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
@@ -21,10 +21,10 @@ class BulkParentChild extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onBulkAction(BulkActionEvent $event)
|
||||
public function onBulkAction(BulkActionEvent $event): void
|
||||
{
|
||||
global $user, $page, $config;
|
||||
if ($user->can(Permissions::BULK_PARENT_CHILD)&&
|
||||
if ($user->can(Permissions::BULK_PARENT_CHILD) &&
|
||||
($event->action == BulkParentChild::PARENT_CHILD_ACTION_NAME)) {
|
||||
$prev_id = null;
|
||||
foreach ($event->items as $image) {
|
||||
|
||||
@@ -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'];
|
||||
@@ -84,7 +87,7 @@ class Comment
|
||||
SELECT COUNT(*) AS count
|
||||
FROM comments
|
||||
WHERE owner_id=:owner_id
|
||||
", ["owner_id"=>$user->id]);
|
||||
", ["owner_id" => $user->id]);
|
||||
}
|
||||
|
||||
#[Field(name: "owner")]
|
||||
@@ -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
|
||||
{
|
||||
@@ -116,7 +122,7 @@ class CommentList extends Extension
|
||||
/** @var CommentListTheme $theme */
|
||||
public Themelet $theme;
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_int('comment_window', 5);
|
||||
@@ -126,7 +132,7 @@ class CommentList extends Extension
|
||||
$config->set_default_bool('comment_captcha', false);
|
||||
}
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
if ($this->get_version("ext_comments_version") < 3) {
|
||||
@@ -179,21 +185,21 @@ class CommentList extends Extension
|
||||
}
|
||||
|
||||
|
||||
public function onPageNavBuilding(PageNavBuildingEvent $event)
|
||||
public function onPageNavBuilding(PageNavBuildingEvent $event): void
|
||||
{
|
||||
$event->add_nav_link("comment", new Link('comment/list'), "Comments");
|
||||
}
|
||||
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
if ($event->parent=="comment") {
|
||||
if ($event->parent == "comment") {
|
||||
$event->add_nav_link("comment_list", new Link('comment/list'), "All");
|
||||
$event->add_nav_link("comment_help", new Link('ext_doc/comment'), "Help");
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $cache, $config, $database, $user, $page;
|
||||
if ($event->page_matches("comment/add", method: "POST", permission: Permissions::CREATE_COMMENT)) {
|
||||
@@ -295,28 +301,24 @@ class CommentList extends Extension
|
||||
$event->add_disallow("comment");
|
||||
}
|
||||
|
||||
public function onAdminBuilding(AdminBuildingEvent $event)
|
||||
public function onAdminBuilding(AdminBuildingEvent $event): void
|
||||
{
|
||||
$this->theme->display_admin_block();
|
||||
}
|
||||
|
||||
public function onPostListBuilding(PostListBuildingEvent $event)
|
||||
public function onPostListBuilding(PostListBuildingEvent $event): void
|
||||
{
|
||||
global $cache, $config;
|
||||
$cc = $config->get_int("comment_count");
|
||||
if ($cc > 0) {
|
||||
$recent = $cache->get("recent_comments");
|
||||
if (is_null($recent)) {
|
||||
$recent = $this->get_recent_comments($cc);
|
||||
$cache->set("recent_comments", $recent, 60);
|
||||
}
|
||||
$recent = cache_get_or_set("recent_comments", fn () => $this->get_recent_comments($cc), 60);
|
||||
if (count($recent) > 0) {
|
||||
$this->theme->display_recent_comments($recent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function onUserPageBuilding(UserPageBuildingEvent $event)
|
||||
public function onUserPageBuilding(UserPageBuildingEvent $event): void
|
||||
{
|
||||
$i_days_old = ((time() - \Safe\strtotime($event->display_user->join_date)) / 86400) + 1;
|
||||
$i_comment_count = Comment::count_comments_by_user($event->display_user);
|
||||
@@ -327,7 +329,7 @@ class CommentList extends Extension
|
||||
$this->theme->display_recent_user_comments($recent, $event->display_user);
|
||||
}
|
||||
|
||||
public function onDisplayingImage(DisplayingImageEvent $event)
|
||||
public function onDisplayingImage(DisplayingImageEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
$this->theme->display_image_comments(
|
||||
@@ -338,22 +340,22 @@ class CommentList extends Extension
|
||||
}
|
||||
|
||||
// TODO: split akismet into a separate class, which can veto the event
|
||||
public function onCommentPosting(CommentPostingEvent $event)
|
||||
public function onCommentPosting(CommentPostingEvent $event): void
|
||||
{
|
||||
$this->add_comment_wrapper($event->image_id, $event->user, $event->comment);
|
||||
}
|
||||
|
||||
public function onCommentDeletion(CommentDeletionEvent $event)
|
||||
public function onCommentDeletion(CommentDeletionEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("
|
||||
DELETE FROM comments
|
||||
WHERE id=:comment_id
|
||||
", ["comment_id"=>$event->comment_id]);
|
||||
", ["comment_id" => $event->comment_id]);
|
||||
log_info("comment", "Deleting Comment #{$event->comment_id}");
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Comment Options");
|
||||
$sb->add_bool_option("comment_captcha", "Require CAPTCHA for anonymous comments: ");
|
||||
@@ -372,7 +374,7 @@ class CommentList extends Extension
|
||||
$sb->add_bool_option("comment_samefags_public");
|
||||
}
|
||||
|
||||
public function onSearchTermParse(SearchTermParseEvent $event)
|
||||
public function onSearchTermParse(SearchTermParseEvent $event): void
|
||||
{
|
||||
if (is_null($event->term)) {
|
||||
return;
|
||||
@@ -392,9 +394,9 @@ class CommentList extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onHelpPageBuilding(HelpPageBuildingEvent $event)
|
||||
public function onHelpPageBuilding(HelpPageBuildingEvent $event): void
|
||||
{
|
||||
if ($event->key===HelpPages::SEARCH) {
|
||||
if ($event->key === HelpPages::SEARCH) {
|
||||
$block = new Block();
|
||||
$block->header = "Comments";
|
||||
$block->body = $this->theme->get_help_html();
|
||||
@@ -403,7 +405,8 @@ class CommentList extends Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* #return Comment[]
|
||||
* @param array<string,mixed> $args
|
||||
* @return Comment[]
|
||||
*/
|
||||
private static function get_generic_comments(string $query, array $args): array
|
||||
{
|
||||
@@ -417,7 +420,7 @@ class CommentList extends Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* #return Comment[]
|
||||
* @return Comment[]
|
||||
*/
|
||||
private static function get_recent_comments(int $count): array
|
||||
{
|
||||
@@ -431,13 +434,13 @@ class CommentList extends Extension
|
||||
LEFT JOIN users ON comments.owner_id=users.id
|
||||
ORDER BY comments.id DESC
|
||||
LIMIT :limit
|
||||
", ["limit"=>$count]);
|
||||
", ["limit" => $count]);
|
||||
}
|
||||
|
||||
/**
|
||||
* #return Comment[]
|
||||
* @return Comment[]
|
||||
*/
|
||||
private static function get_user_comments(int $user_id, int $count, int $offset=0): array
|
||||
private static function get_user_comments(int $user_id, int $count, int $offset = 0): array
|
||||
{
|
||||
return CommentList::get_generic_comments("
|
||||
SELECT
|
||||
@@ -450,12 +453,12 @@ class CommentList extends Extension
|
||||
WHERE users.id = :user_id
|
||||
ORDER BY comments.id DESC
|
||||
LIMIT :limit OFFSET :offset
|
||||
", ["user_id"=>$user_id, "offset"=>$offset, "limit"=>$count]);
|
||||
", ["user_id" => $user_id, "offset" => $offset, "limit" => $count]);
|
||||
}
|
||||
|
||||
/**
|
||||
* public just for Image::get_comments()
|
||||
* #return Comment[]
|
||||
* @return Comment[]
|
||||
*/
|
||||
public static function get_comments(int $image_id): array
|
||||
{
|
||||
@@ -469,7 +472,7 @@ class CommentList extends Extension
|
||||
LEFT JOIN users ON comments.owner_id=users.id
|
||||
WHERE comments.image_id=:image_id
|
||||
ORDER BY comments.id ASC
|
||||
", ["image_id"=>$image_id]);
|
||||
", ["image_id" => $image_id]);
|
||||
}
|
||||
|
||||
private function is_comment_limit_hit(): bool
|
||||
@@ -495,7 +498,7 @@ class CommentList extends Extension
|
||||
SELECT *
|
||||
FROM comments
|
||||
WHERE owner_ip = :remote_ip AND posted > now() - $window_sql
|
||||
", ["remote_ip"=>get_real_ip()]);
|
||||
", ["remote_ip" => get_real_ip()]);
|
||||
|
||||
return (count($result) >= $max);
|
||||
}
|
||||
@@ -515,7 +518,8 @@ class CommentList extends Extension
|
||||
private function is_spam_akismet(string $text): bool
|
||||
{
|
||||
global $config, $user;
|
||||
if (strlen($config->get_string('comment_wordpress_key')) > 0) {
|
||||
$key = $config->get_string('comment_wordpress_key');
|
||||
if (!is_null($key) && strlen($key) > 0) {
|
||||
$comment = [
|
||||
'author' => $user->name,
|
||||
'email' => $user->email,
|
||||
@@ -527,11 +531,7 @@ class CommentList extends Extension
|
||||
];
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
$akismet = new \Akismet(
|
||||
$_SERVER['SERVER_NAME'],
|
||||
$config->get_string('comment_wordpress_key'),
|
||||
$comment
|
||||
);
|
||||
$akismet = new \Akismet($_SERVER['SERVER_NAME'], $key, $comment);
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
if ($akismet->errorsExist()) {
|
||||
@@ -552,11 +552,11 @@ class CommentList extends Extension
|
||||
SELECT *
|
||||
FROM comments
|
||||
WHERE image_id=:image_id AND comment=:comment
|
||||
", ["image_id"=>$image_id, "comment"=>$comment]);
|
||||
", ["image_id" => $image_id, "comment" => $comment]);
|
||||
}
|
||||
// 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;
|
||||
|
||||
@@ -567,12 +567,12 @@ class CommentList extends Extension
|
||||
|
||||
// all checks passed
|
||||
if ($user->is_anonymous()) {
|
||||
$page->add_cookie("nocache", "Anonymous Commenter", time()+60*60*24, "/");
|
||||
$page->add_cookie("nocache", "Anonymous Commenter", time() + 60 * 60 * 24, "/");
|
||||
}
|
||||
$database->execute(
|
||||
"INSERT INTO comments(image_id, owner_id, owner_ip, posted, comment) ".
|
||||
"VALUES(:image_id, :user_id, :remote_addr, now(), :comment)",
|
||||
["image_id"=>$image_id, "user_id"=>$user->id, "remote_addr"=>get_real_ip(), "comment"=>$comment]
|
||||
["image_id" => $image_id, "user_id" => $user->id, "remote_addr" => get_real_ip(), "comment" => $comment]
|
||||
);
|
||||
$cid = $database->get_last_insert_id('comments_id_seq');
|
||||
$snippet = substr($comment, 0, 100);
|
||||
@@ -581,7 +581,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;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
function replyTo(imageId, commentId, userId) {
|
||||
var box = $("#comment_on_"+imageId);
|
||||
var box = document.getElementById("comment_on_"+imageId);
|
||||
var text = "[url=site://post/view/"+imageId+"#c"+commentId+"]@"+userId+"[/url]: ";
|
||||
|
||||
box.focus();
|
||||
box.val(box.val() + text);
|
||||
box.value += text;
|
||||
$("#c"+commentId).highlight();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class CommentListTest extends ShimmiePHPUnitTestCase
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testCommentsPage()
|
||||
public function testCommentsPage(): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
@@ -90,7 +90,7 @@ class CommentListTest extends ShimmiePHPUnitTestCase
|
||||
$this->assert_no_text('ASDFASDF');
|
||||
}
|
||||
|
||||
public function testSingleDel()
|
||||
public function testSingleDel(): void
|
||||
{
|
||||
global $database, $user;
|
||||
|
||||
|
||||
@@ -8,12 +8,15 @@ 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)
|
||||
public function display_comment_list(array $images, int $page_number, int $total_pages, bool $can_post): void
|
||||
{
|
||||
global $config, $page, $user;
|
||||
|
||||
@@ -29,7 +32,7 @@ class CommentListTheme extends Themelet
|
||||
|
||||
$h_prev = ($page_number <= 1) ? "Prev" :
|
||||
'<a href="'.make_link('comment/list/'.$prev).'">Prev</a>';
|
||||
$h_index = "<a href='".make_link("post/list")."'>Index</a>";
|
||||
$h_index = "<a href='".make_link()."'>Index</a>";
|
||||
$h_next = ($page_number >= $total_pages) ? "Next" :
|
||||
'<a href="'.make_link('comment/list/'.$next).'">Next</a>';
|
||||
|
||||
@@ -56,7 +59,7 @@ class CommentListTheme extends Themelet
|
||||
$comment_count = count($comments);
|
||||
if ($comment_limit > 0 && $comment_count > $comment_limit) {
|
||||
$comment_html .= "<p>showing $comment_limit of $comment_count comments</p>";
|
||||
$comments = array_slice($comments, -$comment_limit);
|
||||
$comments = array_slice($comments, negative_int($comment_limit));
|
||||
$this->show_anon_id = false;
|
||||
} else {
|
||||
$this->show_anon_id = true;
|
||||
@@ -91,7 +94,7 @@ class CommentListTheme extends Themelet
|
||||
}
|
||||
}
|
||||
|
||||
public function display_admin_block()
|
||||
public function display_admin_block(): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
@@ -111,9 +114,9 @@ class CommentListTheme extends Themelet
|
||||
/**
|
||||
* Add some comments to the page, probably in a sidebar.
|
||||
*
|
||||
* #param Comment[] $comments An array of Comment objects to be shown
|
||||
* @param Comment[] $comments An array of Comment objects to be shown
|
||||
*/
|
||||
public function display_recent_comments(array $comments)
|
||||
public function display_recent_comments(array $comments): void
|
||||
{
|
||||
global $page;
|
||||
$this->show_anon_id = false;
|
||||
@@ -128,9 +131,9 @@ class CommentListTheme extends Themelet
|
||||
/**
|
||||
* Show comments for an image.
|
||||
*
|
||||
* #param Comment[] $comments
|
||||
* @param Comment[] $comments
|
||||
*/
|
||||
public function display_image_comments(Image $image, array $comments, bool $postbox)
|
||||
public function display_image_comments(Image $image, array $comments, bool $postbox): void
|
||||
{
|
||||
global $page;
|
||||
$this->show_anon_id = true;
|
||||
@@ -147,9 +150,9 @@ class CommentListTheme extends Themelet
|
||||
/**
|
||||
* Show comments made by a user.
|
||||
*
|
||||
* #param Comment[] $comments
|
||||
* @param Comment[] $comments
|
||||
*/
|
||||
public function display_recent_user_comments(array $comments, User $user)
|
||||
public function display_recent_user_comments(array $comments, User $user): void
|
||||
{
|
||||
global $page;
|
||||
$html = "";
|
||||
@@ -164,7 +167,10 @@ class CommentListTheme extends Themelet
|
||||
$page->add_block(new Block("Comments", $html, "left", 70, "comment-list-user"));
|
||||
}
|
||||
|
||||
public function display_all_user_comments(array $comments, int $page_number, int $total_pages, User $user)
|
||||
/**
|
||||
* @param Comment[] $comments
|
||||
*/
|
||||
public function display_all_user_comments(array $comments, int $page_number, int $total_pages, User $user): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
@@ -186,7 +192,7 @@ class CommentListTheme extends Themelet
|
||||
//$query = empty($u_tags) ? "" : '/'.$u_tags;
|
||||
|
||||
$h_prev = ($page_number <= 1) ? "Prev" : "<a href='$prev'>Prev</a>";
|
||||
$h_index = "<a href='".make_link("post/list")."'>Index</a>";
|
||||
$h_index = "<a href='".make_link()."'>Index</a>";
|
||||
$h_next = ($page_number >= $total_pages) ? "Next" : "<a href='$next'>Next</a>";
|
||||
|
||||
$page->set_title(html_escape($user->name)."'s comments");
|
||||
@@ -194,7 +200,7 @@ class CommentListTheme extends Themelet
|
||||
$this->display_paginator($page, "comment/beta-search/{$user->name}", null, $page_number, $total_pages);
|
||||
}
|
||||
|
||||
protected function comment_to_html(Comment $comment, bool $trim=false): string
|
||||
protected function comment_to_html(Comment $comment, bool $trim = false): string
|
||||
{
|
||||
global $config, $user;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class CronUploaderInfo extends ExtensionInfo
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Cron Uploader";
|
||||
public string $url = self::SHIMMIE_URL;
|
||||
public array $authors = ["YaoiFox"=>"admin@yaoifox.com", "Matthew Barbour"=>"matthew@darkholme.net"];
|
||||
public array $authors = ["YaoiFox" => "admin@yaoifox.com", "Matthew Barbour" => "matthew@darkholme.net"];
|
||||
public string $license = self::LICENSE_GPLV2;
|
||||
public ExtensionCategory $category = ExtensionCategory::FILE_HANDLING;
|
||||
public string $description = "Uploads images automatically using Cron Jobs";
|
||||
|
||||
@@ -21,7 +21,7 @@ class CronUploader extends Extension
|
||||
|
||||
private static bool $IMPORT_RUNNING = false;
|
||||
|
||||
public function onInitUserConfig(InitUserConfigEvent $event)
|
||||
public function onInitUserConfig(InitUserConfigEvent $event): void
|
||||
{
|
||||
$event->user_config->set_default_string(
|
||||
CronUploaderConfig::DIR,
|
||||
@@ -32,7 +32,7 @@ class CronUploader extends Extension
|
||||
$event->user_config->set_default_int(CronUploaderConfig::LOG_LEVEL, SCORE_LOG_INFO);
|
||||
}
|
||||
|
||||
public function onUserOptionsBuilding(UserOptionsBuildingEvent $event)
|
||||
public function onUserOptionsBuilding(UserOptionsBuildingEvent $event): void
|
||||
{
|
||||
if ($event->user->can(Permissions::CRON_ADMIN)) {
|
||||
$documentation_link = make_http(make_link("cron_upload"));
|
||||
@@ -55,9 +55,9 @@ class CronUploader extends Extension
|
||||
}
|
||||
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
if ($event->parent=="system") {
|
||||
if ($event->parent == "system") {
|
||||
$event->add_nav_link("cron_docs", new Link('cron_upload'), "Cron Upload");
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ class CronUploader extends Extension
|
||||
* Checks if the cron upload page has been accessed
|
||||
* and initializes the upload.
|
||||
*/
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
if ($event->page_matches("cron_upload/run")) {
|
||||
$this->process_upload();
|
||||
@@ -75,7 +75,7 @@ class CronUploader extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onAdminBuilding(AdminBuildingEvent $event)
|
||||
public function onAdminBuilding(AdminBuildingEvent $event): void
|
||||
{
|
||||
$failed_dir = $this->get_failed_dir();
|
||||
$results = get_dir_contents($failed_dir);
|
||||
@@ -91,7 +91,7 @@ class CronUploader extends Extension
|
||||
$this->theme->display_form($failed_dirs);
|
||||
}
|
||||
|
||||
public function onAdminAction(AdminActionEvent $event)
|
||||
public function onAdminAction(AdminActionEvent $event): void
|
||||
{
|
||||
$action = $event->action;
|
||||
switch ($action) {
|
||||
@@ -116,14 +116,14 @@ class CronUploader extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onLog(LogEvent $event)
|
||||
public function onLog(LogEvent $event): void
|
||||
{
|
||||
global $user_config;
|
||||
|
||||
if (self::$IMPORT_RUNNING) {
|
||||
$all = $user_config->get_bool(CronUploaderConfig::INCLUDE_ALL_LOGS);
|
||||
if ($event->priority >= $user_config->get_int(CronUploaderConfig::LOG_LEVEL) &&
|
||||
($event->section==self::NAME || $all)) {
|
||||
($event->section == self::NAME || $all)) {
|
||||
$output = "[" . date('Y-m-d H:i:s') . "] " . ($all ? '[' . $event->section . '] ' : '') . "[" . LOGGING_LEVEL_NAMES[$event->priority] . "] " . $event->message;
|
||||
|
||||
echo $output . "\r\n";
|
||||
@@ -135,7 +135,7 @@ class CronUploader extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
private function restage_folder(string $folder)
|
||||
private function restage_folder(string $folder): void
|
||||
{
|
||||
global $page;
|
||||
if (empty($folder)) {
|
||||
@@ -153,7 +153,7 @@ class CronUploader extends Extension
|
||||
$results = get_files_recursively($stage_dir);
|
||||
|
||||
if (count($results) == 0) {
|
||||
if (remove_empty_dirs($stage_dir)===false) {
|
||||
if (remove_empty_dirs($stage_dir) === false) {
|
||||
$page->flash("Nothing to stage from $folder, cannot remove folder");
|
||||
} else {
|
||||
$page->flash("Nothing to stage from $folder, removing folder");
|
||||
@@ -178,21 +178,21 @@ class CronUploader extends Extension
|
||||
mkdir($dir, 0775, true);
|
||||
}
|
||||
|
||||
if (rename($result, $new_path)===false) {
|
||||
if (rename($result, $new_path) === false) {
|
||||
$page->flash("Could not move file: " .$result);
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($success===true) {
|
||||
if ($success === true) {
|
||||
$page->flash("Re-staged $folder to queue");
|
||||
if (remove_empty_dirs($stage_dir)===false) {
|
||||
if (remove_empty_dirs($stage_dir) === false) {
|
||||
$page->flash("Could not remove $folder");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -321,7 +321,7 @@ class CronUploader extends Extension
|
||||
{
|
||||
global $database, $user, $user_config, $config, $_shm_load_start;
|
||||
|
||||
$max_time = intval(ini_get('max_execution_time'))*.8;
|
||||
$max_time = intval(ini_get('max_execution_time')) * .8;
|
||||
|
||||
$this->set_headers();
|
||||
|
||||
@@ -361,34 +361,25 @@ class CronUploader extends Extension
|
||||
// Upload the file(s)
|
||||
foreach ($image_queue as $img) {
|
||||
$execution_time = ftime() - $_shm_load_start;
|
||||
if ($execution_time>$max_time) {
|
||||
if ($execution_time > $max_time) {
|
||||
break;
|
||||
} else {
|
||||
$remaining = $max_time - $execution_time;
|
||||
$this->log_message(SCORE_LOG_DEBUG, "Max run time remaining: $remaining");
|
||||
}
|
||||
try {
|
||||
$database->begin_transaction();
|
||||
$this->log_message(SCORE_LOG_INFO, "Adding file: {$img[0]} - tags: {$img[2]}");
|
||||
$result = $this->add_image($img[0], $img[1], $img[2]);
|
||||
if ($database->is_transaction_open()) {
|
||||
$database->commit();
|
||||
}
|
||||
$this->move_uploaded($img[0], $img[1], $output_subdir, false);
|
||||
$result = $database->with_savepoint(function () use ($img, $output_subdir) {
|
||||
$this->log_message(SCORE_LOG_INFO, "Adding file: {$img[0]} - tags: {$img[2]}");
|
||||
$result = $this->add_image($img[0], $img[1], $img[2]);
|
||||
$this->move_uploaded($img[0], $img[1], $output_subdir, false);
|
||||
return $result;
|
||||
});
|
||||
if ($result->merged) {
|
||||
$merged++;
|
||||
} else {
|
||||
$added++;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
try {
|
||||
if ($database->is_transaction_open()) {
|
||||
$database->rollback();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// rollback failed, let's just log things and die
|
||||
}
|
||||
|
||||
$failed++;
|
||||
$this->log_message(SCORE_LOG_ERROR, "(" . gettype($e) . ") " . $e->getMessage());
|
||||
$this->log_message(SCORE_LOG_ERROR, $e->getTraceAsString());
|
||||
@@ -401,7 +392,7 @@ class CronUploader extends Extension
|
||||
}
|
||||
|
||||
// Throw exception if there's nothing in the queue
|
||||
if ($merged+$failed+$added === 0) {
|
||||
if ($merged + $failed + $added === 0) {
|
||||
$this->log_message(SCORE_LOG_WARNING, "Your queue is empty so nothing could be uploaded.");
|
||||
return false;
|
||||
}
|
||||
@@ -419,19 +410,19 @@ 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;
|
||||
|
||||
$rootDir = $user_config->get_string(CronUploaderConfig::DIR);
|
||||
$rootLength = strlen($rootDir);
|
||||
if ($rootDir[$rootLength-1]=="/"||$rootDir[$rootLength-1]=="\\") {
|
||||
if ($rootDir[$rootLength - 1] == "/" || $rootDir[$rootLength - 1] == "\\") {
|
||||
$rootLength--;
|
||||
}
|
||||
|
||||
$relativeDir = dirname(substr($path, $rootLength + 7));
|
||||
|
||||
if ($relativeDir==".") {
|
||||
if ($relativeDir == ".") {
|
||||
$relativeDir = "";
|
||||
}
|
||||
|
||||
@@ -459,20 +450,22 @@ 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, string $tags): DataUploadEvent
|
||||
private function add_image(string $tmpname, string $filename, array $tags): DataUploadEvent
|
||||
{
|
||||
$event = send_event(new DataUploadEvent($tmpname, basename($filename), 0, [
|
||||
'tags' => Tag::implode($tags),
|
||||
]));
|
||||
|
||||
// Generate info message
|
||||
if ($event->image_id == -1) {
|
||||
if (count($event->images) == 0) {
|
||||
throw new UploadException("File type not recognised (".$event->mime."). Filename: {$filename}");
|
||||
} elseif ($event->merged === true) {
|
||||
$infomsg = "Post merged. ID: {$event->image_id} - Filename: {$filename}";
|
||||
$infomsg = "Post merged. ID: {$event->images[0]->id} - Filename: {$filename}";
|
||||
} else {
|
||||
$infomsg = "Post uploaded. ID: {$event->image_id} - Filename: {$filename}";
|
||||
$infomsg = "Post uploaded. ID: {$event->images[0]->id} - Filename: {$filename}";
|
||||
}
|
||||
$this->log_message(SCORE_LOG_INFO, $infomsg);
|
||||
|
||||
@@ -480,7 +473,7 @@ class CronUploader extends Extension
|
||||
}
|
||||
|
||||
private const PARTIAL_DOWNLOAD_EXTENSIONS = ['crdownload','part'];
|
||||
private const SKIPPABLE_FILES = ['.ds_store','thumbs.db'];
|
||||
private const SKIPPABLE_FILES = ['.ds_store', 'thumbs.db', 'desktop.ini', '.listing'];
|
||||
|
||||
private function is_skippable_file(string $path): bool
|
||||
{
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
table.log th {
|
||||
table.cron_uploader_log th {
|
||||
width: 200px;
|
||||
}
|
||||
@@ -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 = "";
|
||||
@@ -34,7 +40,7 @@ class CronUploaderTheme extends Themelet
|
||||
$page->set_heading("Cron Uploader");
|
||||
|
||||
if (!$config->get_bool(UserConfig::ENABLE_API_KEYS)) {
|
||||
$info_html .= "<b style='color:red'>THIS EXTENSION REQUIRES USER API KEYS TO BE ENABLED IN <a href=''>BOARD ADMIN</a></b>";
|
||||
$info_html .= "<b style='color:red'>THIS EXTENSION REQUIRES USER API KEYS TO BE ENABLED IN <a href=''>BOARD ADMIN</a></b><br/>";
|
||||
}
|
||||
|
||||
$info_html .= "<b>Information</b>
|
||||
@@ -84,7 +90,7 @@ class CronUploaderTheme extends Themelet
|
||||
</ol>";
|
||||
|
||||
|
||||
$max_time = intval(ini_get('max_execution_time'))*.8;
|
||||
$max_time = intval(ini_get('max_execution_time')) * .8;
|
||||
|
||||
$usage_html = "Upload your images you want to be uploaded to the queue directory using your FTP client or other means.
|
||||
<br />(<b>{$queue_dirinfo['path']}</b>)
|
||||
@@ -109,13 +115,13 @@ class CronUploaderTheme extends Themelet
|
||||
|
||||
$block = new Block("Cron Uploader", $info_html, "main", 10);
|
||||
$block_install = new Block("Setup Guide", $install_html, "main", 30);
|
||||
$block_usage= new Block("Usage Guide", $usage_html, "main", 20);
|
||||
$block_usage = new Block("Usage Guide", $usage_html, "main", 20);
|
||||
$page->add_block($block);
|
||||
$page->add_block($block_install);
|
||||
$page->add_block($block_usage);
|
||||
|
||||
if (!empty($log_entries)) {
|
||||
$log_html = "<table class='log'>";
|
||||
$log_html = "<table class='cron_uploader_log'>";
|
||||
foreach ($log_entries as $entry) {
|
||||
$log_html .= "<tr><th>{$entry["date_sent"]}</th><td>{$entry["message"]}</td></tr>";
|
||||
}
|
||||
@@ -130,28 +136,28 @@ class CronUploaderTheme extends Themelet
|
||||
$form = SHM_SIMPLE_FORM(
|
||||
"user_admin/cron_uploader",
|
||||
TABLE(
|
||||
["class"=>"form"],
|
||||
["class" => "form"],
|
||||
TBODY(
|
||||
TR(
|
||||
TH("Cron Uploader")
|
||||
),
|
||||
TR(
|
||||
TH("Root dir"),
|
||||
TD(INPUT(["type"=>'text', "name"=>'name', "required"=>true]))
|
||||
TD(INPUT(["type" => 'text', "name" => 'name', "required" => true]))
|
||||
),
|
||||
TR(
|
||||
TH(),
|
||||
TD(
|
||||
LABEL(INPUT(["type"=>'checkbox', "name"=>'stop_on_error']), "Stop On Error")
|
||||
LABEL(INPUT(["type" => 'checkbox', "name" => 'stop_on_error']), "Stop On Error")
|
||||
)
|
||||
),
|
||||
TR(
|
||||
TH(rawHTML("Repeat Password")),
|
||||
TD(INPUT(["type"=>'password', "name"=>'pass2', "required"=>true]))
|
||||
TD(INPUT(["type" => 'password', "name" => 'pass2', "required" => true]))
|
||||
)
|
||||
),
|
||||
TFOOT(
|
||||
TR(TD(["colspan"=>"2"], INPUT(["type"=>"submit", "value"=>"Save Settings"])))
|
||||
TR(TD(["colspan" => "2"], INPUT(["type" => "submit", "value" => "Save Settings"])))
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -159,7 +165,10 @@ class CronUploaderTheme extends Themelet
|
||||
return (string)$html;
|
||||
}
|
||||
|
||||
public function display_form(array $failed_dirs)
|
||||
/**
|
||||
* @param string[] $failed_dirs
|
||||
*/
|
||||
public function display_form(array $failed_dirs): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class CustomHtmlHeadersInfo extends ExtensionInfo
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Custom HTML Headers";
|
||||
public string $url = "http://www.drudexsoftware.com";
|
||||
public array $authors = ["Drudex Software"=>"support@drudexsoftware.com"];
|
||||
public array $authors = ["Drudex Software" => "support@drudexsoftware.com"];
|
||||
public string $license = self::LICENSE_GPLV2;
|
||||
public ExtensionCategory $category = ExtensionCategory::ADMIN;
|
||||
public string $description = "Allows admins to modify & set custom <head> content";
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Shimmie2;
|
||||
class CustomHtmlHeaders extends Extension
|
||||
{
|
||||
# Adds setup block for custom <head> content
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Custom HTML Headers");
|
||||
|
||||
@@ -25,30 +25,30 @@ class CustomHtmlHeaders extends Extension
|
||||
], "<br>Add website name in title");
|
||||
}
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_string("sitename_in_title", "none");
|
||||
}
|
||||
|
||||
# Load Analytics tracking code on page request
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
$this->handle_custom_html_headers();
|
||||
$this->handle_modified_page_title();
|
||||
}
|
||||
|
||||
private function handle_custom_html_headers()
|
||||
private function handle_custom_html_headers(): void
|
||||
{
|
||||
global $config, $page;
|
||||
|
||||
$header = $config->get_string('custom_html_headers', '');
|
||||
if ($header!='') {
|
||||
if ($header != '') {
|
||||
$page->add_html_header($header);
|
||||
}
|
||||
}
|
||||
|
||||
private function handle_modified_page_title()
|
||||
private function handle_modified_page_title(): void
|
||||
{
|
||||
global $config, $page;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ class DanbooruApiInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Danbooru Client API";
|
||||
public array $authors = ["JJS"=>"jsutinen@gmail.com"];
|
||||
public array $authors = ["JJS" => "jsutinen@gmail.com"];
|
||||
public string $description = "Allow Danbooru apps like Danbooru Uploader for Firefox to communicate with Shimmie";
|
||||
public ExtensionCategory $category = ExtensionCategory::INTEGRATION;
|
||||
public ?string $documentation =
|
||||
|
||||
@@ -6,18 +6,30 @@ namespace Shimmie2;
|
||||
|
||||
use MicroHTML\HTMLElement;
|
||||
|
||||
/**
|
||||
* @param mixed[] ...$args
|
||||
*/
|
||||
function TAGS(...$args): HTMLElement
|
||||
{
|
||||
return new HTMLElement("tags", $args);
|
||||
}
|
||||
/**
|
||||
* @param mixed[] ...$args
|
||||
*/
|
||||
function TAG(...$args): HTMLElement
|
||||
{
|
||||
return new HTMLElement("tag", $args);
|
||||
}
|
||||
/**
|
||||
* @param mixed[] ...$args
|
||||
*/
|
||||
function POSTS(...$args): HTMLElement
|
||||
{
|
||||
return new HTMLElement("posts", $args);
|
||||
}
|
||||
/**
|
||||
* @param mixed[] ...$args
|
||||
*/
|
||||
function POST(...$args): HTMLElement
|
||||
{
|
||||
return new HTMLElement("post", $args);
|
||||
@@ -26,7 +38,7 @@ function POST(...$args): HTMLElement
|
||||
|
||||
class DanbooruApi extends Extension
|
||||
{
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
@@ -75,6 +87,7 @@ class DanbooruApi extends Extension
|
||||
$user = $duser;
|
||||
} else {
|
||||
$user = User::by_id($config->get_int("anon_id", 0));
|
||||
assert(!is_null($user));
|
||||
}
|
||||
send_event(new UserLoginEvent($user));
|
||||
}
|
||||
@@ -101,7 +114,7 @@ class DanbooruApi extends Extension
|
||||
foreach ($idlist as $id) {
|
||||
$sqlresult = $database->get_all(
|
||||
"SELECT id,tag,count FROM tags WHERE id = :id",
|
||||
['id'=>$id]
|
||||
['id' => $id]
|
||||
);
|
||||
foreach ($sqlresult as $row) {
|
||||
$results[] = [$row['count'], $row['tag'], $row['id']];
|
||||
@@ -112,7 +125,7 @@ class DanbooruApi extends Extension
|
||||
foreach ($namelist as $name) {
|
||||
$sqlresult = $database->get_all(
|
||||
"SELECT id,tag,count FROM tags WHERE LOWER(tag) = LOWER(:tag)",
|
||||
['tag'=>$name]
|
||||
['tag' => $name]
|
||||
);
|
||||
foreach ($sqlresult as $row) {
|
||||
$results[] = [$row['count'], $row['tag'], $row['id']];
|
||||
@@ -130,7 +143,7 @@ class DanbooruApi extends Extension
|
||||
$start = isset($GET['after_id']) ? int_escape($GET['offset']) : 0;
|
||||
$sqlresult = $database->get_all(
|
||||
"SELECT id,tag,count FROM tags WHERE count > 0 AND id >= :id ORDER BY id DESC",
|
||||
['id'=>$start]
|
||||
['id' => $start]
|
||||
);
|
||||
foreach ($sqlresult as $row) {
|
||||
$results[] = [$row['count'], $row['tag'], $row['id']];
|
||||
@@ -200,13 +213,14 @@ class DanbooruApi extends Extension
|
||||
$tags = array_filter($tags, static function ($element) {
|
||||
return $element !== "*";
|
||||
});
|
||||
$count = Image::count_images($tags);
|
||||
$results = Image::find_images(max($start, 0), min($limit, 100), $tags);
|
||||
$tags = array_values($tags); // reindex array because count_images() expects a 0-based array
|
||||
$count = Search::count_images($tags);
|
||||
$results = Search::find_images(max($start, 0), min($limit, 100), $tags);
|
||||
}
|
||||
|
||||
// Now we have the array $results filled with Image objects
|
||||
// Let's display them
|
||||
$xml = POSTS(["count"=>$count, "offset"=>$start]);
|
||||
$xml = POSTS(["count" => $count, "offset" => $start]);
|
||||
foreach ($results as $img) {
|
||||
// Sanity check to see if $img is really an image object
|
||||
// If it isn't (e.g. someone requested an invalid md5 or id), break out of the this
|
||||
@@ -267,8 +281,7 @@ class DanbooruApi extends Extension
|
||||
*/
|
||||
private function api_add_post(): void
|
||||
{
|
||||
global $user, $page;
|
||||
$danboorup_kludge = 1; // danboorup for firefox makes broken links out of location: /path
|
||||
global $database, $user, $page;
|
||||
|
||||
// Check first if a login was supplied, if it wasn't check if the user is logged in via cookie
|
||||
// If all that fails, it's an anonymous upload
|
||||
@@ -307,7 +320,7 @@ class DanbooruApi extends Extension
|
||||
fetch_url($source, $file);
|
||||
} catch (FetchException $e) {
|
||||
$page->set_code(409);
|
||||
$page->add_http_header("X-Danbooru-Errors: fopen read error");
|
||||
$page->add_http_header("X-Danbooru-Errors: $e");
|
||||
return;
|
||||
}
|
||||
$filename = basename($source);
|
||||
@@ -322,6 +335,7 @@ class DanbooruApi extends Extension
|
||||
|
||||
// Was an md5 supplied? Does it match the file hash?
|
||||
$hash = md5_file($file);
|
||||
assert($hash !== false);
|
||||
if (isset($_REQUEST['md5']) && strtolower($_REQUEST['md5']) != $hash) {
|
||||
$page->set_code(409);
|
||||
$page->add_http_header("X-Danbooru-Errors: md5 mismatch");
|
||||
@@ -336,9 +350,7 @@ class DanbooruApi extends Extension
|
||||
$page->set_code(409);
|
||||
$page->add_http_header("X-Danbooru-Errors: duplicate");
|
||||
$existinglink = make_link("post/view/" . $existing->id);
|
||||
if ($danboorup_kludge) {
|
||||
$existinglink = make_http($existinglink);
|
||||
}
|
||||
$existinglink = make_http($existinglink);
|
||||
$page->add_http_header("X-Danbooru-Location: $existinglink");
|
||||
return;
|
||||
}
|
||||
@@ -360,9 +372,7 @@ class DanbooruApi extends Extension
|
||||
});
|
||||
|
||||
$newid = make_link("post/view/" . $newimg->id);
|
||||
if ($danboorup_kludge) {
|
||||
$newid = make_http($newid);
|
||||
}
|
||||
$newid = make_http($newid);
|
||||
|
||||
// Did we POST or GET this call?
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
@@ -371,7 +381,6 @@ class DanbooruApi extends Extension
|
||||
$page->add_http_header("Location: $newid");
|
||||
}
|
||||
} catch (UploadException $ex) {
|
||||
// Did something screw up?
|
||||
$page->set_code(409);
|
||||
$page->add_http_header("X-Danbooru-Errors: exception - " . $ex->getMessage());
|
||||
}
|
||||
|
||||
@@ -6,20 +6,20 @@ namespace Shimmie2;
|
||||
|
||||
class DanbooruApiTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testSearch()
|
||||
public function testSearch(): void
|
||||
{
|
||||
$this->log_in_as_admin();
|
||||
|
||||
$image_id = $this->post_image("tests/bedroom_workshop.jpg", "data");
|
||||
|
||||
$this->get_page("api/danbooru/find_posts");
|
||||
$this->get_page("api/danbooru/find_posts", ["id"=>$image_id]);
|
||||
$this->get_page("api/danbooru/find_posts", ["md5"=>"17fc89f372ed3636e28bd25cc7f3bac1"]);
|
||||
$this->get_page("api/danbooru/find_posts", ["tags"=>"*"]);
|
||||
$this->get_page("api/danbooru/find_posts", ["id" => $image_id]);
|
||||
$this->get_page("api/danbooru/find_posts", ["md5" => "17fc89f372ed3636e28bd25cc7f3bac1"]);
|
||||
$this->get_page("api/danbooru/find_posts", ["tags" => "*"]);
|
||||
|
||||
$this->get_page("api/danbooru/find_tags");
|
||||
$this->get_page("api/danbooru/find_tags", ["id"=>1]);
|
||||
$this->get_page("api/danbooru/find_tags", ["name"=>"data"]);
|
||||
$this->get_page("api/danbooru/find_tags", ["id" => 1]);
|
||||
$this->get_page("api/danbooru/find_tags", ["name" => "data"]);
|
||||
|
||||
$page = $this->get_page("api/danbooru/post/show/$image_id");
|
||||
$this->assertEquals(302, $page->code);
|
||||
|
||||
@@ -10,7 +10,7 @@ class DownloadInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Download";
|
||||
public array $authors = ["Matthew Barbour"=>"matthew@darkholme.net"];
|
||||
public array $authors = ["Matthew Barbour" => "matthew@darkholme.net"];
|
||||
public string $license = self::LICENSE_WTFPL;
|
||||
public string $description = "System-wide download functions";
|
||||
public bool $core = true;
|
||||
|
||||
@@ -14,17 +14,13 @@ class Download extends Extension
|
||||
return 99;
|
||||
}
|
||||
|
||||
|
||||
public function onImageDownloading(ImageDownloadingEvent $event)
|
||||
public function onImageDownloading(ImageDownloadingEvent $event): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
$page->set_mime($event->mime);
|
||||
|
||||
$page->set_mode(PageMode::FILE);
|
||||
|
||||
$page->set_file($event->path, $event->file_modified);
|
||||
|
||||
$event->stop_processing = true;
|
||||
}
|
||||
}
|
||||
|
||||
16
ext/download/test.php
Normal file
16
ext/download/test.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
|
||||
class DownloadTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testView(): void
|
||||
{
|
||||
global $page;
|
||||
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
|
||||
$this->get_page("image/$image_id/moo.jpg");
|
||||
$this->assertEquals(PageMode::FILE, $page->mode);
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,14 @@ class Downtime extends Extension
|
||||
return 10;
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Downtime");
|
||||
$sb->add_bool_option("downtime", "Disable non-admin access: ");
|
||||
$sb->add_longtext_option("downtime_message", "<br>");
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $page, $user;
|
||||
|
||||
|
||||
@@ -10,9 +10,10 @@ class DowntimeTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
global $config;
|
||||
$config->set_bool("downtime", false);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function testDowntime()
|
||||
public function testDowntime(): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ class DowntimeTheme extends Themelet
|
||||
/**
|
||||
* Show the admin that downtime mode is enabled
|
||||
*/
|
||||
public function display_notification(Page $page)
|
||||
public function display_notification(Page $page): void
|
||||
{
|
||||
$page->add_block(new Block(
|
||||
"Downtime",
|
||||
"<span style='font-size: 1.5em; text-align: center;'><b>DOWNTIME MODE IS ON!</b></span>",
|
||||
"<span style='font-size: 1.5rem; text-align: center;'><b>DOWNTIME MODE IS ON!</b></span>",
|
||||
"left",
|
||||
0
|
||||
));
|
||||
@@ -22,7 +22,7 @@ class DowntimeTheme extends Themelet
|
||||
/**
|
||||
* Display $message and exit
|
||||
*/
|
||||
public function display_message(string $message)
|
||||
public function display_message(string $message): void
|
||||
{
|
||||
global $config, $user, $page;
|
||||
$theme_name = $config->get_string(SetupConfig::THEME);
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class EmoticonsTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testEmoticons()
|
||||
public function testEmoticons(): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class EmoticonList extends Extension
|
||||
/** @var EmoticonListTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
if ($event->page_matches("emote/list")) {
|
||||
$this->theme->display_emotes(\Safe\glob("ext/emoticons/default/*"));
|
||||
|
||||
@@ -6,7 +6,10 @@ namespace Shimmie2;
|
||||
|
||||
class EmoticonListTheme extends Themelet
|
||||
{
|
||||
public function display_emotes(array $list)
|
||||
/**
|
||||
* @param string[] $list
|
||||
*/
|
||||
public function display_emotes(array $list): void
|
||||
{
|
||||
global $page;
|
||||
$data_href = get_base_href();
|
||||
|
||||
@@ -11,7 +11,7 @@ class Eokm extends Extension
|
||||
return 40;
|
||||
} // early, to veto ImageUploadEvent
|
||||
|
||||
public function onImageAddition(ImageAdditionEvent $event)
|
||||
public function onImageAddition(ImageAdditionEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$username = $config->get_string("eokm_username");
|
||||
@@ -41,7 +41,7 @@ class Eokm extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("EOKM Filter");
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class EokmTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testPass()
|
||||
public function testPass(): void
|
||||
{
|
||||
// no EOKM login details set, so be a no-op
|
||||
$this->log_in_as_user();
|
||||
@@ -15,17 +15,4 @@ class EokmTest extends ShimmiePHPUnitTestCase
|
||||
$this->assert_no_text("Image too small");
|
||||
$this->assert_no_text("ratio");
|
||||
}
|
||||
|
||||
/*
|
||||
public function testFail()
|
||||
{
|
||||
$this->log_in_as_user();
|
||||
try {
|
||||
$this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
|
||||
$this->assertTrue(false, "Invalid-size image was allowed");
|
||||
} catch (UploadException $e) {
|
||||
$this->assertEquals("Image too small", $e->getMessage());
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -4,12 +4,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\{InputInterface,InputArgument};
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ET extends Extension
|
||||
{
|
||||
/** @var ETTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($event->page_matches("system_info", permission: Permissions::VIEW_SYSINFO)) {
|
||||
@@ -17,7 +21,7 @@ class ET extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($event->parent === "system") {
|
||||
@@ -27,7 +31,7 @@ class ET extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::VIEW_SYSINFO)) {
|
||||
@@ -35,19 +39,20 @@ class ET extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onCommand(CommandEvent $event)
|
||||
public function onCliGen(CliGenEvent $event): void
|
||||
{
|
||||
if ($event->cmd == "help") {
|
||||
print "\tinfo\n";
|
||||
print "\t\tList a bunch of info\n\n";
|
||||
}
|
||||
if ($event->cmd == "info") {
|
||||
print($this->to_yaml($this->get_info()));
|
||||
}
|
||||
$event->app->register('info')
|
||||
->setDescription('List a bunch of info')
|
||||
->setCode(function (InputInterface $input, OutputInterface $output): int {
|
||||
print($this->to_yaml($this->get_info()));
|
||||
return Command::SUCCESS;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the information and return it in a keyed array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function get_info(): array
|
||||
{
|
||||
@@ -81,7 +86,7 @@ class ET extends Extension
|
||||
'url' => make_http(make_link("/")),
|
||||
],
|
||||
"versions" => [
|
||||
'shimmie' => VERSION,
|
||||
'shimmie' => $ver,
|
||||
'schema' => $config->get_int("db_version"),
|
||||
'php' => phpversion(),
|
||||
'db' => $database->get_driver_id()->value . " " . $database->get_version(),
|
||||
@@ -134,6 +139,9 @@ class ET extends Extension
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $info
|
||||
*/
|
||||
private function to_yaml(array $info): string
|
||||
{
|
||||
$data = "";
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class ETTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testET()
|
||||
public function testET(): void
|
||||
{
|
||||
$this->log_in_as_admin();
|
||||
$this->get_page("system_info");
|
||||
|
||||
@@ -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)
|
||||
public function display_info_page(string $yaml): void
|
||||
{
|
||||
global $page;
|
||||
|
||||
@@ -26,21 +24,21 @@ 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"],
|
||||
INPUT(["type"=>"hidden", "name"=>"registration_api", "value"=>"2"]),
|
||||
["action" => "https://shimmie.shishnet.org/register.php", "method" => "POST"],
|
||||
INPUT(["type" => "hidden", "name" => "registration_api", "value" => "2"]),
|
||||
P(
|
||||
"Your stats are useful so that I know which combinations of ".
|
||||
"web servers / databases / etc I need to support :)"
|
||||
),
|
||||
P(TEXTAREA(
|
||||
["name"=>'data', "style"=>"width: 100%; height: 20em;"],
|
||||
["name" => 'data', "style" => "width: 100%; height: 20em;"],
|
||||
$yaml
|
||||
)),
|
||||
P(INPUT(
|
||||
["type"=>'submit', "value"=>'Click to send to Shish', "style"=>"width: 100%; padding: 1em;"]
|
||||
["type" => 'submit', "value" => 'Click to send to Shish', "style" => "width: 100%; padding: 1em;"]
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use function MicroHTML\{PRE};
|
||||
|
||||
class ETServer extends Extension
|
||||
{
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $database, $page, $user;
|
||||
if ($event->page_matches("register.php")) {
|
||||
@@ -28,7 +28,7 @@ class ETServer extends Extension
|
||||
foreach ($database->get_all("SELECT responded, data FROM registration ORDER BY responded DESC") as $row) {
|
||||
$page->add_block(new Block(
|
||||
$row["responded"],
|
||||
PRE(["style"=>"text-align: left; overflow: scroll;"], $row["data"]),
|
||||
PRE(["style" => "text-align: left; overflow: scroll;"], $row["data"]),
|
||||
"main",
|
||||
$n++
|
||||
));
|
||||
@@ -37,7 +37,7 @@ class ETServer extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
|
||||
21
ext/et_server/test.php
Normal file
21
ext/et_server/test.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
|
||||
class ETServerTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testView(): void
|
||||
{
|
||||
$this->post_page("register.php", ["data" => "test entry"]);
|
||||
|
||||
$this->log_in_as_user();
|
||||
$this->get_page("register.php");
|
||||
$this->assert_no_text("test entry");
|
||||
|
||||
$this->log_in_as_admin();
|
||||
$this->get_page("register.php");
|
||||
$this->assert_text("test entry");
|
||||
}
|
||||
}
|
||||
@@ -4,23 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
|
||||
function __extman_extcmp(ExtensionInfo $a, ExtensionInfo $b): int
|
||||
{
|
||||
if ($a->beta===true&&$b->beta===false) {
|
||||
return 1;
|
||||
}
|
||||
if ($a->beta===false&&$b->beta===true) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return strcmp($a->name, $b->name);
|
||||
}
|
||||
|
||||
function __extman_extactive(ExtensionInfo $a): bool
|
||||
{
|
||||
return Extension::is_enabled($a->key);
|
||||
}
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\{InputInterface,InputArgument};
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ExtensionAuthor
|
||||
{
|
||||
@@ -39,7 +25,7 @@ class ExtManager extends Extension
|
||||
/** @var ExtManagerTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
if ($event->page_matches("ext_manager/set", method: "POST", permission: Permissions::MANAGE_EXTENSION_LIST)) {
|
||||
@@ -71,21 +57,20 @@ class ExtManager extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onCommand(CommandEvent $event)
|
||||
public function onCliGen(CliGenEvent $event): void
|
||||
{
|
||||
if ($event->cmd == "help") {
|
||||
print "\tdisable-all-ext\n";
|
||||
print "\t\tdisable all extensions\n\n";
|
||||
}
|
||||
if ($event->cmd == "disable-all-ext") {
|
||||
$this->write_config([]);
|
||||
}
|
||||
$event->app->register('disable-all-ext')
|
||||
->setDescription('Disable all extensions')
|
||||
->setCode(function (InputInterface $input, OutputInterface $output): int {
|
||||
$this->write_config([]);
|
||||
return Command::SUCCESS;
|
||||
});
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($event->parent==="system") {
|
||||
if ($event->parent === "system") {
|
||||
if ($user->can(Permissions::MANAGE_EXTENSION_LIST)) {
|
||||
$event->add_nav_link("ext_manager", new Link('ext_manager'), "Extension Manager");
|
||||
} else {
|
||||
@@ -94,7 +79,7 @@ class ExtManager extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::MANAGE_EXTENSION_LIST)) {
|
||||
@@ -103,13 +88,13 @@ class ExtManager extends Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* #return ExtensionInfo[]
|
||||
* @return ExtensionInfo[]
|
||||
*/
|
||||
private function get_extensions(bool $all): array
|
||||
{
|
||||
$extensions = ExtensionInfo::get_all();
|
||||
if (!$all) {
|
||||
$extensions = array_filter($extensions, "Shimmie2\__extman_extactive");
|
||||
$extensions = array_filter($extensions, fn ($x) => Extension::is_enabled($x->key));
|
||||
}
|
||||
usort($extensions, function ($a, $b) {
|
||||
if ($a->category->name !== $b->category->name) {
|
||||
@@ -123,13 +108,19 @@ class ExtManager extends Extension
|
||||
return $extensions;
|
||||
}
|
||||
|
||||
private function set_things($settings)
|
||||
/**
|
||||
* @param array<string, mixed> $settings
|
||||
*/
|
||||
private function set_things(array $settings): void
|
||||
{
|
||||
$core = ExtensionInfo::get_core_extensions();
|
||||
$extras = [];
|
||||
|
||||
foreach (ExtensionInfo::get_all_keys() as $key) {
|
||||
if (!in_array($key, $core) && isset($settings["ext_$key"])) {
|
||||
if (in_array($key, $core)) {
|
||||
continue; // core extensions are always enabled
|
||||
}
|
||||
if (isset($settings["ext_$key"]) && $settings["ext_$key"] === "on") {
|
||||
$extras[] = $key;
|
||||
}
|
||||
}
|
||||
@@ -138,19 +129,14 @@ class ExtManager extends Extension
|
||||
}
|
||||
|
||||
/**
|
||||
* #param string[] $extras
|
||||
* @param string[] $extras
|
||||
*/
|
||||
private function write_config(array $extras)
|
||||
private function write_config(array $extras): void
|
||||
{
|
||||
file_put_contents(
|
||||
"data/config/extensions.conf.php",
|
||||
'<' . '?php' . "\n" .
|
||||
'define("EXTRA_EXTS", "' . implode(",", $extras) . '");' . "\n"
|
||||
);
|
||||
|
||||
// when the list of active extensions changes, we can be
|
||||
// pretty sure that the list of who reacts to what will
|
||||
// change too
|
||||
_clear_cached_event_listeners();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class ExtManagerTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testAuth()
|
||||
public function testAuth(): void
|
||||
{
|
||||
$this->get_page('ext_manager');
|
||||
$this->assert_title("Extensions");
|
||||
|
||||
@@ -25,16 +25,16 @@ use function MicroHTML\rawHTML;
|
||||
class ExtManagerTheme extends Themelet
|
||||
{
|
||||
/**
|
||||
* #param ExtensionInfo[] $extensions
|
||||
* @param ExtensionInfo[] $extensions
|
||||
*/
|
||||
public function display_table(Page $page, array $extensions, bool $editable)
|
||||
public function display_table(Page $page, array $extensions, bool $editable): void
|
||||
{
|
||||
$tbody = TBODY();
|
||||
|
||||
$form = SHM_SIMPLE_FORM(
|
||||
"ext_manager/set",
|
||||
TABLE(
|
||||
["id"=>'extensions', "class"=>'zebra'],
|
||||
["id" => 'extensions', "class" => 'zebra'],
|
||||
THEAD(TR(
|
||||
$editable ? TH("Enabled") : null,
|
||||
TH("Name"),
|
||||
@@ -42,7 +42,7 @@ class ExtManagerTheme extends Themelet
|
||||
TH("Description")
|
||||
)),
|
||||
$tbody,
|
||||
$editable ? TFOOT(TR(TD(["colspan"=>'5'], INPUT(["type"=>'submit', "value"=>'Set Extensions'])))) : null
|
||||
$editable ? TFOOT(TR(TD(["colspan" => '5'], INPUT(["type" => 'submit', "value" => 'Set Extensions'])))) : null
|
||||
)
|
||||
);
|
||||
|
||||
@@ -68,18 +68,18 @@ class ExtManagerTheme extends Themelet
|
||||
}
|
||||
|
||||
$tbody->appendChild(TR(
|
||||
["data-ext"=>$extension->name],
|
||||
["data-ext" => $extension->name],
|
||||
$editable ? TD(INPUT([
|
||||
"type"=>'checkbox',
|
||||
"name"=>"ext_{$extension->key}",
|
||||
"id"=>"ext_{$extension->key}",
|
||||
"checked"=>($extension->is_enabled() === true),
|
||||
"disabled"=>($extension->is_supported()===false || $extension->core===true)
|
||||
"type" => 'checkbox',
|
||||
"name" => "ext_{$extension->key}",
|
||||
"id" => "ext_{$extension->key}",
|
||||
"checked" => ($extension->is_enabled() === true),
|
||||
"disabled" => ($extension->is_supported() === false || $extension->core === true)
|
||||
])) : null,
|
||||
TD(LABEL(
|
||||
["for"=>"ext_{$extension->key}"],
|
||||
["for" => "ext_{$extension->key}"],
|
||||
(
|
||||
($extension->beta===true ? "[BETA] " : "").
|
||||
($extension->beta === true ? "[BETA] " : "").
|
||||
(empty($extension->name) ? $extension->key : $extension->name)
|
||||
)
|
||||
)),
|
||||
@@ -87,16 +87,16 @@ class ExtManagerTheme extends Themelet
|
||||
// TODO: A proper "docs" symbol would be preferred here.
|
||||
$extension->documentation ?
|
||||
A(
|
||||
["href"=>make_link("ext_doc/" . url_escape($extension->key))],
|
||||
IMG(["src"=>'ext/ext_manager/baseline_open_in_new_black_18dp.png'])
|
||||
["href" => make_link("ext_doc/" . url_escape($extension->key))],
|
||||
IMG(["src" => 'ext/ext_manager/baseline_open_in_new_black_18dp.png'])
|
||||
) :
|
||||
null
|
||||
),
|
||||
TD(
|
||||
["style"=>'text-align: left;'],
|
||||
["style" => 'text-align: left;'],
|
||||
$extension->description,
|
||||
" ",
|
||||
B(["style"=>'color:red'], $extension->get_support_info())
|
||||
B(["style" => 'color:red'], $extension->get_support_info())
|
||||
),
|
||||
));
|
||||
}
|
||||
@@ -127,15 +127,15 @@ class ExtManagerTheme extends Themelet
|
||||
$page->add_block(new Block("Extension Manager", $form));
|
||||
}
|
||||
|
||||
public function display_doc(Page $page, ExtensionInfo $info)
|
||||
public function display_doc(Page $page, ExtensionInfo $info): void
|
||||
{
|
||||
$author = emptyHTML();
|
||||
if (count($info->authors) > 0) {
|
||||
$author->appendChild(BR());
|
||||
$author->appendChild(B(count($info->authors) > 1 ? "Authors: " : "Author: "));
|
||||
foreach ($info->authors as $auth=>$email) {
|
||||
foreach ($info->authors as $auth => $email) {
|
||||
if (!empty($email)) {
|
||||
$author->appendChild(A(["href"=>"mailto:$email"], $auth));
|
||||
$author->appendChild(A(["href" => "mailto:$email"], $auth));
|
||||
} else {
|
||||
$author->appendChild($auth);
|
||||
}
|
||||
@@ -144,12 +144,12 @@ class ExtManagerTheme extends Themelet
|
||||
}
|
||||
|
||||
$html = DIV(
|
||||
["style"=>'margin: auto; text-align: left; width: 512px;'],
|
||||
["style" => 'margin: auto; text-align: left; width: 512px;'],
|
||||
$author,
|
||||
($info->link ? emptyHTML(BR(), B("Home Page"), A(["href" => $info->link], "Link")) : null),
|
||||
P(rawHTML($info->documentation ?? "(This extension has no documentation)")),
|
||||
// <hr>,
|
||||
P(A(["href"=>make_link("ext_manager")], "Back to the list"))
|
||||
P(A(["href" => make_link("ext_manager")], "Back to the list"))
|
||||
);
|
||||
|
||||
$page->set_title("Documentation for " . html_escape($info->name));
|
||||
|
||||
@@ -10,7 +10,7 @@ class FavoritesInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Favorites";
|
||||
public array $authors = ["Daniel Marschall"=>"info@daniel-marschall.de"];
|
||||
public array $authors = ["Daniel Marschall" => "info@daniel-marschall.de"];
|
||||
public string $license = self::LICENSE_GPLV2;
|
||||
public string $description = "Allow users to favorite images";
|
||||
public ?string $documentation =
|
||||
|
||||
@@ -27,7 +27,12 @@ class Favorites extends Extension
|
||||
/** @var FavoritesTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
Image::$prop_types["favorites"] = ImagePropType::INT;
|
||||
}
|
||||
|
||||
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event): void
|
||||
{
|
||||
global $database, $user;
|
||||
if (!$user->is_anonymous()) {
|
||||
@@ -36,7 +41,7 @@ class Favorites extends Extension
|
||||
|
||||
$is_favorited = $database->get_one(
|
||||
"SELECT COUNT(*) AS ct FROM user_favorites WHERE user_id = :user_id AND image_id = :image_id",
|
||||
["user_id"=>$user_id, "image_id"=>$image_id]
|
||||
["user_id" => $user_id, "image_id" => $image_id]
|
||||
) > 0;
|
||||
|
||||
if ($is_favorited) {
|
||||
@@ -47,7 +52,7 @@ class Favorites extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onDisplayingImage(DisplayingImageEvent $event)
|
||||
public function onDisplayingImage(DisplayingImageEvent $event): void
|
||||
{
|
||||
$people = $this->list_persons_who_have_favorited($event->image);
|
||||
if (count($people) > 0) {
|
||||
@@ -55,7 +60,7 @@ class Favorites extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
if ($user->is_anonymous()) {
|
||||
@@ -76,7 +81,7 @@ class Favorites extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onUserPageBuilding(UserPageBuildingEvent $event)
|
||||
public function onUserPageBuilding(UserPageBuildingEvent $event): void
|
||||
{
|
||||
$i_favorites_count = Search::count_images(["favorited_by={$event->display_user->name}"]);
|
||||
$i_days_old = ((time() - \Safe\strtotime($event->display_user->join_date)) / 86400) + 1;
|
||||
@@ -85,7 +90,7 @@ class Favorites extends Extension
|
||||
$event->add_part("<a href='$favorites_link'>Posts favorited</a>: $i_favorites_count, $h_favorites_rate per day");
|
||||
}
|
||||
|
||||
public function onImageInfoSet(ImageInfoSetEvent $event)
|
||||
public function onImageInfoSet(ImageInfoSetEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
$action = $event->get_param("favorite_action");
|
||||
@@ -98,7 +103,7 @@ class Favorites extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onFavoriteSet(FavoriteSetEvent $event)
|
||||
public function onFavoriteSet(FavoriteSetEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
$this->add_vote($event->image_id, $user->id, $event->do_set);
|
||||
@@ -106,26 +111,26 @@ class Favorites extends Extension
|
||||
|
||||
// FIXME: this should be handled by the foreign key. Check that it
|
||||
// is, and then remove this
|
||||
public function onImageDeletion(ImageDeletionEvent $event)
|
||||
public function onImageDeletion(ImageDeletionEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("DELETE FROM user_favorites WHERE image_id=:image_id", ["image_id"=>$event->image->id]);
|
||||
$database->execute("DELETE FROM user_favorites WHERE image_id=:image_id", ["image_id" => $event->image->id]);
|
||||
}
|
||||
|
||||
public function onParseLinkTemplate(ParseLinkTemplateEvent $event)
|
||||
public function onParseLinkTemplate(ParseLinkTemplateEvent $event): void
|
||||
{
|
||||
$event->replace('$favorites', (string)$event->image->favorites);
|
||||
$event->replace('$favorites', (string)$event->image['favorites']);
|
||||
}
|
||||
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
|
||||
public function onUserBlockBuilding(UserBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
$username = url_escape($user->name);
|
||||
$event->add_link("My Favorites", make_link("post/list/favorited_by=$username/1"), 20);
|
||||
$event->add_link("My Favorites", search_link(["favorited_by=$username"]), 20);
|
||||
}
|
||||
|
||||
public function onSearchTermParse(SearchTermParseEvent $event)
|
||||
public function onSearchTermParse(SearchTermParseEvent $event): void
|
||||
{
|
||||
if (is_null($event->term)) {
|
||||
return;
|
||||
@@ -149,21 +154,21 @@ class Favorites extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onHelpPageBuilding(HelpPageBuildingEvent $event)
|
||||
public function onHelpPageBuilding(HelpPageBuildingEvent $event): void
|
||||
{
|
||||
if ($event->key===HelpPages::SEARCH) {
|
||||
if ($event->key === HelpPages::SEARCH) {
|
||||
$event->add_block(new Block("Favorites", $this->theme->get_help_html()));
|
||||
}
|
||||
}
|
||||
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event)
|
||||
public function onPageSubNavBuilding(PageSubNavBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($event->parent=="posts") {
|
||||
if ($event->parent == "posts") {
|
||||
$event->add_nav_link("posts_favorites", new Link("post/list/favorited_by={$user->name}/1"), "My Favorites");
|
||||
}
|
||||
|
||||
if ($event->parent==="user") {
|
||||
if ($event->parent === "user") {
|
||||
if ($user->can(Permissions::MANAGE_ADMINTOOLS)) {
|
||||
$username = url_escape($user->name);
|
||||
$event->add_nav_link("favorites", new Link("post/list/favorited_by=$username/1"), "My Favorites");
|
||||
@@ -171,7 +176,7 @@ class Favorites extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event)
|
||||
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
@@ -181,7 +186,7 @@ class Favorites extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onBulkAction(BulkActionEvent $event)
|
||||
public function onBulkAction(BulkActionEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
|
||||
@@ -209,7 +214,7 @@ class Favorites extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
@@ -240,30 +245,30 @@ 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) {
|
||||
if (!$database->get_row("select 1 from user_favorites where image_id=:image_id and user_id=:user_id", ["image_id"=>$image_id, "user_id"=>$user_id])) {
|
||||
if (!$database->get_row("select 1 from user_favorites where image_id=:image_id and user_id=:user_id", ["image_id" => $image_id, "user_id" => $user_id])) {
|
||||
$database->execute(
|
||||
"INSERT INTO user_favorites(image_id, user_id, created_at) VALUES(:image_id, :user_id, NOW())",
|
||||
["image_id"=>$image_id, "user_id"=>$user_id]
|
||||
["image_id" => $image_id, "user_id" => $user_id]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$database->execute(
|
||||
"DELETE FROM user_favorites WHERE image_id = :image_id AND user_id = :user_id",
|
||||
["image_id"=>$image_id, "user_id"=>$user_id]
|
||||
["image_id" => $image_id, "user_id" => $user_id]
|
||||
);
|
||||
}
|
||||
$database->execute(
|
||||
"UPDATE images SET favorites=(SELECT COUNT(*) FROM user_favorites WHERE image_id=:image_id) WHERE id=:user_id",
|
||||
["image_id"=>$image_id, "user_id"=>$user_id]
|
||||
["image_id" => $image_id, "user_id" => $user_id]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* #return string[]
|
||||
* @return string[]
|
||||
*/
|
||||
private function list_persons_who_have_favorited(Image $image): array
|
||||
{
|
||||
@@ -271,7 +276,7 @@ class Favorites extends Extension
|
||||
|
||||
return $database->get_col(
|
||||
"SELECT name FROM users WHERE id IN (SELECT user_id FROM user_favorites WHERE image_id = :image_id) ORDER BY name",
|
||||
["image_id"=>$image->id]
|
||||
["image_id" => $image->id]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class FavoritesTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testFavorites()
|
||||
public function testFavorites(): void
|
||||
{
|
||||
global $user;
|
||||
$this->log_in_as_user();
|
||||
|
||||
@@ -9,13 +9,13 @@ class Featured extends Extension
|
||||
/** @var FeaturedTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_int('featured_id', 0);
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $page, $user;
|
||||
if ($event->page_matches("featured_image/set/{image_id}", method: "POST", permission: Permissions::EDIT_FEATURE)) {
|
||||
@@ -41,22 +41,25 @@ class Featured extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onPostListBuilding(PostListBuildingEvent $event)
|
||||
public function onPostListBuilding(PostListBuildingEvent $event): void
|
||||
{
|
||||
global $cache, $config, $page, $user;
|
||||
$fid = $config->get_int("featured_id");
|
||||
if ($fid > 0) {
|
||||
$image = $cache->get("featured_image_object:$fid");
|
||||
if (is_null($image)) {
|
||||
$image = Image::by_id($fid);
|
||||
if ($image) { // make sure the object is fully populated before saving
|
||||
$image->get_tag_array();
|
||||
}
|
||||
$cache->set("featured_image_object:$fid", $image, 600);
|
||||
}
|
||||
$image = cache_get_or_set(
|
||||
"featured_image_object:$fid",
|
||||
function () use ($fid) {
|
||||
$image = Image::by_id($fid);
|
||||
if ($image) { // make sure the object is fully populated before saving
|
||||
$image->get_tag_array();
|
||||
}
|
||||
return $image;
|
||||
},
|
||||
600
|
||||
);
|
||||
if (!is_null($image)) {
|
||||
if (Extension::is_enabled(RatingsInfo::KEY)) {
|
||||
if (!in_array($image->rating, Ratings::get_user_class_privs($user))) {
|
||||
if (!in_array($image['rating'], Ratings::get_user_class_privs($user))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +68,7 @@ class Featured extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onImageDeletion(ImageDeletionEvent $event)
|
||||
public function onImageDeletion(ImageDeletionEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
if ($event->image->id == $config->get_int("featured_id")) {
|
||||
@@ -74,7 +77,7 @@ class Featured extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
|
||||
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event): void
|
||||
{
|
||||
global $user;
|
||||
if ($user->can(Permissions::EDIT_FEATURE) && $event->context == "view") {
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class FeaturedTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function testFeatured()
|
||||
public function testFeatured(): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
|
||||
@@ -21,16 +21,16 @@ class FeaturedTheme extends Themelet
|
||||
$tsize = get_thumbnail_size($image->width, $image->height);
|
||||
|
||||
return DIV(
|
||||
["style"=>"text-align: center;"],
|
||||
["style" => "text-align: center;"],
|
||||
A(
|
||||
["href"=>make_link("post/view/{$image->id}", $query)],
|
||||
["href" => make_link("post/view/{$image->id}", $query)],
|
||||
IMG([
|
||||
"id"=>"thumb_rand_{$image->id}",
|
||||
"title"=>$image->get_tooltip(),
|
||||
"alt"=>$image->get_tooltip(),
|
||||
"class"=>'highlighted',
|
||||
"style"=>"max-height: {$tsize[1]}px; max-width: 100%;",
|
||||
"src"=>$image->get_thumb_link()
|
||||
"id" => "thumb_rand_{$image->id}",
|
||||
"title" => $image->get_tooltip(),
|
||||
"alt" => $image->get_tooltip(),
|
||||
"class" => 'highlighted',
|
||||
"style" => "max-height: {$tsize[1]}px; max-width: 100%;",
|
||||
"src" => $image->get_thumb_link()
|
||||
])
|
||||
)
|
||||
);
|
||||
|
||||
@@ -10,7 +10,7 @@ class ForumInfo extends ExtensionInfo
|
||||
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Forum";
|
||||
public array $authors = ["Sein Kraft"=>"mail@seinkraft.info","Alpha"=>"alpha@furries.com.ar"];
|
||||
public array $authors = ["Sein Kraft" => "mail@seinkraft.info","Alpha" => "alpha@furries.com.ar"];
|
||||
public string $license = self::LICENSE_GPLV2;
|
||||
public ExtensionCategory $category = ExtensionCategory::FEATURE;
|
||||
public string $description = "Rough forum extension";
|
||||
|
||||
@@ -17,7 +17,7 @@ class Forum extends Extension
|
||||
/** @var ForumTheme */
|
||||
protected Themelet $theme;
|
||||
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event)
|
||||
public function onDatabaseUpgrade(DatabaseUpgradeEvent $event): void
|
||||
{
|
||||
global $config, $database;
|
||||
|
||||
@@ -65,7 +65,7 @@ class Forum extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Forum");
|
||||
$sb->add_int_option("forumTitleSubString", "Title max long: ");
|
||||
@@ -75,12 +75,12 @@ class Forum extends Extension
|
||||
$sb->add_int_option("forumMaxCharsPerPost", "<br>Max chars per post: ");
|
||||
}
|
||||
|
||||
public function onUserPageBuilding(UserPageBuildingEvent $event)
|
||||
public function onUserPageBuilding(UserPageBuildingEvent $event): void
|
||||
{
|
||||
global $database;
|
||||
|
||||
$threads_count = $database->get_one("SELECT COUNT(*) FROM forum_threads WHERE user_id=:user_id", ['user_id'=>$event->display_user->id]);
|
||||
$posts_count = $database->get_one("SELECT COUNT(*) FROM forum_posts WHERE user_id=:user_id", ['user_id'=>$event->display_user->id]);
|
||||
$threads_count = $database->get_one("SELECT COUNT(*) FROM forum_threads WHERE user_id=:user_id", ['user_id' => $event->display_user->id]);
|
||||
$posts_count = $database->get_one("SELECT COUNT(*) FROM forum_posts WHERE user_id=:user_id", ['user_id' => $event->display_user->id]);
|
||||
|
||||
$days_old = ((time() - \Safe\strtotime($event->display_user->join_date)) / 86400) + 1;
|
||||
|
||||
@@ -91,12 +91,12 @@ class Forum extends Extension
|
||||
$event->add_part("Forum posts: $posts_count, $posts_rate per day");
|
||||
}
|
||||
|
||||
public function onPageNavBuilding(PageNavBuildingEvent $event)
|
||||
public function onPageNavBuilding(PageNavBuildingEvent $event): void
|
||||
{
|
||||
$event->add_nav_link("forum", new Link('forum/index'), "Forum");
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page, $user;
|
||||
if ($event->page_matches("forum/index", paged: true)) {
|
||||
@@ -173,63 +173,75 @@ class Forum extends Extension
|
||||
private function get_total_pages_for_thread(int $threadID): int
|
||||
{
|
||||
global $database, $config;
|
||||
$result = $database->get_row("SELECT COUNT(1) AS count FROM forum_posts WHERE thread_id = :thread_id", ['thread_id'=>$threadID]);
|
||||
$result = $database->get_row("
|
||||
SELECT COUNT(1) AS count
|
||||
FROM forum_posts
|
||||
WHERE thread_id = :thread_id
|
||||
", ['thread_id' => $threadID]);
|
||||
|
||||
return (int) ceil($result["count"] / $config->get_int("forumPostsPerPage"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function sanity_check_new_thread(): array
|
||||
{
|
||||
$errors = null;
|
||||
$errors = [];
|
||||
if (!array_key_exists("title", $_POST)) {
|
||||
$errors .= "<div id='error'>No title supplied.</div>";
|
||||
$errors[] = "No title supplied.";
|
||||
} elseif (strlen($_POST["title"]) == 0) {
|
||||
$errors .= "<div id='error'>You cannot have an empty title.</div>";
|
||||
} elseif (strlen(html_escape($_POST["title"])) > 255) {
|
||||
$errors .= "<div id='error'>Your title is too long.</div>";
|
||||
$errors[] = "You cannot have an empty title.";
|
||||
} elseif (strlen($_POST["title"]) > 255) {
|
||||
$errors[] = "Your title is too long.";
|
||||
}
|
||||
|
||||
if (!array_key_exists("message", $_POST)) {
|
||||
$errors .= "<div id='error'>No message supplied.</div>";
|
||||
$errors[] = "No message supplied.";
|
||||
} elseif (strlen($_POST["message"]) == 0) {
|
||||
$errors .= "<div id='error'>You cannot have an empty message.</div>";
|
||||
$errors[] = "You cannot have an empty message.";
|
||||
}
|
||||
|
||||
return [$errors];
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function sanity_check_new_post(): array
|
||||
{
|
||||
$errors = null;
|
||||
$errors = [];
|
||||
if (!array_key_exists("threadID", $_POST)) {
|
||||
$errors = "<div id='error'>No thread ID supplied.</div>";
|
||||
$errors[] = "No thread ID supplied.";
|
||||
} elseif (strlen($_POST["threadID"]) == 0) {
|
||||
$errors = "<div id='error'>No thread ID supplied.</div>";
|
||||
$errors[] = "No thread ID supplied.";
|
||||
} elseif (is_numeric($_POST["threadID"])) {
|
||||
if (!array_key_exists("message", $_POST)) {
|
||||
$errors .= "<div id='error'>No message supplied.</div>";
|
||||
$errors[] = "No message supplied.";
|
||||
} elseif (strlen($_POST["message"]) == 0) {
|
||||
$errors .= "<div id='error'>You cannot have an empty message.</div>";
|
||||
$errors[] = "You cannot have an empty message.";
|
||||
}
|
||||
}
|
||||
|
||||
return [$errors];
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function sanity_check_viewed_thread(int $threadID): array
|
||||
{
|
||||
$errors = null;
|
||||
$errors = [];
|
||||
if (!$this->threadExists($threadID)) {
|
||||
$errors = "<div id='error'>Inexistent thread.</div>";
|
||||
$errors[] = "Inexistent thread.";
|
||||
}
|
||||
return [$errors];
|
||||
return $errors;
|
||||
}
|
||||
|
||||
private function get_thread_title(int $threadID): string
|
||||
{
|
||||
global $database;
|
||||
$result = $database->get_row("SELECT t.title FROM forum_threads AS t WHERE t.id = :id ", ['id'=>$threadID]);
|
||||
return $result["title"];
|
||||
return $database->get_one("SELECT t.title FROM forum_threads AS t WHERE t.id = :id ", ['id' => $threadID]);
|
||||
}
|
||||
|
||||
private function show_last_threads(Page $page, int $pageNumber, bool $showAdminOptions = false): void
|
||||
@@ -275,7 +287,7 @@ class Forum extends Extension
|
||||
|
||||
private function save_new_thread(User $user): int
|
||||
{
|
||||
$title = html_escape($_POST["title"]);
|
||||
$title = $_POST["title"];
|
||||
$sticky = !empty($_POST["sticky"]);
|
||||
|
||||
global $database;
|
||||
@@ -285,7 +297,7 @@ class Forum extends Extension
|
||||
(title, sticky, user_id, date, uptodate)
|
||||
VALUES
|
||||
(:title, :sticky, :user_id, now(), now())",
|
||||
['title'=>$title, 'sticky'=>$sticky, 'user_id'=>$user->id]
|
||||
['title' => $title, 'sticky' => $sticky, 'user_id' => $user->id]
|
||||
);
|
||||
|
||||
$threadID = $database->get_last_insert_id("forum_threads_id_seq");
|
||||
@@ -299,7 +311,7 @@ class Forum extends Extension
|
||||
{
|
||||
global $config;
|
||||
$userID = $user->id;
|
||||
$message = html_escape($_POST["message"]);
|
||||
$message = $_POST["message"];
|
||||
|
||||
$max_characters = $config->get_int('forumMaxCharsPerPost');
|
||||
$message = substr($message, 0, $max_characters);
|
||||
@@ -308,32 +320,32 @@ class Forum extends Extension
|
||||
$database->execute("
|
||||
INSERT INTO forum_posts (thread_id, user_id, date, message)
|
||||
VALUES (:thread_id, :user_id, now(), :message)
|
||||
", ['thread_id'=>$threadID, 'user_id'=>$userID, 'message'=>$message]);
|
||||
", ['thread_id' => $threadID, 'user_id' => $userID, 'message' => $message]);
|
||||
|
||||
$postID = $database->get_last_insert_id("forum_posts_id_seq");
|
||||
|
||||
log_info("forum", "Post {$postID} created by {$user->name}");
|
||||
|
||||
$database->execute("UPDATE forum_threads SET uptodate=now() WHERE id=:id", ['id'=>$threadID]);
|
||||
$database->execute("UPDATE forum_threads SET uptodate=now() WHERE id=:id", ['id' => $threadID]);
|
||||
}
|
||||
|
||||
private function delete_thread(int $threadID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("DELETE FROM forum_threads WHERE id = :id", ['id'=>$threadID]);
|
||||
$database->execute("DELETE FROM forum_posts WHERE thread_id = :thread_id", ['thread_id'=>$threadID]);
|
||||
$database->execute("DELETE FROM forum_threads WHERE id = :id", ['id' => $threadID]);
|
||||
$database->execute("DELETE FROM forum_posts WHERE thread_id = :thread_id", ['thread_id' => $threadID]);
|
||||
}
|
||||
|
||||
private function delete_post(int $postID): void
|
||||
{
|
||||
global $database;
|
||||
$database->execute("DELETE FROM forum_posts WHERE id = :id", ['id'=>$postID]);
|
||||
$database->execute("DELETE FROM forum_posts WHERE id = :id", ['id' => $postID]);
|
||||
}
|
||||
|
||||
private function threadExists(int $threadID): bool
|
||||
{
|
||||
global $database;
|
||||
$result=$database->get_one("SELECT EXISTS (SELECT * FROM forum_threads WHERE id=:id)", ['id'=>$threadID]);
|
||||
$result = $database->get_one("SELECT EXISTS (SELECT * FROM forum_threads WHERE id=:id)", ['id' => $threadID]);
|
||||
return $result == 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,20 @@ declare(strict_types=1);
|
||||
|
||||
namespace Shimmie2;
|
||||
|
||||
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)
|
||||
/**
|
||||
* @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.";
|
||||
@@ -23,33 +34,45 @@ class ForumTheme extends Themelet
|
||||
|
||||
|
||||
|
||||
public function display_new_thread_composer(Page $page, $threadText = null, $threadTitle = null)
|
||||
public function display_new_thread_composer(Page $page, string $threadText = null, string $threadTitle = null): void
|
||||
{
|
||||
global $config, $user;
|
||||
$max_characters = $config->get_int('forumMaxCharsPerPost');
|
||||
$html = make_form(make_link("forum/create"));
|
||||
|
||||
|
||||
if (!is_null($threadTitle)) {
|
||||
$threadTitle = html_escape($threadTitle);
|
||||
}
|
||||
|
||||
if (!is_null($threadText)) {
|
||||
$threadText = html_escape($threadText);
|
||||
}
|
||||
|
||||
$html .= "
|
||||
<table style='width: 500px;'>
|
||||
<tr><td>Title:</td><td><input type='text' name='title' value='$threadTitle'></td></tr>
|
||||
<tr><td>Message:</td><td><textarea id='message' name='message' >$threadText</textarea></td></tr>
|
||||
<tr><td></td><td><small>Max characters alowed: $max_characters.</small></td></tr>";
|
||||
if ($user->can(Permissions::FORUM_ADMIN)) {
|
||||
$html .= "<tr><td colspan='2'><label for='sticky'>Sticky:</label><input name='sticky' id='sticky' type='checkbox' value='Y' /></td></tr>";
|
||||
}
|
||||
$html .= "<tr><td colspan='2'><input type='submit' value='Submit' /></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
";
|
||||
$html = SHM_SIMPLE_FORM(
|
||||
"forum/create",
|
||||
TABLE(
|
||||
["style" => "width: 500px;"],
|
||||
TR(
|
||||
TD("Title:"),
|
||||
TD(INPUT(["type" => "text", "name" => "title", "value" => $threadTitle]))
|
||||
),
|
||||
TR(
|
||||
TD("Message:"),
|
||||
TD(TEXTAREA(
|
||||
["id" => "message", "name" => "message"],
|
||||
$threadText
|
||||
))
|
||||
),
|
||||
TR(
|
||||
TD(),
|
||||
TD(SMALL("Max characters allowed: $max_characters."))
|
||||
),
|
||||
$user->can(Permissions::FORUM_ADMIN) ? TR(
|
||||
TD(),
|
||||
TD(
|
||||
LABEL(["for" => "sticky"], "Sticky:"),
|
||||
INPUT(["name" => "sticky", "id" => "sticky", "type" => "checkbox", "value" => "Y"])
|
||||
)
|
||||
) : null,
|
||||
TR(
|
||||
TD(
|
||||
["colspan" => 2],
|
||||
INPUT(["type" => "submit", "value" => "Submit"])
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$blockTitle = "Write a new thread";
|
||||
$page->set_title(html_escape($blockTitle));
|
||||
@@ -57,36 +80,43 @@ class ForumTheme extends Themelet
|
||||
$page->add_block(new Block($blockTitle, $html, "main", 120));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function display_new_post_composer(Page $page, $threadID)
|
||||
public function display_new_post_composer(Page $page, int $threadID): void
|
||||
{
|
||||
global $config;
|
||||
|
||||
$max_characters = $config->get_int('forumMaxCharsPerPost');
|
||||
|
||||
$html = make_form(make_link("forum/answer"));
|
||||
|
||||
$html .= '<input type="hidden" name="threadID" value="'.$threadID.'" />';
|
||||
|
||||
$html .= "
|
||||
<table style='width: 500px;'>
|
||||
<tr><td>Message:</td><td><textarea id='message' name='message' ></textarea>
|
||||
<tr><td></td><td><small>Max characters alowed: $max_characters.</small></td></tr>
|
||||
</td></tr>";
|
||||
|
||||
$html .= "<tr><td colspan='2'><input type='submit' value='Submit' /></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
";
|
||||
$html = SHM_SIMPLE_FORM(
|
||||
"forum/answer",
|
||||
INPUT(["type" => "hidden", "name" => "threadID", "value" => $threadID]),
|
||||
TABLE(
|
||||
["style" => "width: 500px;"],
|
||||
TR(
|
||||
TD("Message:"),
|
||||
TD(TEXTAREA(["id" => "message", "name" => "message"]))
|
||||
),
|
||||
TR(
|
||||
TD(),
|
||||
TD(SMALL("Max characters allowed: $max_characters."))
|
||||
),
|
||||
TR(
|
||||
TD(
|
||||
["colspan" => 2],
|
||||
INPUT(["type" => "submit", "value" => "Submit"])
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$blockTitle = "Answer to this thread";
|
||||
$page->add_block(new Block($blockTitle, $html, "main", 130));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function display_thread($posts, $showAdminOptions, $threadTitle, $threadID, $pageNumber, $totalPages)
|
||||
/**
|
||||
* @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*/;
|
||||
|
||||
@@ -94,68 +124,70 @@ class ForumTheme extends Themelet
|
||||
|
||||
$current_post = 0;
|
||||
|
||||
$html =
|
||||
"<div id=returnLink>[<a href=".make_link("forum/index/").">Return</a>]</div><br><br>".
|
||||
"<table id='threadPosts' class='zebra'>".
|
||||
"<thead><tr>".
|
||||
"<th id=threadHeadUser>User</th>".
|
||||
"<th>Message</th>".
|
||||
"</tr></thead>";
|
||||
|
||||
$tbody = TBODY();
|
||||
foreach ($posts as $post) {
|
||||
$current_post++;
|
||||
$message = mb_convert_encoding($post["message"], "UTF-8", "HTML-ENTITIES");
|
||||
|
||||
$message = send_event(new TextFormattingEvent($message))->formatted;
|
||||
$message = str_replace('\n\r', '<br>', $message);
|
||||
$message = str_replace('\r\n', '<br>', $message);
|
||||
$message = str_replace('\n', '<br>', $message);
|
||||
$message = str_replace('\r', '<br>', $message);
|
||||
|
||||
$message = stripslashes($message);
|
||||
|
||||
$userLink = "<a href='".make_link("user/".$post["user_name"]."")."'>".$post["user_name"]."</a>";
|
||||
|
||||
$poster = User::by_name($post["user_name"]);
|
||||
$gravatar = $poster->get_avatar_html();
|
||||
|
||||
$rank = "<sup class='user_rank'>{$post["user_class"]}</sup>";
|
||||
|
||||
$postID = $post['id'];
|
||||
|
||||
//if($user->can(Permissions::FORUM_ADMIN)){
|
||||
//$delete_link = "<a href=".make_link("forum/delete/".$threadID."/".$postID).">Delete</a>";
|
||||
//} else {
|
||||
//$delete_link = "";
|
||||
//}
|
||||
|
||||
if ($showAdminOptions) {
|
||||
$delete_link = "<a href=".make_link("forum/delete/".$threadID."/".$postID).">Delete</a>";
|
||||
} else {
|
||||
$delete_link = "";
|
||||
}
|
||||
|
||||
$post_number = (($pageNumber-1)*$posts_per_page)+$current_post;
|
||||
$html .= "<tr >
|
||||
<tr class='postHead'>
|
||||
<td class='forumSupuser'></td>
|
||||
<td class='forumSupmessage'><div class=deleteLink>".$delete_link."</div></td>
|
||||
</tr>
|
||||
<tr class='posBody'>
|
||||
<td class='forumUser'>".$userLink."<br>".$rank."<br>".$gravatar."<br></td>
|
||||
<td class='forumMessage'>
|
||||
<div class=postDate><small>".autodate($post['date'])."</small></div>
|
||||
<div class=postNumber> #".$post_number."</div>
|
||||
<br>
|
||||
<div class=postMessage>".$message."</td>
|
||||
</tr>
|
||||
<tr class='postFoot'>
|
||||
<td class='forumSubuser'></td>
|
||||
<td class='forumSubmessage'></td>
|
||||
</tr>";
|
||||
$post_number = (($pageNumber - 1) * $posts_per_page) + $current_post;
|
||||
$tbody->appendChild(
|
||||
emptyHTML(
|
||||
TR(
|
||||
["class" => "postHead"],
|
||||
TD(["class" => "forumSupuser"]),
|
||||
TD(
|
||||
["class" => "forumSupmessage"],
|
||||
DIV(
|
||||
["class" => "deleteLink"],
|
||||
$showAdminOptions ? A(["href" => make_link("forum/delete/".$threadID."/".$post['id'])], "Delete") : null
|
||||
)
|
||||
)
|
||||
),
|
||||
TR(
|
||||
["class" => "posBody"],
|
||||
TD(
|
||||
["class" => "forumUser"],
|
||||
A(["href" => make_link("user/".$post["user_name"])], $post["user_name"]),
|
||||
BR(),
|
||||
SUP(["class" => "user_rank"], $post["user_class"]),
|
||||
BR(),
|
||||
rawHTML(User::by_name($post["user_name"])->get_avatar_html()),
|
||||
BR()
|
||||
),
|
||||
TD(
|
||||
["class" => "forumMessage"],
|
||||
DIV(["class" => "postDate"], SMALL(rawHTML(autodate($post['date'])))),
|
||||
DIV(["class" => "postNumber"], " #".$post_number),
|
||||
BR(),
|
||||
DIV(["class" => "postMessage"], rawHTML(send_event(new TextFormattingEvent($post["message"]))->formatted))
|
||||
)
|
||||
),
|
||||
TR(
|
||||
["class" => "postFoot"],
|
||||
TD(["class" => "forumSubuser"]),
|
||||
TD(["class" => "forumSubmessage"])
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$html .= "</tbody></table>";
|
||||
$html = emptyHTML(
|
||||
DIV(
|
||||
["id" => "returnLink"],
|
||||
A(["href" => make_link("forum/index/")], "Return")
|
||||
),
|
||||
BR(),
|
||||
BR(),
|
||||
TABLE(
|
||||
["id" => "threadPosts", "class" => "zebra"],
|
||||
THEAD(
|
||||
TR(
|
||||
TH(["id" => "threadHeadUser"], "User"),
|
||||
TH("Message")
|
||||
)
|
||||
),
|
||||
$tbody
|
||||
)
|
||||
);
|
||||
|
||||
$this->display_paginator($page, "forum/view/".$threadID, null, $pageNumber, $totalPages);
|
||||
|
||||
@@ -164,61 +196,55 @@ 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.</a>';
|
||||
|
||||
$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): string
|
||||
/**
|
||||
* @param Thread[] $threads
|
||||
*/
|
||||
private function make_thread_list(array $threads, bool $showAdminOptions): HTMLElement
|
||||
{
|
||||
$html = "<table id='threadList' class='zebra'>".
|
||||
"<thead><tr>".
|
||||
"<th>Title</th>".
|
||||
"<th>Author</th>".
|
||||
"<th>Updated</th>".
|
||||
"<th>Responses</th>";
|
||||
global $config;
|
||||
|
||||
if ($showAdminOptions) {
|
||||
$html .= "<th>Actions</th>";
|
||||
}
|
||||
$tbody = TBODY();
|
||||
$html = TABLE(
|
||||
["id" => "threadList", "class" => "zebra"],
|
||||
THEAD(
|
||||
TR(
|
||||
TH("Title"),
|
||||
TH("Author"),
|
||||
TH("Updated"),
|
||||
TH("Responses"),
|
||||
$showAdminOptions ? TH("Actions") : null
|
||||
)
|
||||
),
|
||||
$tbody
|
||||
);
|
||||
|
||||
$html .= "</tr></thead><tbody>";
|
||||
|
||||
$current_post = 0;
|
||||
foreach ($threads as $thread) {
|
||||
$oe = ($current_post++ % 2 == 0) ? "even" : "odd";
|
||||
|
||||
global $config;
|
||||
$titleSubString = $config->get_int('forumTitleSubString');
|
||||
$title = truncate($thread["title"], $titleSubString);
|
||||
|
||||
if (bool_escape($thread["sticky"])) {
|
||||
$sticky = "Sticky: ";
|
||||
} else {
|
||||
$sticky = "";
|
||||
}
|
||||
|
||||
$html .= "<tr class='$oe'>".
|
||||
'<td class="left">'.$sticky.'<a href="'.make_link("forum/view/".$thread["id"]).'">'.$title."</a></td>".
|
||||
'<td><a href="'.make_link("user/".$thread["user_name"]).'">'.$thread["user_name"]."</a></td>".
|
||||
"<td>".autodate($thread["uptodate"])."</td>".
|
||||
"<td>".$thread["response_count"]."</td>";
|
||||
|
||||
if ($showAdminOptions) {
|
||||
$html .= '<td><a href="'.make_link("forum/nuke/".$thread["id"]).'" title="Delete '.$title.'">Delete</a></td>';
|
||||
}
|
||||
|
||||
$html .= "</tr>";
|
||||
$tbody->appendChild(
|
||||
TR(
|
||||
TD(
|
||||
["class" => "left"],
|
||||
bool_escape($thread["sticky"]) ? "Sticky: " : "",
|
||||
A(["href" => make_link("forum/view/".$thread["id"])], $title)
|
||||
),
|
||||
TD(
|
||||
A(["href" => make_link("user/".$thread["user_name"])], $thread["user_name"])
|
||||
),
|
||||
TD(rawHTML(autodate($thread["uptodate"]))),
|
||||
TD($thread["response_count"]),
|
||||
$showAdminOptions ? TD(A(["href" => make_link("forum/nuke/".$thread["id"])], "Delete")) : null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$html .= "</tbody></table>";
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class FourOhFour extends Extension
|
||||
{
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $page;
|
||||
// hax.
|
||||
@@ -20,7 +20,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) {
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Shimmie2;
|
||||
|
||||
class FourOhFourTest extends ShimmiePHPUnitTestCase
|
||||
{
|
||||
public function test404Handler()
|
||||
public function test404Handler(): void
|
||||
{
|
||||
$this->get_page('not/a/page');
|
||||
// most descriptive error first
|
||||
|
||||
@@ -11,7 +11,7 @@ class GoogleAnalyticsInfo extends ExtensionInfo
|
||||
public string $key = self::KEY;
|
||||
public string $name = "Google Analytics";
|
||||
public string $url = "http://drudexsoftware.com";
|
||||
public array $authors = ["Drudex Software"=>"support@drudexsoftware.com"];
|
||||
public array $authors = ["Drudex Software" => "support@drudexsoftware.com"];
|
||||
public string $license = self::LICENSE_GPLV2;
|
||||
public string $description = "Integrates Google Analytics tracking";
|
||||
public ?string $documentation =
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Shimmie2;
|
||||
class GoogleAnalytics extends Extension
|
||||
{
|
||||
# Add analytics to config
|
||||
public function onSetupBuilding(SetupBuildingEvent $event)
|
||||
public function onSetupBuilding(SetupBuildingEvent $event): void
|
||||
{
|
||||
$sb = $event->panel->create_new_block("Google Analytics");
|
||||
$sb->add_text_option("google_analytics_id", "Analytics ID: ");
|
||||
@@ -15,7 +15,7 @@ class GoogleAnalytics extends Extension
|
||||
}
|
||||
|
||||
# Load Analytics tracking code on page request
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $page;
|
||||
|
||||
|
||||
@@ -106,14 +106,14 @@ class GraphQL extends Extension
|
||||
}
|
||||
}
|
||||
|
||||
public function onInitExt(InitExtEvent $event)
|
||||
public function onInitExt(InitExtEvent $event): void
|
||||
{
|
||||
global $config;
|
||||
$config->set_default_string('graphql_cors_pattern', "");
|
||||
$config->set_default_bool('graphql_debug', false);
|
||||
}
|
||||
|
||||
public function onPageRequest(PageRequestEvent $event)
|
||||
public function onPageRequest(PageRequestEvent $event): void
|
||||
{
|
||||
global $config, $page;
|
||||
if ($event->page_matches("graphql")) {
|
||||
@@ -125,6 +125,8 @@ class GraphQL extends Extension
|
||||
]);
|
||||
$t2 = ftime();
|
||||
$resp = $server->executeRequest();
|
||||
assert(!is_array($resp));
|
||||
assert(is_a($resp, \GraphQL\Executor\ExecutionResult::class));
|
||||
if ($config->get_bool("graphql_debug")) {
|
||||
$debug = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::RETHROW_INTERNAL_EXCEPTIONS;
|
||||
$body = $resp->toArray($debug);
|
||||
@@ -148,6 +150,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;
|
||||
@@ -159,7 +164,7 @@ class GraphQL extends Extension
|
||||
$metadata = only_strings($_POST);
|
||||
|
||||
$results = [];
|
||||
for ($n=0; $n<100; $n++) {
|
||||
for ($n = 0; $n < 100; $n++) {
|
||||
if (empty($_POST["url$n"]) && empty($_FILES["data$n"])) {
|
||||
break;
|
||||
}
|
||||
@@ -181,10 +186,9 @@ class GraphQL extends Extension
|
||||
*/
|
||||
private static function handle_upload(int $n, array $metadata): array
|
||||
{
|
||||
global $database;
|
||||
if (!empty($_POST["url$n"])) {
|
||||
return ["error" => "URLs not handled yet"];
|
||||
$tmpname = "...";
|
||||
$filename = "...";
|
||||
throw new UploadException("URLs not handled yet");
|
||||
} else {
|
||||
$ec = $_FILES["data$n"]["error"];
|
||||
switch ($ec) {
|
||||
@@ -193,7 +197,7 @@ 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:
|
||||
throw new UploadException("Mystery error: ".var_export($ec, true));
|
||||
}
|
||||
@@ -203,10 +207,10 @@ class GraphQL extends Extension
|
||||
return send_event(new DataUploadEvent($tmpname, $filename, $n, $metadata));
|
||||
});
|
||||
|
||||
return ["image_id" => $event->image_id];
|
||||
return array_map(fn ($im) => $im->id, $event->images);
|
||||
}
|
||||
|
||||
public function onCommand(CommandEvent $event)
|
||||
public function onCliGen(CliGenEvent $event): void
|
||||
{
|
||||
$event->app->register('graphql:query')
|
||||
->addArgument('query', InputArgument::REQUIRED)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user