From 16c57402770deefdc7c16bc58b93efec212acf73 Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Sat, 4 Oct 2014 13:56:38 +0200 Subject: [PATCH] Added comment API --- data/config.ini | 7 + public_html/js/Auth.js | 7 + src/Controllers/CommentController.php | 128 ++++++++++++++++++ .../ViewProxies/CommentViewProxy.php | 32 +++++ src/Entities/Comment.php | 4 +- src/Privilege.php | 7 + src/SearchServices/Filters/CommentFilter.php | 14 ++ src/SearchServices/Filters/PostFilter.php | 1 + .../Parsers/PostSearchParser.php | 12 ++ src/Services/CommentService.php | 99 ++++++++++++++ src/di.php | 1 + 11 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 src/Controllers/CommentController.php create mode 100644 src/Controllers/ViewProxies/CommentViewProxy.php create mode 100644 src/SearchServices/Filters/CommentFilter.php create mode 100644 src/Services/CommentService.php diff --git a/data/config.ini b/data/config.ini index 2598620c..92d8cdc8 100644 --- a/data/config.ini +++ b/data/config.ini @@ -56,6 +56,13 @@ changePostRelations = regularUser, powerUser, moderator, administrator listTags = anonymous, regularUser, powerUser, moderator, administrator +listComments = anonymous, regularUser, powerUser, moderator, administrator +addComments = regularUser, powerUser, moderator, administrator +editOwnComments = regularUser, powerUser, moderator, administrator +editAllComments = moderator, administrator +deleteOwnComments = regularUser, powerUser, moderator, administrator +deleteAllComments = moderator, administrator + viewHistory = anonymous, regularUser, powerUser, moderator, administrator [users] diff --git a/public_html/js/Auth.js b/public_html/js/Auth.js index 1fe4361f..1ae9f866 100644 --- a/public_html/js/Auth.js +++ b/public_html/js/Auth.js @@ -33,6 +33,13 @@ App.Auth = function(_, jQuery, util, api, appState, promise) { changePostThumbnail: 'changePostThumbnail', changePostRelations: 'changePostRelations', + listComments: 'listComments', + addComments: 'addComments', + editOwnComments: 'editOwnComments', + editAllComments: 'editAllComments', + deleteOwnComments: 'deleteOwnComments', + deleteAllComments: 'deleteAllComments', + listTags: 'listTags', viewHistory: 'viewHistory', diff --git a/src/Controllers/CommentController.php b/src/Controllers/CommentController.php new file mode 100644 index 00000000..b35cb0e3 --- /dev/null +++ b/src/Controllers/CommentController.php @@ -0,0 +1,128 @@ +privilegeService = $privilegeService; + $this->authService = $authService; + $this->postService = $postService; + $this->commentService = $commentService; + $this->commentViewProxy = $commentViewProxy; + $this->postViewProxy = $postViewProxy; + $this->inputReader = $inputReader; + } + + public function registerRoutes(\Szurubooru\Router $router) + { + $router->get('/api/comments', [$this, 'getComments']); + $router->get('/api/comments/:postNameOrId', [$this, 'getPostComments']); + $router->post('/api/comments/:postNameOrId', [$this, 'addComment']); + $router->put('/api/comments/:commentId', [$this, 'editComment']); + $router->delete('/api/comments/:commentId', [$this, 'deleteComment']); + } + + public function getComments() + { + $this->privilegeService->assertPrivilege(\Szurubooru\Privilege::LIST_COMMENTS); + + $filter = new \Szurubooru\SearchServices\Filters\PostFilter(); + $filter->setPageSize(10); + $filter->setPageNumber($this->inputReader->page); + $filter->setOrder([ + \Szurubooru\SearchServices\Filters\PostFilter::ORDER_LAST_COMMENT_TIME => + \Szurubooru\SearchServices\Filters\PostFilter::ORDER_DESC]); + + $requirement = new \Szurubooru\SearchServices\Requirements\Requirement(); + $requirement->setValue(new \Szurubooru\SearchServices\Requirements\RequirementRangedValue()); + $requirement->getValue()->setMinValue(1); + $requirement->setType(\Szurubooru\SearchServices\Filters\PostFilter::REQUIREMENT_COMMENT_COUNT); + $filter->addRequirement($requirement); + + $result = $this->postService->getFiltered($filter); + $posts = $result->getEntities(); + + $data = []; + foreach ($posts as $post) + { + $data[] = [ + 'post' => $this->postViewProxy->fromEntity($post), + 'comments' => $this->commentViewProxy->fromArray($this->commentService->getByPost($post))]; + } + + return [ + 'data' => $data, + 'pageSize' => $result->getPageSize(), + 'totalRecords' => $result->getTotalRecords()]; + } + + public function getPostComments($postNameOrId) + { + $this->privilegeService->assertPrivilege(\Szurubooru\Privilege::LIST_COMMENTS); + $post = $this->postService->getByNameOrId($postNameOrId); + + $filter = new \Szurubooru\SearchServices\Filters\CommentFilter(); + $filter->setOrder([ + \Szurubooru\SearchServices\Filters\CommentFilter::ORDER_ID => + \Szurubooru\SearchServices\Filters\CommentFilter::ORDER_ASC]); + + $requirement = new \Szurubooru\SearchServices\Requirements\Requirement(); + $requirement->setValue(new \Szurubooru\SearchServices\Requirements\RequirementSingleValue($post->getId())); + $requirement->setType(\Szurubooru\SearchServices\Filters\CommentFilter::REQUIREMENT_POST_ID); + $filter->addRequirement($requirement); + + $result = $this->commentService->getFiltered($filter); + $entities = $this->commentViewProxy->fromArray($result->getEntities()); + return ['data' => $entities]; + } + + public function addComment($postNameOrId) + { + $this->privilegeService->assertPrivilege(\Szurubooru\Privilege::ADD_COMMENTS); + + $post = $this->postService->getByNameOrId($postNameOrId); + $comment = $this->commentService->createComment($post, $this->inputReader->text); + return $this->commentViewProxy->fromEntity($comment); + } + + public function editComment($commentId) + { + $comment = $this->commentService->getById($commentId); + + $this->privilegeService->assertPrivilege( + ($comment->getUser() and $this->privilegeService->isLoggedIn($comment->getUser())) + ? \Szurubooru\Privilege::EDIT_OWN_COMMENTS + : \Szurubooru\Privilege::EDIT_ALL_COMMENTS); + + $comment = $this->commentService->updateComment($comment, $this->inputReader->text); + return $this->commentViewProxy->fromEntity($comment); + } + + public function deleteComment($commentId) + { + $comment = $this->commentService->getById($commentId); + + $this->privilegeService->assertPrivilege( + $this->privilegeService->isLoggedIn($comment->getUser()) + ? \Szurubooru\Privilege::DELETE_OWN_COMMENTS + : \Szurubooru\Privilege::DELETE_ALL_COMMENTS); + + return $this->commentService->deleteComment($comment); + } +} diff --git a/src/Controllers/ViewProxies/CommentViewProxy.php b/src/Controllers/ViewProxies/CommentViewProxy.php new file mode 100644 index 00000000..f905b4ac --- /dev/null +++ b/src/Controllers/ViewProxies/CommentViewProxy.php @@ -0,0 +1,32 @@ +postViewProxy = $postViewProxy; + $this->userViewProxy = $userViewProxy; + } + + public function fromEntity($comment, $config = []) + { + $result = new \StdClass; + if ($comment) + { + $result->id = $comment->getId(); + $result->creationTime = $comment->getCreationTime(); + $result->lastEditTime = $comment->getLastEditTime(); + $result->text = $comment->getText(); + $result->postId = $comment->getPostId(); + $result->user = $this->userViewProxy->fromEntity($comment->getUser()); + } + return $result; + } +} + diff --git a/src/Entities/Comment.php b/src/Entities/Comment.php index 3449995e..4857e0fa 100644 --- a/src/Entities/Comment.php +++ b/src/Entities/Comment.php @@ -67,10 +67,10 @@ class Comment extends Entity return $this->lazyLoad(self::LAZY_LOADER_USER, null); } - public function setUser(\Szurubooru\Entities\User $user) + public function setUser(\Szurubooru\Entities\User $user = null) { $this->lazySave(self::LAZY_LOADER_USER, $user); - $this->userId = $user->getId(); + $this->userId = $user ? $user->getId() : null; } public function getPost() diff --git a/src/Privilege.php b/src/Privilege.php index f064f320..15eda37a 100644 --- a/src/Privilege.php +++ b/src/Privilege.php @@ -35,5 +35,12 @@ class Privilege const LIST_TAGS = 'listTags'; + const LIST_COMMENTS = 'listComments'; + const ADD_COMMENTS = 'addComments'; + const EDIT_OWN_COMMENTS = 'editOwnComments'; + const EDIT_ALL_COMMENTS = 'editAllComments'; + const DELETE_OWN_COMMENTS = 'deleteOwnComments'; + const DELETE_ALL_COMMENTS = 'deleteAllComments'; + const VIEW_HISTORY = 'viewHistory'; } diff --git a/src/SearchServices/Filters/CommentFilter.php b/src/SearchServices/Filters/CommentFilter.php new file mode 100644 index 00000000..a65d0751 --- /dev/null +++ b/src/SearchServices/Filters/CommentFilter.php @@ -0,0 +1,14 @@ +setOrder([self::ORDER_ID => self::ORDER_DESC]); + } +} diff --git a/src/SearchServices/Filters/PostFilter.php b/src/SearchServices/Filters/PostFilter.php index e1be1fb7..c8061595 100644 --- a/src/SearchServices/Filters/PostFilter.php +++ b/src/SearchServices/Filters/PostFilter.php @@ -20,6 +20,7 @@ class PostFilter extends BasicFilter implements IFilter const REQUIREMENT_HASH = 'name'; const REQUIREMENT_TAG_COUNT = 'tagCount'; const REQUIREMENT_FAV_COUNT = 'favCount'; + const REQUIREMENT_COMMENT_COUNT = 'commentCount'; const REQUIREMENT_SCORE = 'score'; const REQUIREMENT_UPLOADER = 'uploader.name'; const REQUIREMENT_SAFETY = 'safety'; diff --git a/src/SearchServices/Parsers/PostSearchParser.php b/src/SearchServices/Parsers/PostSearchParser.php index d7d06b85..948b99da 100644 --- a/src/SearchServices/Parsers/PostSearchParser.php +++ b/src/SearchServices/Parsers/PostSearchParser.php @@ -41,6 +41,9 @@ class PostSearchParser extends AbstractSearchParser elseif ($token->getKey() === 'fav_count') $this->addFavCountRequirement($filter, $token); + elseif ($token->getKey() === 'comment_count') + $this->addCommentCountRequirement($filter, $token); + elseif ($token->getKey() === 'score') $this->addScoreRequirement($filter, $token); @@ -180,6 +183,15 @@ class PostSearchParser extends AbstractSearchParser self::ALLOW_COMPOSITE | self::ALLOW_RANGES); } + private function addCommentCountRequirement($filter, $token) + { + $this->addRequirementFromToken( + $filter, + $token, + \Szurubooru\SearchServices\Filters\PostFilter::REQUIREMENT_COMMENT_COUNT, + self::ALLOW_COMPOSITE | self::ALLOW_RANGES); + } + private function addScoreRequirement($filter, $token) { $this->addRequirementFromToken( diff --git a/src/Services/CommentService.php b/src/Services/CommentService.php new file mode 100644 index 00000000..f029b123 --- /dev/null +++ b/src/Services/CommentService.php @@ -0,0 +1,99 @@ +validator = $validator; + $this->commentDao = $commentDao; + $this->transactionManager = $transactionManager; + $this->authService = $authService; + $this->timeService = $timeService; + } + + public function getById($commentId) + { + $transactionFunc = function() use ($commentId) + { + $comment = $this->commentDao->findById($commentId); + if (!$comment) + throw new \InvalidArgumentException('Comment with ID "' . $commentId . '" was not found.'); + return $comment; + }; + return $this->transactionManager->rollback($transactionFunc); + } + + public function getByPost(\Szurubooru\Entities\Post $post) + { + $transactionFunc = function() use ($post) + { + return $this->commentDao->findByPost($post); + }; + return $this->transactionManager->rollback($transactionFunc); + } + + public function getFiltered(\Szurubooru\SearchServices\Filters\CommentFilter $filter) + { + $transactionFunc = function() use ($filter) + { + return $this->commentDao->findFiltered($filter); + }; + return $this->transactionManager->rollback($transactionFunc); + } + + public function createComment(\Szurubooru\Entities\Post $post, $text) + { + $transactionFunc = function() use ($post, $text) + { + $comment = new \Szurubooru\Entities\Comment(); + $comment->setCreationTime($this->timeService->getCurrentTime()); + $comment->setLastEditTime($this->timeService->getCurrentTime()); + $comment->setUser($this->authService->isLoggedIn() ? $this->authService->getLoggedInUser() : null); + $comment->setPost($post); + + $this->updateCommentText($comment, $text); + + return $this->commentDao->save($comment); + }; + return $this->transactionManager->commit($transactionFunc); + } + + public function updateComment(\Szurubooru\Entities\Comment $comment, $newText) + { + $transactionFunc = function() use ($comment, $newText) + { + $comment->setLastEditTime($this->timeService->getCurrentTime()); + + $this->updateCommentText($comment, $newText); + return $this->commentDao->save($comment); + }; + return $this->transactionManager->commit($transactionFunc); + } + + public function deleteComment(\Szurubooru\Entities\Comment $comment) + { + $transactionFunc = function() use ($comment) + { + $this->commentDao->deleteById($comment->getId()); + }; + $this->transactionManager->commit($transactionFunc); + } + + private function updateCommentText(\Szurubooru\Entities\Comment $comment, $text) + { + $this->validator->validateLength($text, 5, 2000, 'Comment text'); + $comment->setText($text); + } +} diff --git a/src/di.php b/src/di.php index c0693f05..7ae0bc9e 100644 --- a/src/di.php +++ b/src/di.php @@ -44,6 +44,7 @@ return [ $container->get(\Szurubooru\Controllers\HistoryController::class), $container->get(\Szurubooru\Controllers\FavoritesController::class), $container->get(\Szurubooru\Controllers\PostScoreController::class), + $container->get(\Szurubooru\Controllers\CommentController::class), ]; }), ];