From 349521e801bea9a07f1b8ec1b3261cf9077e3788 Mon Sep 17 00:00:00 2001 From: Murtaza Sultani Date: Tue, 23 Sep 2025 09:03:58 +0200 Subject: =?UTF-8?q?Resolve=20"Forum:=20Bearbeitungs=20und=20L=C3=B6schrech?= =?UTF-8?q?te=20f=C3=BCr=20Dozenten=20und=20Tutoren=20hinzuf=C3=BCgen"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #5757 Merge request studip/studip!4393 --- lib/classes/JsonApi/Routes/Forum/Authority.php | 11 +++ lib/classes/JsonApi/Routes/Forum/ConfigIndex.php | 1 + lib/classes/JsonApi/Routes/Forum/PostingDelete.php | 16 +--- lib/classes/JsonApi/Routes/Forum/PostingUpdate.php | 17 ++-- lib/classes/JsonApi/Schemas/Forum/Posting.php | 11 ++- lib/classes/JsonApi/Schemas/Forum/Topic.php | 1 - resources/vue/components/forum/ForumApp.vue | 5 +- resources/vue/components/forum/posts/Post.vue | 95 +++++++++++++--------- resources/vue/store/pinia/forum/ForumConfig.js | 2 + 9 files changed, 88 insertions(+), 71 deletions(-) diff --git a/lib/classes/JsonApi/Routes/Forum/Authority.php b/lib/classes/JsonApi/Routes/Forum/Authority.php index 95091a0..2ad779c 100644 --- a/lib/classes/JsonApi/Routes/Forum/Authority.php +++ b/lib/classes/JsonApi/Routes/Forum/Authority.php @@ -1,6 +1,7 @@ isAccessibleToUser($user?->user_id); } + + public static function canEditPost(User $user, Posting $posting, $isDiscussionClosed = false): bool + { + return (!$isDiscussionClosed && $posting->user_id === $user->user_id) || $GLOBALS['perm']->have_studip_perm('tutor', $posting->range_id, $user->id); + } + + public static function canDeletePost(User $user, Posting $posting, $isDiscussionClosed = false): bool + { + return self::canEditPost($user, $posting, $isDiscussionClosed); + } } diff --git a/lib/classes/JsonApi/Routes/Forum/ConfigIndex.php b/lib/classes/JsonApi/Routes/Forum/ConfigIndex.php index 8383608..de9a9a6 100644 --- a/lib/classes/JsonApi/Routes/Forum/ConfigIndex.php +++ b/lib/classes/JsonApi/Routes/Forum/ConfigIndex.php @@ -28,6 +28,7 @@ class ConfigIndex extends JsonApiController return $this->getMetaResponse([ 'is-admin' => CoreForum::isAdmin($range->id), 'is-moderator' => CoreForum::isModerator($range->id), + 'is-tutor' => $GLOBALS['perm']->have_studip_perm('tutor', $range->id, $user->id), 'anonymous-post' => (bool) Config::get()->FORUM_ANONYMOUS_POSTINGS, 'tile-layout' => (bool) UserConfig::get($user->user_id)->FORUM_TILE_LAYOUT ]); diff --git a/lib/classes/JsonApi/Routes/Forum/PostingDelete.php b/lib/classes/JsonApi/Routes/Forum/PostingDelete.php index e49755d..64225b3 100644 --- a/lib/classes/JsonApi/Routes/Forum/PostingDelete.php +++ b/lib/classes/JsonApi/Routes/Forum/PostingDelete.php @@ -3,7 +3,6 @@ namespace JsonApi\Routes\Forum; use JsonApi\Errors\AuthorizationFailedException; use JsonApi\Errors\RecordNotFoundException; -use JsonApi\Routes\Courses\Authority as CourseAuthority; use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; use JsonApi\JsonApiController; @@ -13,21 +12,14 @@ class PostingDelete extends JsonApiController { public function __invoke(Request $request, Response $response, $args) { - $user = $this->getUser($request); - - $posting = Posting::findOneBySQL( - "posting_id = :posting_id AND user_id = :user_id", - [ - 'posting_id' => $args['posting_id'], - 'user_id' => $user->user_id - ] - ); - + $posting = Posting::find($args['posting_id']); if (!$posting) { throw new RecordNotFoundException(); } - if ($posting->discussion->closed_at) { + if ( + !Authority::canDeletePost($this->getUser($request), $posting, (bool) $posting->discussion->closed_at) + ) { throw new AuthorizationFailedException(); } diff --git a/lib/classes/JsonApi/Routes/Forum/PostingUpdate.php b/lib/classes/JsonApi/Routes/Forum/PostingUpdate.php index cd50373..63b1ce5 100644 --- a/lib/classes/JsonApi/Routes/Forum/PostingUpdate.php +++ b/lib/classes/JsonApi/Routes/Forum/PostingUpdate.php @@ -25,25 +25,18 @@ class PostingUpdate extends JsonApiController public function __invoke(Request $request, Response $response, $args) { - $json = $this->validate($request); - $user = $this->getUser($request); - - $posting = Posting::findOneBySQL( - "posting_id = :posting_id AND user_id = :user_id", - [ - 'posting_id' => $args['posting_id'], - 'user_id' => $user->user_id - ] - ); - + $posting = Posting::find($args['posting_id']); if (!$posting) { throw new RecordNotFoundException(); } - if ($posting->discussion->closed_at) { + if ( + !Authority::canEditPost($this->getUser($request), $posting, (bool) $posting->discussion->closed_at) + ) { throw new AuthorizationFailedException(); } + $json = $this->validate($request); $posting->content = Markup::purifyHtml(Markup::markAsHtml(self::arrayGet($json, 'data.attributes.content'))); $posting->anonymous = (self::arrayGet($json, 'data.attributes.anonymous') && \Config::get()->FORUM_ANONYMOUS_POSTINGS); $posting->store(); diff --git a/lib/classes/JsonApi/Schemas/Forum/Posting.php b/lib/classes/JsonApi/Schemas/Forum/Posting.php index aa8423a..e2323ec 100644 --- a/lib/classes/JsonApi/Schemas/Forum/Posting.php +++ b/lib/classes/JsonApi/Schemas/Forum/Posting.php @@ -26,7 +26,6 @@ class Posting extends SchemaProvider } /** - * @inheritDoc * @param \Forum\Posting $resource */ public function getAttributes($resource, ContextInterface $context): iterable @@ -49,7 +48,6 @@ class Posting extends SchemaProvider } /** - * @inheritDoc * @param \Forum\Posting $resource */ public function getResourceMeta($resource) @@ -79,7 +77,7 @@ class Posting extends SchemaProvider return $relationships; } - private function addAuthorRelationship(array $relationships, \Forum\Posting $posting, $withAuthor = false) + private function addAuthorRelationship(array $relationships, \Forum\Posting $posting, bool $withAuthor = false) { $author = $posting->author; @@ -95,7 +93,7 @@ class Posting extends SchemaProvider return $relationships; } - private function addDiscussionRelationship(array $relationships, \Forum\Posting $posting, $withDiscussion = false) + private function addDiscussionRelationship(array $relationships, \Forum\Posting $posting, bool $withDiscussion = false) { if ($withDiscussion) { $relationships[self::REL_DISCUSSION] = [ @@ -109,7 +107,7 @@ class Posting extends SchemaProvider return $relationships; } - private function addPostingRelationship(array $relationships, \Forum\Posting $posting, $withPosting = false) + private function addPostingRelationship(array $relationships, \Forum\Posting $posting, bool $withPosting = false) { $posting = $posting->posting; @@ -125,7 +123,7 @@ class Posting extends SchemaProvider return $relationships; } - private function addReactionsRelationship(array $relationships, \Forum\Posting $posting, $withReactions = false) + private function addReactionsRelationship(array $relationships, \Forum\Posting $posting, bool $withReactions = false) { if ($withReactions) { $relationships[self::REL_REACTIONS] = [ @@ -138,4 +136,5 @@ class Posting extends SchemaProvider return $relationships; } + } diff --git a/lib/classes/JsonApi/Schemas/Forum/Topic.php b/lib/classes/JsonApi/Schemas/Forum/Topic.php index 06022c6..22a8c83 100644 --- a/lib/classes/JsonApi/Schemas/Forum/Topic.php +++ b/lib/classes/JsonApi/Schemas/Forum/Topic.php @@ -21,7 +21,6 @@ class Topic extends SchemaProvider } /** - * @inheritdoc * @param \Forum\Topic $resource */ public function getAttributes($resource, ContextInterface $context): iterable diff --git a/resources/vue/components/forum/ForumApp.vue b/resources/vue/components/forum/ForumApp.vue index dc0adc0..7a0ea35 100644 --- a/resources/vue/components/forum/ForumApp.vue +++ b/resources/vue/components/forum/ForumApp.vue @@ -10,8 +10,9 @@ const fetchConfigs = async () => { forumConfig.$patch({ isModerator: response.meta['is-moderator'], isAdmin: response.meta['is-admin'], + isTutor: response.meta['is-tutor'], anonymousPost: response.meta['anonymous-post'], - tileLayout: response.meta['tile-layout'], + tileLayout: response.meta['tile-layout'] }); } catch (error) { STUDIP.Report.error(error); @@ -26,7 +27,7 @@ onMounted(async () => { } else { await fetchConfigs(); } -}) +});