Pulling updates from upstream

This commit is contained in:
MichaelYick 2023-05-30 02:00:09 -05:00
commit f2ee60fac5
45 changed files with 726 additions and 469 deletions

View File

@ -44,7 +44,7 @@
"shish/microcrud" : "^2.0",
"shish/microhtml" : "^2.0",
"shish/gqla" : "dev-main",
"enshrined/svg-sanitize" : "^0.15",
"enshrined/svg-sanitize" : "^0.16",
"bower-asset/jquery" : "^1.12",
"bower-asset/jquery-timeago" : "^1.5",

589
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -170,9 +170,9 @@ class Image
* @return Image[]
*/
#[Query(name: "posts", type: "[Post!]!", args: ["tags" => "[string!]"])]
public static function find_images(?int $start = 0, ?int $limit = null, array $tags=[]): array
public static function find_images(?int $offset = 0, ?int $limit = null, array $tags=[]): array
{
$result = self::find_images_internal($start, $limit, $tags);
$result = self::find_images_internal($offset, $limit, $tags);
$images = [];
foreach ($result as $row) {
@ -272,53 +272,6 @@ class Image
return (int)ceil(Image::count_images($tags) / $config->get_int(IndexConfig::IMAGES));
}
private static function terms_to_conditions(array $terms): array
{
$tag_conditions = [];
$img_conditions = [];
$stpen = 0; // search term parse event number
$order = null;
/*
* Turn a bunch of strings into a bunch of TagCondition
* and ImgCondition objects
*/
$stpe = send_event(new SearchTermParseEvent($stpen++, null, $terms));
if ($stpe->order) {
$order = $stpe->order;
} elseif (!empty($stpe->querylets)) {
foreach ($stpe->querylets as $querylet) {
$img_conditions[] = new ImgCondition($querylet, true);
}
}
foreach ($terms as $term) {
$positive = true;
if (is_string($term) && !empty($term) && ($term[0] == '-')) {
$positive = false;
$term = substr($term, 1);
}
if (strlen($term) === 0) {
continue;
}
$stpe = send_event(new SearchTermParseEvent($stpen++, $term, $terms));
if ($stpe->order) {
$order = $stpe->order;
} elseif (!empty($stpe->querylets)) {
foreach ($stpe->querylets as $querylet) {
$img_conditions[] = new ImgCondition($querylet, $positive);
}
} else {
// if the whole match is wild, skip this
if (str_replace("*", "", $term) != "") {
$tag_conditions[] = new TagCondition($term, $positive);
}
}
}
return [$tag_conditions, $img_conditions, $order];
}
/*
* Accessors & mutators
*/
@ -849,19 +802,24 @@ class Image
): Querylet {
global $config;
list($tag_conditions, $img_conditions, $order) = self::terms_to_conditions($terms);
$order = ($order ?: "images.".$config->get_string(IndexConfig::ORDER));
$tag_conditions = [];
$img_conditions = [];
$order = null;
$positive_tag_count = 0;
$negative_tag_count = 0;
foreach ($tag_conditions as $tq) {
if ($tq->positive) {
$positive_tag_count++;
} else {
$negative_tag_count++;
}
/*
* Turn a bunch of strings into a bunch of TagCondition
* and ImgCondition objects
*/
$stpen = 0; // search term parse event number
foreach (array_merge([null], $terms) as $term) {
$stpe = send_event(new SearchTermParseEvent($stpen++, $term, $terms));
$order ??= $stpe->order;
$img_conditions = array_merge($img_conditions, $stpe->img_conditions);
$tag_conditions = array_merge($tag_conditions, $stpe->tag_conditions);
}
$order = ($order ?: "images.".$config->get_string(IndexConfig::ORDER));
/*
* Turn a bunch of Querylet objects into a base query
*
@ -875,7 +833,7 @@ class Image
*/
// no tags, do a simple search
if ($positive_tag_count === 0 && $negative_tag_count === 0) {
if (count($tag_conditions) === 0) {
$query = new Querylet("SELECT images.* FROM images WHERE 1=1");
}
@ -883,21 +841,20 @@ class Image
// and do the offset / limit there, which is 10x faster than fetching
// all the image_tags and doing the offset / limit on the result.
elseif (
(
($positive_tag_count === 1 && $negative_tag_count === 0)
|| ($positive_tag_count === 0 && $negative_tag_count === 1)
)
count($tag_conditions) === 1
&& empty($img_conditions)
&& ($order == "id DESC" || $order == "images.id DESC")
&& !is_null($offset)
&& !is_null($limit)
) {
$in = $positive_tag_count === 1 ? "IN" : "NOT IN";
$tc = $tag_conditions[0];
$in = $tc->positive ? "IN" : "NOT IN";
// IN (SELECT id FROM tags) is 100x slower than doing a separate
// query and then a second query for IN(first_query_results)??
$tag_array = self::tag_or_wildcard_to_ids($tag_conditions[0]->tag);
$tag_array = self::tag_or_wildcard_to_ids($tc->tag);
if (count($tag_array) == 0) {
if ($positive_tag_count == 1) {
// if wildcard expanded to nothing, take a shortcut
if ($tc->positive) {
$query = new Querylet("SELECT images.* FROM images WHERE 1=0");
} else {
$query = new Querylet("SELECT images.* FROM images WHERE 1=1");
@ -923,7 +880,7 @@ class Image
}
}
// more than one positive tag, or more than zero negative tags
// more than one tag, or more than zero other conditions, or a non-default sort order
else {
$positive_tag_id_array = [];
$positive_wildcard_id_array = [];

View File

@ -118,4 +118,5 @@ abstract class Permissions
public const BULK_IMPORT = "bulk_import";
public const BULK_EXPORT = "bulk_export";
public const BULK_DOWNLOAD = "bulk_download";
public const BULK_PARENT_CHILD = "bulk_parent_child";
}

View File

@ -184,6 +184,7 @@ new UserClass("admin", "base", [
Permissions::EDIT_FEATURE => true,
Permissions::BULK_EDIT_VOTE => true,
Permissions::EDIT_OTHER_VOTE => true,
Permissions::CREATE_VOTE => true,
Permissions::VIEW_SYSINTO => true,
Permissions::HELLBANNED => false,
@ -222,6 +223,7 @@ new UserClass("admin", "base", [
Permissions::BULK_IMPORT =>true,
Permissions::BULK_EXPORT =>true,
Permissions::BULK_DOWNLOAD => true,
Permissions::BULK_PARENT_CHILD => true,
Permissions::SET_PRIVATE_IMAGE => true,
Permissions::SET_OTHERS_PRIVATE_IMAGES => true,

View File

@ -645,7 +645,7 @@ function _fatal_error(\Exception $e): void
foreach ($t as $n => $f) {
$c = $f['class'] ?? '';
$t = $f['type'] ?? '';
$a = implode(", ", array_map("Shimmie2\stringer", $f['args']));
$a = implode(", ", array_map("Shimmie2\stringer", $f['args'] ?? []));
print("$n: {$f['file']}({$f['line']}): {$c}{$t}{$f['function']}({$a})\n");
}

View File

@ -121,6 +121,13 @@ class Approval extends Extension
}
}
public function onUserBlockBuilding(UserBlockBuildingEvent $event)
{
global $user;
if ($user->can(Permissions::APPROVE_IMAGE)) {
$event->add_link("Pending Approval", make_link("/post/list/approved%3Ano/1"), 60);
}
}
public const SEARCH_REGEXP = "/^approved:(yes|no)/";
public function onSearchTermParse(SearchTermParseEvent $event)

View File

@ -1,7 +1,7 @@
document.addEventListener('DOMContentLoaded', () => {
var metatags = ['order:id', 'order:width', 'order:height', 'order:filesize', 'order:filename', 'order:favorites'];
$('[name="search"]').tagit({
$('.autocomplete_tags').tagit({
singleFieldDelimiter: ' ',
beforeTagAdded: function(event, ui) {
if(metatags.indexOf(ui.tagLabel) !== -1) {
@ -93,8 +93,14 @@ document.addEventListener('DOMContentLoaded', () => {
//Stop tags containing space.
if(keyCode === 32) {
e.preventDefault();
var el = $('.ui-widget-content:focus');
$('.autocomplete_tags').tagit('createTag', $(this).val());
//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();

View File

@ -17,6 +17,6 @@ class BrowserSearchInfo extends ExtensionInfo
public string $description = "Allows the user to add a browser 'plugin' to search the site with real-time suggestions";
public ?string $documentation =
"Once installed, users with an opensearch compatible browser should see their search box light up with whatever \"click here to add a search engine\" notification they have
Some code (and lots of help) by Artanis (Erik Youngren <artanis.00@gmail.com>) from the 'tagger' extension - Used with permission";
<br>
<br>Some code (and lots of help) by Artanis (<a href='mailto:artanis.00@gmail.com'>Erik Youngren</a>) from the 'tagger' extension - Used with permission";
}

View File

@ -13,5 +13,26 @@ class BulkActionsInfo extends ExtensionInfo
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 Christian Walde <walde.christian@googlemail.com>, contributions by Shish and Agasa.";
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.
<p>
<p>
<b>Delete</b>
<br>Deletes all selected posts.
</p>
<p>
<b>Tag</b>
<br>Add the tags to all selected posts.
<br><code>[background wallpaper]</code> + <code>[sky]</code> <code>[background wallpaper sky]</code>
<br>
<br>Remove the tags from all selected posts.
<br><code>[background wallpaper]</code> + <code>[-wallpaper]</code> <code>[background]</code>
<br>
<br>Replace the tags in all selected posts.
<br><code>[background wallpaper]</code> + <code>[sky]</code> <code>[sky]</code>
</p>
<p>
<b>Source</b>
<br>Sets the source of all selected posts.
</p>
</p>";
}

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
class BulkParentChildInfo extends ExtensionInfo
{
public const KEY = "bulk_parent_child";
public string $key = self::KEY;
public string $name = "Bulk Parent Child";
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];
}

View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Shimmie2;
class BulkParentChildConfig
{
}
class BulkParentChildException extends BulkActionException
{
}
class BulkParentChild extends Extension
{
private const PARENT_CHILD_ACTION_NAME = "bulk_parent_child";
public function onBulkActionBlockBuilding(BulkActionBlockBuildingEvent $event)
{
global $user;
if ($user->can(Permissions::BULK_PARENT_CHILD)) {
$event->add_action(BulkParentChild::PARENT_CHILD_ACTION_NAME, "Set Parent Child");
}
}
public function onBulkAction(BulkActionEvent $event)
{
global $user, $page, $config;
if ($user->can(Permissions::BULK_PARENT_CHILD)&&
($event->action == BulkParentChild::PARENT_CHILD_ACTION_NAME)) {
$prev_id = null;
foreach ($event->items as $image) {
if ($prev_id != null) {
send_event(new ImageRelationshipSetEvent($image->id, $prev_id));
}
$prev_id = $image->id;
}
}
}
}

View File

@ -216,6 +216,13 @@ class CommentList extends Extension
}
}
public function onRobotsBuilding(RobotsBuildingEvent $event)
{
// comment lists change all the time, crawlers should
// index individual image's comments
$event->add_disallow("comment");
}
private function onPageRequest_add()
{
global $user, $page;

View File

@ -37,7 +37,7 @@ class CommentListTheme extends Themelet
$page->set_title("Comments");
$page->set_heading("Comments");
$page->add_block(new Block("Navigation", $nav, "left"));
$page->add_block(new Block("Navigation", $nav, "left", 0));
$this->display_paginator($page, "comment/list", null, $page_number, $total_pages);
// parts for each image

View File

@ -16,10 +16,10 @@ class CustomHtmlHeadersInfo extends ExtensionInfo
public string $description = "Allows admins to modify & set custom &lt;head&gt; content";
public ?string $documentation =
"When you go to board config you can find a block named Custom HTML Headers.
In that block you can simply place any thing you can place within &lt;head&gt;&lt;/head&gt;
This can be useful if you want to add website tracking code or other javascript.
NOTE: Only use if you know what you're doing.
You can also add your website name as prefix or suffix to the title of each page on your website.";
<br>In that block you can simply place any thing you can place within &lt;head&gt;&lt;/head&gt;
<br>
<br>This can be useful if you want to add website tracking code or other javascript.
<br>NOTE: Only use if you know what you're doing.
<br>
<br>You can also add your website name as prefix or suffix to the title of each page on your website.";
}

View File

@ -13,7 +13,7 @@ class DanbooruApiInfo extends ExtensionInfo
public array $authors = ["JJS"=>"jsutinen@gmail.com"];
public string $description = "Allow Danbooru apps like Danbooru Uploader for Firefox to communicate with Shimmie";
public ?string $documentation =
"<p>Notes:
"<b>Notes</b>:
<br>danbooru API based on documentation from danbooru 1.0 -
http://attachr.com/7569
<br>I've only been able to test add_post and find_tags because I use the
@ -24,34 +24,32 @@ class DanbooruApiInfo extends ExtensionInfo
<li>find_posts - sort of works, filename is returned as the original filename and probably won't help when it comes to actually downloading it
<li>find_tags - id, name, and after_id all work but the tags parameter is ignored just like danbooru 1.0 ignores it
</ul>
CHANGELOG
13-OCT-08 8:00PM CST - JJS
Bugfix - Properly escape source attribute
17-SEP-08 10:00PM CST - JJS
Bugfix for changed page name checker in PageRequestEvent
13-APR-08 10:00PM CST - JJS
Properly escape the tags returned in find_tags and find_posts - Caught by ATravelingGeek
Updated extension info to be a bit more clear about its purpose
Deleted add_comment code as it didn't do anything anyway
01-MAR-08 7:00PM CST - JJS
Rewrote to make it compatible with Shimmie trunk again (r723 at least)
It may or may not support the new file handling stuff correctly, I'm only testing with images and the danbooru uploader for firefox
21-OCT-07 9:07PM CST - JJS
Turns out I actually did need to implement the new parameter names
for danbooru api v1.8.1. Now danbooruup should work when used with /api/danbooru/post/create.xml
Also correctly redirects the url provided by danbooruup in the event
of a duplicate image.
19-OCT-07 4:46PM CST - JJS
Add compatibility with danbooru api v1.8.1 style urls
for find_posts and add_post. NOTE: This does not implement
the changes to the parameter names, it is simply a
workaround for the latest danbooruup firefox extension.
Completely compatibility will probably involve a rewrite with a different URL
";
<br><b>CHANGELOG</b>
<br>13-OCT-08 8:00PM CST - JJS
<br>Bugfix - Properly escape source attribute
<br>
<br>17-SEP-08 10:00PM CST - JJS
<br>Bugfix for changed page name checker in PageRequestEvent
<br>
<br>13-APR-08 10:00PM CST - JJS
<br>Properly escape the tags returned in find_tags and find_posts - Caught by ATravelingGeek
<br>Updated extension info to be a bit more clear about its purpose
<br>Deleted add_comment code as it didn't do anything anyway
<br>
<br>01-MAR-08 7:00PM CST - JJS
<br>Rewrote to make it compatible with Shimmie trunk again (r723 at least)
<br>It may or may not support the new file handling stuff correctly, I'm only testing with images and the danbooru uploader for firefox
<br>
<br>21-OCT-07 9:07PM CST - JJS
<br>Turns out I actually did need to implement the new parameter names
<br>for danbooru api v1.8.1. Now danbooruup should work when used with /api/danbooru/post/create.xml
<br>Also correctly redirects the url provided by danbooruup in the event
<br>of a duplicate image.
<br>
<br>19-OCT-07 4:46PM CST - JJS
<br>Add compatibility with danbooru api v1.8.1 style urls
<br>for find_posts and add_post. NOTE: This does not implement
<br>the changes to the parameter names, it is simply a
<br>workaround for the latest danbooruup firefox extension.
<br>Completely compatibility will probably involve a rewrite with a different URL";
}

View File

@ -10,6 +10,31 @@ use GraphQL\Error\DebugFlag;
use GraphQL\Type\Schema;
use GraphQL\Utils\SchemaPrinter;
#[\GQLA\InputObjectType]
class MetadataInput
{
public function __construct(
#[\GQLA\Field]
public string $tags,
#[\GQLA\Field]
public string $source,
) {
}
#[\GQLA\Mutation]
public static function update_post_metadata(int $post_id, MetadataInput $metadata): Image
{
global $user;
$_POST['tag_edit__tags'] = $metadata->tags;
$_POST['tag_edit__source'] = $metadata->source;
$image = Image::by_id($post_id);
if (!$image->is_locked() || $user->can(Permissions::EDIT_IMAGE_LOCK)) {
send_event(new ImageInfoSetEvent($image));
}
return Image::by_id($post_id);
}
}
class GraphQL extends Extension
{
public static function get_schema(): Schema
@ -73,6 +98,7 @@ class GraphQL extends Extension
$body['stats'] = get_debug_info_arr();
$body['stats']['graphql_schema_time'] = round($t2 - $t1, 2);
$body['stats']['graphql_execute_time'] = round($t3 - $t2, 2);
// sleep(1);
$page->set_mode(PageMode::DATA);
$page->set_mime("application/json");
$page->set_data(\json_encode($body, JSON_UNESCAPED_UNICODE));

View File

@ -33,7 +33,7 @@ class ImageIO extends Extension
public const THUMBNAIL_TYPES = [
'JPEG' => MimeType::JPEG,
'WEBP (Not IE/Safari compatible)' => MimeType::WEBP
'WEBP (Not IE compatible)' => MimeType::WEBP
];
public function onInitExt(InitExtEvent $event)
@ -196,6 +196,19 @@ class ImageIO extends Extension
$event->image->delete();
}
public function onCommand(CommandEvent $event)
{
if ($event->cmd == "help") {
print "\tdelete <post id>\n";
print "\t\tdelete a specific post\n\n";
}
if ($event->cmd == "delete") {
$post_id = (int)$event->args[0];
$image = Image::by_id($post_id);
send_event(new ImageDeletionEvent($image));
}
}
public function onImageReplace(ImageReplaceEvent $event)
{
try {

View File

@ -12,23 +12,48 @@ class SearchTermParseEvent extends Event
{
public int $id = 0;
public ?string $term = null;
public bool $positive = true;
/** @var string[] */
public array $context = [];
/** @var Querylet[] */
public array $querylets = [];
/** @var ImgCondition[] */
public array $img_conditions = [];
/** @var TagCondition[] */
public array $tag_conditions = [];
public ?string $order = null;
public function __construct(int $id, string $term=null, array $context=[])
{
parent::__construct();
if ($term == "-" || $term == "*") {
throw new SearchTermParseException("'$term' is not a valid search term");
}
$positive = true;
if (is_string($term) && !empty($term) && ($term[0] == '-')) {
$positive = false;
$term = substr($term, 1);
}
$this->id = $id;
$this->positive = $positive;
$this->term = $term;
$this->context = $context;
}
public function add_querylet(Querylet $q)
{
$this->querylets[] = $q;
$this->add_img_condition(new ImgCondition($q, $this->positive));
}
public function add_img_condition(ImgCondition $c)
{
$this->img_conditions[] = $c;
}
public function add_tag_condition(TagCondition $c)
{
$this->tag_conditions[] = $c;
}
}

View File

@ -257,5 +257,16 @@ class Index extends Extension
$seed = date("Ymd");
$event->order = "RAND($seed)";
}
// If we've reached this far, and nobody else has done anything with this term, then treat it as a tag
if ($event->order == null && $event->img_conditions == [] && $event->tag_conditions == []) {
$event->add_tag_condition(new TagCondition($event->term, $event->positive));
}
}
public function get_priority(): int
{
// we want to turn a search term into a TagCondition only if nobody did anything else with that term
return 95;
}
}

View File

@ -6,5 +6,6 @@
box-shadow: none;
margin: 0px;
padding: 0px;
text-align: justify;
text-align: left;
margin: 0 10px 10px 0;
}

View File

@ -85,20 +85,20 @@ class Media extends Extension
{
$sb = $event->panel->create_new_block("Media Engines");
// if (self::imagick_available()) {
// try {
// $image = new Imagick(realpath('tests/favicon.png'));
// $image->clear();
// $sb->add_label("ImageMagick detected");
// } catch (ImagickException $e) {
// $sb->add_label("<b style='color:red'>ImageMagick not detected</b>");
// }
// } else {
// if (self::imagick_available()) {
// try {
// $image = new Imagick(realpath('tests/favicon.png'));
// $image->clear();
// $sb->add_label("ImageMagick detected");
// } catch (ImagickException $e) {
// $sb->add_label("<b style='color:red'>ImageMagick not detected</b>");
// }
// } else {
$sb->start_table();
$sb->add_table_header("Commands");
$sb->add_text_option(MediaConfig::CONVERT_PATH, "convert", true);
// }
// }
$sb->add_text_option(MediaConfig::FFMPEG_PATH, "ffmpeg", true);
$sb->add_text_option(MediaConfig::FFPROBE_PATH, "ffprobe", true);
@ -202,8 +202,8 @@ class Media extends Extension
break;
case MediaEngine::IMAGICK:
// if (self::imagick_available()) {
// } else {
// if (self::imagick_available()) {
// } else {
self::image_resize_convert(
$event->input_path,
$event->input_mime,
@ -227,9 +227,9 @@ class Media extends Extension
}
// TODO: Get output optimization tools working better
// if ($config->get_bool("thumb_optim", false)) {
// exec("jpegoptim $outname", $output, $ret);
// }
// if ($config->get_bool("thumb_optim", false)) {
// exec("jpegoptim $outname", $output, $ret);
// }
}
public const CONTENT_SEARCH_TERM_REGEX = "/^content[=|:]((video)|(audio)|(image)|(unknown))$/i";

View File

@ -63,12 +63,12 @@ abstract class VideoCodecs
//
// public static function is_input_supported(string $engine, string $mime): bool
// {
// return MimeType::matches_array(
// $mime,
// MediaEngine::INPUT_SUPPORT[$engine]
// );
// }
//
// public static function is_input_supported(string $engine, string $mime): bool
// {
// return MimeType::matches_array(
// $mime,
// MediaEngine::INPUT_SUPPORT[$engine]
// );
// }
}

View File

@ -251,9 +251,11 @@ class MimeType
$output = MimeType::PPM;
break;
// TODO: There is no uniquely defined Mime type for the cursor format. Need to figure this out.
// case FileExtension::CUR:
// $output = MimeType::CUR;
// break;
/*
case FileExtension::CUR:
$output = MimeType::CUR;
break;
*/
}
}
}

View File

@ -76,7 +76,7 @@ class PrivateImage extends Extension
throw new SCoreException("Post not found.");
}
if ($image->owner_id!=$user->can(Permissions::SET_OTHERS_PRIVATE_IMAGES)) {
throw new SCoreException("Cannot set another user's image to private.");
throw new SCoreException("Cannot set another user's image to public.");
}
self::publicize_image($image_id);
@ -114,7 +114,7 @@ class PrivateImage extends Extension
{
global $user, $page;
if ($event->image->private===true && $event->image->owner_id!=$user->id && !$user->can(Permissions::SET_OTHERS_PRIVATE_IMAGES)) {
if ($event->image->private==true && $event->image->owner_id!=$user->id && !$user->can(Permissions::SET_OTHERS_PRIVATE_IMAGES)) {
$page->set_mode(PageMode::REDIRECT);
$page->set_redirect(make_link("post/list"));
}
@ -221,7 +221,7 @@ class PrivateImage extends Extension
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
{
global $user;
if ($user->can(Permissions::SET_PRIVATE_IMAGE) && $user->id==$event->image->owner_id) {
if (($user->can(Permissions::SET_PRIVATE_IMAGE) && $user->id==$event->image->owner_id) || $user->can(Permissions::SET_OTHERS_PRIVATE_IMAGES)) {
$event->add_part($this->theme->get_image_admin_html($event->image));
}
}

View File

@ -10,7 +10,7 @@ class PrivateImageTheme extends Themelet
{
public function get_image_admin_html(Image $image): string
{
if ($image->private===false) {
if ($image->private==false) {
$html = SHM_SIMPLE_FORM(
'privatize_image/'.$image->id,
INPUT(["type"=>'hidden', "name"=>'image_id', "value"=>$image->id]),

View File

@ -13,9 +13,9 @@ class QRImageInfo extends ExtensionInfo
public string $url = "http://seemslegit.com";
public array $authors = ["Zach Hall"=>"zach@sosguy.net"];
public string $license = self::LICENSE_GPLV2;
public string $description = "Turns BBCode into HTML";
public string $description = "Shows a QR Code for downloading a post to cell phones";
public ?string $documentation =
"Shows a QR Code for downloading a post to cell phones.
Based on Artanis's Link to Post Extension <artanis.00@gmail.com>
Further modified by Shish to remove the 7MB local QR generator and replace it with a link to google chart APIs";
<br>Based on <a href='mailto:artanis.00@gmail.com'>Artanis</a>'s Link to Post Extension.
<br>Further modified by Shish to remove the 7MB local QR generator and replace it with a link to Google Chart APIs";
}

View File

@ -153,7 +153,7 @@ class Ratings extends Extension
$options[$rating->name] = $rating->code;
}
$sb = $event->panel->create_new_block("Post Ratings");
$sb = $event->panel->create_new_block("Post Rating Visibility");
$sb->start_table();
foreach (array_keys($_shm_user_classes) as $key) {
if ($key == "base" || $key == "hellbanned") {

View File

@ -101,6 +101,14 @@ class Rule34 extends Extension
}
}
public function onRobotsBuilding(RobotsBuildingEvent $event)
{
// robots should only check the canonical site, not mirrors
if ($_SERVER['HTTP_HOST'] != "rule34.paheal.net") {
$event->add_disallow("");
}
}
public function onPageRequest(PageRequestEvent $event)
{
global $database, $page, $user;

View File

@ -51,6 +51,11 @@ class SourceHistory extends Extension
}
}
public function onRobotsBuilding(RobotsBuildingEvent $event)
{
$event->add_disallow("source_history");
}
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
{
$event->add_part("

View File

@ -4,11 +4,34 @@ declare(strict_types=1);
namespace Shimmie2;
class RobotsBuildingEvent extends Event
{
public array $parts = [
"User-agent: *",
// Site is rate limited to 1 request / sec,
// returns 503 for more than that
"Crawl-delay: 3",
];
public function add_disallow(string $path): void
{
$this->parts[] = "Disallow: /$path";
}
}
class StaticFiles extends Extension
{
public function onPageRequest(PageRequestEvent $event)
{
global $config, $page;
if ($event->page_matches("robots.txt")) {
$rbe = send_event(new RobotsBuildingEvent());
$page->set_mode(PageMode::DATA);
$page->set_mime("text/plain");
$page->set_data(join("\n", $rbe->parts));
}
// hax.
if ($page->mode == PageMode::PAGE && (!isset($page->blocks) || $this->count_main($page->blocks) == 0)) {
$h_pagename = html_escape(implode('/', $event->args));

View File

@ -1,4 +1,4 @@
These files can be overriden by placing files in
themes/$your_theme/filename.foo. For example if
themes/$your_theme/static/filename.foo. For example if
you want your theme "radiance" to have a custom
favicon, place it in themes/radiance/favicon.ico
favicon, place it in themes/radiance/static/favicon.ico

View File

@ -1,11 +0,0 @@
User-agent: *
# comment lists change all the time, crawlers should
# index individual image's comments
Disallow: /comment/
# next and prev are just CPU-heavier ways of getting
# to the same images that the index shows
Disallow: /post/next/
Disallow: /post/prev/
# Site is rate limited to 1 request / sec,
# returns 503 for more than that
Crawl-delay: 3

View File

@ -33,7 +33,7 @@ class SourceSetEvent extends Event
{
parent::__construct();
$this->image = $image;
$this->source = $source;
$this->source = trim($source);
}
}

View File

@ -51,6 +51,11 @@ class TagHistory extends Extension
}
}
public function onRobotsBuilding(RobotsBuildingEvent $event)
{
$event->add_disallow("tag_history");
}
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event)
{
$event->add_part("

View File

@ -211,7 +211,7 @@ class TagListTheme extends Themelet
);
$main_html .= "&nbsp;<br><a class='more' href='".make_link("tags")."'>Full List</a>\n";
$page->add_block(new Block("refine Search", $main_html, "left", 60));
$page->add_block(new Block("Refine Search", $main_html, "left", 60));
}
public function return_tag(array $row, array $tag_category_dict): array

View File

@ -167,6 +167,18 @@ class TranscodeImage extends Extension
{
global $config;
// this onDataUpload happens earlier (or could happen earlier) than handle_pixel.onDataUpload
// it mutates the image such that the incorrect mime type is not checked (checking against
// the post-transcode mime type instead). This is to give user feedback on what the mime type
// was before potential transcoding (the original) at the time of upload, and that it failed if not allowed.
// does it break bulk image importing? ZIP? SVG? there are a few flows that are untested!
if ($config->get_bool(UploadConfig::MIME_CHECK_ENABLED) == true) {
$allowed_mimes = $config->get_array(UploadConfig::ALLOWED_MIME_STRINGS);
if (!MimeType::matches_array($event->mime, $allowed_mimes)) {
throw new UploadException("MIME type not supported: " . $event->mime);
}
}
if ($config->get_bool(TranscodeConfig::UPLOAD) == true) {
if ($event->mime === MimeType::GIF&&MimeType::is_animated_gif($event->tmpname)) {
return;

View File

@ -65,37 +65,37 @@ class TranscodeVideo extends Extension
$sb->end_table();
}
/*
public function onDataUpload(DataUploadEvent $event)
{
// global $config;
//
// if ($config->get_bool(TranscodeVideoConfig::UPLOAD) == true) {
// $ext = strtolower($event->type);
//
// $ext = Media::normalize_format($ext);
//
// if ($event->type=="gif"&&Media::is_animated_gif($event->tmpname)) {
// return;
// }
//
// if (in_array($ext, array_values(self::INPUT_FORMATS))) {
// $target_format = $config->get_string(TranscodeVideoConfig::UPLOAD_PREFIX.$ext);
// if (empty($target_format)) {
// return;
// }
// try {
// $new_image = $this->transcode_image($event->tmpname, $ext, $target_format);
// $event->set_tmpname($new_image, Media::determine_ext($target_format));
// } catch (Exception $e) {
// log_error("transcode_video", "Error while performing upload transcode: ".$e->getMessage());
// // We don't want to interfere with the upload process,
// // so if something goes wrong the untranscoded image jsut continues
// }
// }
// }
global $config;
if ($config->get_bool(TranscodeVideoConfig::UPLOAD) == true) {
$ext = strtolower($event->type);
$ext = Media::normalize_format($ext);
if ($event->type=="gif"&&Media::is_animated_gif($event->tmpname)) {
return;
}
if (in_array($ext, array_values(self::INPUT_FORMATS))) {
$target_format = $config->get_string(TranscodeVideoConfig::UPLOAD_PREFIX.$ext);
if (empty($target_format)) {
return;
}
try {
$new_image = $this->transcode_image($event->tmpname, $ext, $target_format);
$event->set_tmpname($new_image, Media::determine_ext($target_format));
} catch (Exception $e) {
log_error("transcode_video", "Error while performing upload transcode: ".$e->getMessage());
// We don't want to interfere with the upload process,
// so if something goes wrong the untranscoded image jsut continues
}
}
}
}
*/
public function onPageRequest(PageRequestEvent $event)
{

View File

@ -11,4 +11,6 @@ class UploadConfig
public const MIN_FREE_SPACE = "upload_min_free_space";
public const TLSOURCE = "upload_tlsource";
public const TRANSLOAD_ENGINE = "transload_engine";
public const MIME_CHECK_ENABLED = "mime_check_enabled";
public const ALLOWED_MIME_STRINGS = "allowed_mime_strings";
}

View File

@ -98,6 +98,12 @@ class Upload extends Extension
}
}
}
$config->set_default_bool(UploadConfig::MIME_CHECK_ENABLED, false);
$config->set_default_array(
UploadConfig::ALLOWED_MIME_STRINGS,
DataHandlerExtension::get_all_supported_mimes()
);
}
public function onSetupBuilding(SetupBuildingEvent $event)
@ -119,8 +125,21 @@ class Upload extends Extension
$sb->add_label("<i>PHP Limit = " . ini_get('upload_max_filesize') . "</i>");
$sb->add_choice_option(UploadConfig::TRANSLOAD_ENGINE, $tes, "<br/>Transload: ");
$sb->add_bool_option(UploadConfig::TLSOURCE, "<br/>Use transloaded URL as source if none is provided: ");
$sb->start_table();
$sb->add_bool_option(UploadConfig::MIME_CHECK_ENABLED, "Enable upload MIME checks", true);
$sb->add_multichoice_option(UploadConfig::ALLOWED_MIME_STRINGS, $this->get_mime_options(), "Allowed MIME uploads", true);
$sb->end_table();
}
private function get_mime_options(): array
{
$output = [];
foreach (DataHandlerExtension::get_all_supported_mimes() as $mime) {
$output[MimeMap::get_name_for_mime($mime)] = $mime;
}
return $output;
}
public function onPageNavBuilding(PageNavBuildingEvent $event)
{

View File

@ -345,8 +345,8 @@ class UserPage extends Extension
$sb->add_choice_option(
"user_loginshowprofile",
[
"return to previous page" => 0, // 0 is default
"send to user profile" => 1],
"Return to previous page" => 0, // 0 is default
"Send to user profile" => 1],
"On log in/out",
true
);
@ -422,7 +422,7 @@ class UserPage extends Extension
if (!$user->can(Permissions::CREATE_USER)) {
throw new UserCreationException("Account creation is currently disabled");
}
if (!$config->get_bool("login_signup_enabled")) {
if (!$config->get_bool("login_signup_enabled") && !$user->can(Permissions::CREATE_OTHER_USER)) {
throw new UserCreationException("Account creation is currently disabled");
}
if (strlen($name) < 1) {

View File

@ -94,6 +94,14 @@ class ViewImage extends Extension
}
}
public function onRobotsBuilding(RobotsBuildingEvent $event)
{
// next and prev are just CPU-heavier ways of getting
// to the same images that the index shows
$event->add_disallow("post/next");
$event->add_disallow("post/prev");
}
public function onDisplayingImage(DisplayingImageEvent $event)
{
global $page, $user;

View File

@ -9,7 +9,7 @@ class CustomUploadTheme extends UploadTheme
// public function display_block(Page $page) {
// $page->add_block(new Block("Upload", $this->build_upload_block(), "left", 20));
// }
//
//
// public function display_full(Page $page) {
// $page->add_block(new Block("Upload", "Disk nearly full, uploads disabled", "left", 20));
// }

View File

@ -87,7 +87,7 @@
</ul>
<ul>
<li><a href="https://s.zlinkb.com/d.php?z=3832265" target="_blank">[Check out our partners!]</a></li>
<li><a href="https://s.zlinkb.com/d.php?z=3832265" target="_blank">Adult games! &#127918;</a></li>
</ul>
</div>

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB