added APICommentAction, api fixes

This commit is contained in:
crispycat 2024-09-28 02:46:07 -04:00
parent 765def895d
commit b8c302a50e
4 changed files with 171 additions and 5 deletions

View File

@ -0,0 +1,159 @@
<?php
/*
Crispage CMS
crispycat <cc@crispy.cat>
https://crispy.cat/software/crispage
Crispage is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
*/
namespace Crispage\Actions\API;
defined("ROOT") or die();
use \Crispage\Framework\Asset;
use \Crispage\Auth\CorePermissions;
use \Crispage\Exceptions\APIException;
use \Crispage\Assets\Comment;
class APICommentAction extends \Crispage\Framework\Action
implements \Crispage\Response\APIPermissions {
public static function getExtensionInfo(): array {
return [
"id" => "crispage.actions.api.comment",
"version" => VERSION
];
}
public static function getAPIPermissions(): array {
return [
"GET" => CorePermissions::NONE,
"POST" => CorePermissions::POST_COMMENT,
"PATCH" => CorePermissions::MODERATE_COMMENTS
];
}
public function run(): void {
if (!$this->app->settings->get("crispage.comments_enabled", true))
throw new APIException("Comments disabled", 403);
switch ($this->app->request->method) {
case "GET": {
// get content asset
$content = $this->app->assets->get(
intval($this->app->request->json["content_id"] ?? 0)
);
// 404 if content doesn't exist or comments disabled
if (!$content || !$content->getOption("show_comments", true))
throw new APIException("Not found", 404);
// include approved comments only unless user has backend permissions
$filter = boolval(
$this->app->request->json["filter"] ?? 1
);
if (!$this->app->auth->userHasPermission(CorePermissions::BACKEND))
$filter = true;
$filters = ["content_id" => $content->id];
if ($filter) $filters["state"] = Comment::APPROVED;
// get comments
$comments = $this->app->assets->getAllFiltered(
"\\Crispage\\Assets\\Comment",
$filters, "mtime", true
);
$out = [];
foreach ($comments as $comment) {
$author = $this->app->assets->get($comment->author_id);
if (!$author) continue;
$out[] = [
"comment_id" => $comment->id,
"body" => $comment->body,
"content_id" => $comment->content_id,
"author_id" => $author->id,
"author_slug" => $author->slug,
"author_name" => $author->displayname,
"posted" => $comment->ctime,
"state" => $comment->state
];
}
break;
}
case "POST": {
// get content asset
$content = $this->app->assets->get(
intval($this->app->request->json["content_id"] ?? 0)
);
// 404 if content doesn't exist or comments disabled
if (!$content || !$content->getOption("show_comments", true))
throw new APIException("Not found", 404);
$body = strval($this->app->request->json["body"] ?? "");
if (empty($body)) throw new APIException("Body empty", 400);
$ra = $this->app->settings->get("crispage.comments_require_approval", false);
$state = ($ra) ? Comment::PENDING_APPROVAL : Comment::APPROVED;
$comment = $this->app->assets->create(
"\\Crispage\\Assets\\Comment", [
"slug" => $content->slug . "_" . dechex(time()) . bin2hex(random_bytes(2)),
"author_id" => $this->app->auth->currentUser->id,
"content_id" => $content->id,
"body" => $body,
"state" => $state
]
);
$out = [
"comment_id" => $comment->id,
"body" => $comment->body,
"content_id" => $comment->content_id,
"author_id" => $this->app->auth->currentUser->id,
"author_slug" => $this->app->auth->currentUser->slug,
"author_name" => $this->app->auth->currentUser->displayname,
"posted" => $comment->ctime,
"state" => $comment->state
];
break;
}
case "PATCH": {
$comment = $this->app->assets->get(
intval($this->app->request->json["comment_id"] ?? 0)
);
if (!$comment || !is_a($comment, "\\Crispage\\Assets\\Comment"))
throw new APIException("Invalid ID", 400);
$state = intval($this->app->request->json["state"] ?? 0);
if ($state != Comment::HIDDEN && $state != Comment::APPROVED)
throw new APIException("Invalid state", 400);
$comment->state = $state;
$this->app->assets->set($comment);
$out = [
"comment_id" => $comment->id,
"author_id" => $comment->author_id,
"state" => $comment->state
];
break;
}
}
$this->app->page->setAPIOutput($out);
$this->app->page->actionFinished();
}
}
?>

View File

@ -30,25 +30,26 @@
// Get route // Get route
$route = $this->getRoute("api"); $route = $this->getRoute("api");
$this->setRouteLayout($route, "api", "default");
try { try {
if (!$route) throw new APIException(404, "Invalid endpoint"); if (!$route) throw new APIException(404, "Invalid endpoint");
// Get required permissions // Get required permissions
$this->app->loadClass($route->action, "action"); $this->app->loadClass($route->action, "action");
if (!is_a($route->action, "\\Crispage\\Response\\APIPermissions", true)) if (!is_a($route->action, "\\Crispage\\Response\\APIPermissions", true))
throw new APIException(500, "Invalid action"); throw new APIException("Invalid action", 500);
$perms = $route->action::getAPIPermissions(); $perms = $route->action::getAPIPermissions();
$perm = $perms[$this->app->request->method] ?? CorePermissions::NEVER; $perm = $perms[$this->app->request->method] ?? CorePermissions::NEVER;
// Error on invalid method // Error on invalid method
if ($perm == CorePermissions::NEVER) if ($perm === CorePermissions::NEVER)
throw new APIException(405, "Method not allowed"); throw new APIException("Method not allowed", 405);
// Check permissions // Check permissions
if (!$this->app->auth->userHasPermission($perm)) if (!$this->app->auth->userHasPermission($perm))
throw new APIException(401, "Unauthorized"); throw new APIException("Unauthorized", 401);
$this->setRouteLayout($route, "api", "default");
$this->route($route); $this->route($route);
} }
catch (APIException $e) { catch (APIException $e) {

View File

@ -192,6 +192,11 @@
"\\Crispage\\Actions\\API\\APIAssetSearchAction", "\\Crispage\\Actions\\API\\APIAssetSearchAction",
"action", [] "action", []
), ),
new Extension(
"crispage.actions.api.comment", VERSION, "crispage.core",
"\\Crispage\\Actions\\API\\APICommentAction",
"action", []
),
new Extension( new Extension(
"crispage.actions.api.default", VERSION, "crispage.core", "crispage.actions.api.default", VERSION, "crispage.core",
"\\Crispage\\Actions\\API\\APIDefaultAction", "\\Crispage\\Actions\\API\\APIDefaultAction",

View File

@ -70,6 +70,7 @@
new Route("asset/status", "\\Crispage\\Actions\\API\\APIAssetStatusAction", static::RDATA_API), new Route("asset/status", "\\Crispage\\Actions\\API\\APIAssetStatusAction", static::RDATA_API),
new Route("assets", "\\Crispage\\Actions\\API\\APIAssetsAction", static::RDATA_API), new Route("assets", "\\Crispage\\Actions\\API\\APIAssetsAction", static::RDATA_API),
new Route("assets/search", "\\Crispage\\Actions\\API\\APIAssetSearchAction", static::RDATA_API), new Route("assets/search", "\\Crispage\\Actions\\API\\APIAssetSearchAction", static::RDATA_API),
new Route("comment", "\\Crispage\\Actions\\API\\APICommentAction", static::RDATA_API),
new Route("media", "\\Crispage\\Actions\\API\\APIMediaAction", static::RDATA_API), new Route("media", "\\Crispage\\Actions\\API\\APIMediaAction", static::RDATA_API),
new Route("media/folder", "\\Crispage\\Actions\\API\\APIMediaFolderAction", static::RDATA_API), new Route("media/folder", "\\Crispage\\Actions\\API\\APIMediaFolderAction", static::RDATA_API),
new Route("session", "\\Crispage\\Actions\\API\\APISessionAction", static::RDATA_API), new Route("session", "\\Crispage\\Actions\\API\\APISessionAction", static::RDATA_API),