diff --git a/core/imageboard/image.php b/core/imageboard/image.php index d7539876..adcfb7cf 100644 --- a/core/imageboard/image.php +++ b/core/imageboard/image.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Shimmie2; +use GQLA\Expose; + /** * Class Image * @@ -13,18 +15,27 @@ namespace Shimmie2; * image per se, but could be a video, sound file, or any * other supported upload type. */ +#[Expose(name: "Post")] class Image { public const IMAGE_DIR = "images"; public const THUMBNAIL_DIR = "thumbs"; + #[Expose] public ?int $id = null; + #[Expose] public int $height = 0; + #[Expose] public int $width = 0; + #[Expose] public string $hash; + #[Expose] public int $filesize; + #[Expose] public string $filename; + #[Expose] private string $ext; + #[Expose] private string $mime; /** @var ?string[] */ @@ -73,6 +84,7 @@ class Image } } + #[Expose(extends: "Query", name: "post_by_id")] public static function by_id(int $id): ?Image { global $database; @@ -142,7 +154,8 @@ class Image * #param string[] $tags * #return Image[] */ - public static function find_images(int $start, ?int $limit = null, array $tags=[]): array + #[Expose(extends: "Query", name: "posts", type: "[Post]", args: ["tags" => "[string]"])] + public static function find_images(?int $start = 0, ?int $limit = null, array $tags=[]): array { $result = self::find_images_internal($start, $limit, $tags); @@ -349,6 +362,7 @@ class Image /** * Find the User who owns this Image */ + #[Expose(name: "owner")] public function get_owner(): User { return User::by_id($this->owner_id); @@ -449,6 +463,7 @@ class Image * * #return string[] */ + #[Expose(name: "tags", type: "[string]")] public function get_tag_array(): array { global $database; @@ -476,6 +491,7 @@ class Image /** * Get the URL for the full size image */ + #[Expose(name: "image_link")] public function get_image_link(): string { return $this->get_link(ImageConfig::ILINK, '_images/$hash/$id%20-%20$tags.$ext', 'image/$id.$ext'); @@ -484,6 +500,7 @@ class Image /** * Get the nicely formatted version of the file name */ + #[Expose(name: "nice_name")] public function get_nice_image_name(): string { $plte = new ParseLinkTemplateEvent('$id - $tags.$ext', $this); @@ -494,6 +511,7 @@ class Image /** * Get the URL for the thumbnail */ + #[Expose(name: "thumb_link")] public function get_thumb_link(): string { global $config; @@ -528,6 +546,7 @@ class Image * Get the tooltip for this image, formatted according to the * configured template. */ + #[Expose(name: "tooltip")] public function get_tooltip(): string { global $config; @@ -540,6 +559,7 @@ class Image * Get the info for this image, formatted according to the * configured template. */ + #[Expose(name: "info")] public function get_info(): string { global $config; diff --git a/core/imageboard/tag.php b/core/imageboard/tag.php index 89743998..d49bbce3 100644 --- a/core/imageboard/tag.php +++ b/core/imageboard/tag.php @@ -4,6 +4,75 @@ declare(strict_types=1); namespace Shimmie2; +use GQLA\Expose; + +#[Expose(name: "TagUsage")] +class TagUsage { + #[Expose] + public string $tag; + #[Expose] + public int $uses; + + public function __construct(string $tag, int $uses) + { + $this->tag = $tag; + $this->uses = $uses; + } + + #[Expose(extends: "Query", name: "tags", type: '[TagUsage]')] + public static function tags(string $search, int $limit=10): array { + global $cache, $database; + + if (!$search) { + return []; + } + + $search = strtolower($search); + if ( + $search == '' || + $search[0] == '_' || + $search[0] == '%' || + strlen($search) > 32 + ) { + return []; + } + + $cache_key = "tagusage-$search"; + $limitSQL = ""; + $search = str_replace('_', '\_', $search); + $search = str_replace('%', '\%', $search); + $SQLarr = ["search"=>"$search%"]; #, "cat_search"=>"%:$search%"]; + if ($limit !== 0) { + $limitSQL = "LIMIT :limit"; + $SQLarr['limit'] = $limit; + $cache_key .= "-" . $limit; + } + + $res = $cache->get($cache_key); + if (!$res) { + $res = $database->get_pairs( + " + SELECT tag, count + FROM tags + WHERE LOWER(tag) LIKE LOWER(:search) + -- OR LOWER(tag) LIKE LOWER(:cat_search) + AND count > 0 + ORDER BY count DESC + $limitSQL + ", + $SQLarr + ); + $cache->set($cache_key, $res, 600); + } + + $counts = []; + foreach($res as $k => $v) { + $counts[] = new TagUsage($k, $v); + } + return $counts; + } +} + /** * Class Tag * diff --git a/core/user.php b/core/user.php index 87f8d5f4..30e97e1f 100644 --- a/core/user.php +++ b/core/user.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Shimmie2; +use GQLA\Expose; + function _new_user(array $row): User { return new User($row); @@ -17,9 +19,12 @@ function _new_user(array $row): User * * The currently logged in user will always be accessible via the global variable $user. */ +#[Expose(name: "User")] class User { + #[Expose] public int $id; + #[Expose] public string $name; public ?string $email; public string $join_date; @@ -58,6 +63,13 @@ class User } } + #[Expose(extends: "Query")] + public static function me(): User + { + global $user; + return $user; + } + public static function by_session(string $name, string $session): ?User { global $cache, $config, $database; diff --git a/ext/comment/main.php b/ext/comment/main.php index 5f9402f0..449ebe27 100644 --- a/ext/comment/main.php +++ b/ext/comment/main.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Shimmie2; +use GQLA\Expose; + require_once "vendor/ifixit/php-akismet/akismet.class.php"; class CommentPostingEvent extends Event @@ -41,6 +43,7 @@ class CommentPostingException extends SCoreException { } +#[Expose(name: "Comment")] class Comment { public ?User $owner; @@ -48,10 +51,12 @@ class Comment public string $owner_name; public ?string $owner_email; public string $owner_class; + #[Expose] public string $comment; public int $comment_id; public int $image_id; public string $poster_ip; + #[Expose] public string $posted; public function __construct($row) @@ -78,6 +83,7 @@ class Comment ", ["owner_id"=>$user->id]); } + #[Expose(name: "owner")] public function get_owner(): User { if (empty($this->owner)) { @@ -85,6 +91,18 @@ class Comment } return $this->owner; } + + #[Expose(extends: "Post", name: "comments", type: "[Comment]")] + public function get_comments(Image $post): array { + return CommentList::get_comments($post->id); + } + + #[Expose(extends: "Mutation", name: "create_comment")] + public function create_comment(int $post_id, string $comment): bool { + global $user; + send_event(new CommentPostingEvent($post_id, $user, $comment)); + return true; + } } class CommentList extends Extension @@ -427,7 +445,7 @@ class CommentList extends Extension /** * #return Comment[] */ - private function get_generic_comments(string $query, array $args): array + private static function get_generic_comments(string $query, array $args): array { global $database; $rows = $database->get_all($query, $args); @@ -441,9 +459,9 @@ class CommentList extends Extension /** * #return Comment[] */ - private function get_recent_comments(int $count): array + private static function get_recent_comments(int $count): array { - return $this->get_generic_comments(" + return CommentList::get_generic_comments(" SELECT users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class, comments.comment as comment, comments.id as comment_id, @@ -459,9 +477,9 @@ class CommentList extends Extension /** * #return Comment[] */ - private 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 $this->get_generic_comments(" + return CommentList::get_generic_comments(" SELECT users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class, comments.comment as comment, comments.id as comment_id, @@ -476,11 +494,12 @@ class CommentList extends Extension } /** + * public just for Image::get_comments() * #return Comment[] */ - private function get_comments(int $image_id): array + public static function get_comments(int $image_id): array { - return $this->get_generic_comments(" + return CommentList::get_generic_comments(" SELECT users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class, comments.comment as comment, comments.id as comment_id, diff --git a/ext/graphql/info.php b/ext/graphql/info.php new file mode 100644 index 00000000..c6bfce05 --- /dev/null +++ b/ext/graphql/info.php @@ -0,0 +1,17 @@ +page_matches("graphql")) { + $t1 = ftime(); + $server = new StandardServer([ + 'schema' => \GQLA\genSchema(), + ]); + $t2 = ftime(); + $resp = $server->executeRequest(); + $body = $resp->toArray(); + $t3 = ftime(); + $body['stats'] = get_debug_info_arr(); + $body['stats']['graphql_schema_time'] = round($t2 - $t1, 2); + $body['stats']['graphql_execute_time'] = round($t3 - $t2, 2); + $page->set_mode(PageMode::DATA); + $page->set_mime("application/json"); + $page->set_data(\json_encode($body, JSON_UNESCAPED_UNICODE)); + } + } + + public function onCommand(CommandEvent $event) + { + if ($event->cmd == "help") { + print "\tgraphql \n"; + print "\t\teg 'graphql \"{ post_by_id(id: 18) { id, hash } }\"'\n\n"; + print "\tgraphql-schema\n"; + print "\t\tdump the schema\n\n"; + } + if ($event->cmd == "graphql") { + $t1 = ftime(); + $schema = \GQLA\genSchema(); + $t2 = ftime(); + $debug = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::RETHROW_INTERNAL_EXCEPTIONS; + $body = GQL::executeQuery($schema, $event->args[0])->toArray($debug); + $t3 = ftime(); + $body['stats'] = get_debug_info_arr(); + $body['stats']['graphql_schema_time'] = round($t2 - $t1, 2); + $body['stats']['graphql_execute_time'] = round($t3 - $t2, 2); + echo \json_encode($body, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); + } + if ($event->cmd == "graphql-schema") { + $schema = \GQLA\genSchema(); + echo(SchemaPrinter::doPrint($schema)); + } + } +} diff --git a/ext/graphql/test.php b/ext/graphql/test.php new file mode 100644 index 00000000..a0f200e2 --- /dev/null +++ b/ext/graphql/test.php @@ -0,0 +1,14 @@ +assertValid(); + } +} diff --git a/ext/pm/main.php b/ext/pm/main.php index f5c6017a..2e07a1b0 100644 --- a/ext/pm/main.php +++ b/ext/pm/main.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace Shimmie2; +use GQLA\Expose; + class SendPMEvent extends Event { public PM $pm; @@ -15,16 +17,21 @@ class SendPMEvent extends Event } } +#[Expose] class PM { + #[Expose] public int $id; public int $from_id; public string $from_ip; public int $to_id; /** @var mixed */ public $sent_date; + #[Expose] public string $subject; + #[Expose] public string $message; + #[Expose] public bool $is_read; public function __construct($from_id=0, string $from_ip="0.0.0.0", int $to_id=0, string $subject="A Message", string $message="Some Text", bool $read=false)