diff options
| author | Murtaza Sultani <sultani@data-quest.de> | 2025-07-15 09:30:48 +0200 |
|---|---|---|
| committer | Murtaza Sultani <sultani@data-quest.de> | 2025-07-15 09:30:48 +0200 |
| commit | 3b8ca07f47502466bfa537db838b8599dc3ce861 (patch) | |
| tree | 9ff029908a1146d2fd5db67b6eaa7578266718b4 | |
| parent | e04fa1e9b79f784628d640d4c0355f5eba61da01 (diff) | |
Resolve "Autor darf keine neue Diskussion starten"
Closes #5724
Merge request studip/studip!4355
15 files changed, 80 insertions, 33 deletions
diff --git a/app/controllers/course/forum/ForumBaseController.php b/app/controllers/course/forum/ForumBaseController.php index 196bbcf..aaa4dd4 100644 --- a/app/controllers/course/forum/ForumBaseController.php +++ b/app/controllers/course/forum/ForumBaseController.php @@ -31,13 +31,11 @@ abstract class ForumBaseController extends StudipController { $actions = new ActionsWidget(); - if ($this->is_moderator) { - $actions->addLink( - _('Neue Diskussion starten'), - $this->url_for('course/forum/discussions/edit'), - Icon::create('add', Icon::ROLE_CLICKABLE, ['title' => _('Neue Diskussion starten')]) - )->asDialog('width=900;height=750'); - } + $actions->addLink( + _('Neue Diskussion starten'), + $this->url_for('course/forum/discussions/edit'), + Icon::create('add', Icon::ROLE_CLICKABLE, ['title' => _('Neue Diskussion starten')]) + )->asDialog('width=900;height=750'); if ($this->is_admin) { $actions->addLink( diff --git a/app/controllers/course/forum/discussions.php b/app/controllers/course/forum/discussions.php index c946401..7e7aca7 100644 --- a/app/controllers/course/forum/discussions.php +++ b/app/controllers/course/forum/discussions.php @@ -112,10 +112,6 @@ class Course_Forum_DiscussionsController extends Forum\ForumBaseController public function edit_action(ForumDiscussion $discussion = null) { - if (!$this->is_moderator) { - throw new AccessDeniedException(); - } - if ($discussion->isNew()) { PageLayout::setTitle(_('Neue Diskussion starten')); } else { @@ -155,21 +151,20 @@ class Course_Forum_DiscussionsController extends Forum\ForumBaseController public function save_action($discussion_id = null) { - if (!$this->is_moderator) { - throw new AccessDeniedException(); - } - CSRFProtection::verifyUnsafeRequest(); if ($discussion_id) { $discussion = ForumDiscussion::find($discussion_id); } else { $discussion = new ForumDiscussion(); + $discussion->user_id = User::findCurrent()->user_id; } $discussion->title = Request::get('title'); $discussion->closed_at = Request::bool('closed_at', false) ? time() : null; - $discussion->sticky = Request::bool('sticky', false); + if ($this->is_moderator) { + $discussion->sticky = Request::bool('sticky', false); + } if (Request::get('type_id')) { $discussion->type_id = Request::get('type_id'); @@ -227,16 +222,16 @@ class Course_Forum_DiscussionsController extends Forum\ForumBaseController public function delete_action($discussion_id) { - if (!$this->is_moderator) { - throw new AccessDeniedException(); - } - $discussion = ForumDiscussion::find($discussion_id); if (!$discussion) { throw new AccessDeniedException(); } + if (!$this->is_moderator && $discussion->user_id !== User::findCurrent()->user_id) { + throw new AccessDeniedException(); + } + TagRelation::deleteBySQL("range_id = ? AND range_type = 'forum'", [$discussion->discussion_id]); $topic_id = $discussion->topic_id; diff --git a/db/migrations/6.1.15_add_user_id_to_forum_discussions.php b/db/migrations/6.1.15_add_user_id_to_forum_discussions.php new file mode 100644 index 0000000..97df7ce --- /dev/null +++ b/db/migrations/6.1.15_add_user_id_to_forum_discussions.php @@ -0,0 +1,24 @@ +<?php + +final class AddUserIdToForumDiscussions extends Migration +{ + public function up() + { + DBManager::get()->exec("ALTER TABLE forum_discussions Add COLUMN user_id CHAR(32) COLLATE latin1_bin NOT NULL AFTER topic_id"); + DBManager::get()->exec(" + UPDATE forum_discussions AS discussions + SET user_id = ( + SELECT postings.user_id + FROM forum_postings AS postings + WHERE postings.discussion_id = discussions.discussion_id + ORDER BY mkdate ASC + LIMIT 1 + ); + "); + } + + public function down() + { + DBManager::get()->exec("ALTER TABLE forum_discussions DROP COLUMN user_id"); + } +} diff --git a/lib/classes/JsonApi/Routes/Forum/ForumDiscussionIndex.php b/lib/classes/JsonApi/Routes/Forum/ForumDiscussionIndex.php index d3920a3..140a502 100644 --- a/lib/classes/JsonApi/Routes/Forum/ForumDiscussionIndex.php +++ b/lib/classes/JsonApi/Routes/Forum/ForumDiscussionIndex.php @@ -16,6 +16,7 @@ class ForumDiscussionIndex extends JsonApiController protected $allowedIncludePaths = [ \JsonApi\Schemas\Forum\ForumCategory::REL_TOPICS, \JsonApi\Schemas\Forum\ForumDiscussion::REL_CATEGORY, + \JsonApi\Schemas\Forum\ForumDiscussion::REL_USER, \JsonApi\Schemas\Forum\ForumDiscussion::REL_DISCUSSION_TYPE, \JsonApi\Schemas\Forum\ForumDiscussion::REL_MEMBERS, \JsonApi\Schemas\Forum\ForumDiscussion::REL_TAGS diff --git a/lib/classes/JsonApi/Routes/Forum/ForumDiscussionTypeDiscussions.php b/lib/classes/JsonApi/Routes/Forum/ForumDiscussionTypeDiscussions.php index 469903a..6db27ab 100644 --- a/lib/classes/JsonApi/Routes/Forum/ForumDiscussionTypeDiscussions.php +++ b/lib/classes/JsonApi/Routes/Forum/ForumDiscussionTypeDiscussions.php @@ -11,7 +11,8 @@ class ForumDiscussionTypeDiscussions extends JsonApiController { protected $allowedPagingParameters = ['offset', 'limit']; protected $allowedIncludePaths = [ - \JsonApi\Schemas\Forum\ForumDiscussionType::REL_DISCUSSIONS + \JsonApi\Schemas\Forum\ForumDiscussionType::REL_DISCUSSIONS, + \JsonApi\Schemas\Forum\ForumDiscussion::REL_USER, ]; public function __invoke(Request $request, Response $response, $args) diff --git a/lib/classes/JsonApi/Routes/Forum/ForumTopicDiscussions.php b/lib/classes/JsonApi/Routes/Forum/ForumTopicDiscussions.php index 935d9e3..c482c0a 100644 --- a/lib/classes/JsonApi/Routes/Forum/ForumTopicDiscussions.php +++ b/lib/classes/JsonApi/Routes/Forum/ForumTopicDiscussions.php @@ -15,6 +15,7 @@ class ForumTopicDiscussions extends JsonApiController protected $allowedIncludePaths = [ \JsonApi\Schemas\Forum\ForumCategory::REL_TOPICS, \JsonApi\Schemas\Forum\ForumDiscussion::REL_CATEGORY, + \JsonApi\Schemas\Forum\ForumDiscussion::REL_USER, \JsonApi\Schemas\Forum\ForumDiscussion::REL_DISCUSSION_TYPE, \JsonApi\Schemas\Forum\ForumDiscussion::REL_MEMBERS, \JsonApi\Schemas\Forum\ForumDiscussion::REL_TAGS diff --git a/lib/classes/JsonApi/Schemas/Forum/ForumDiscussion.php b/lib/classes/JsonApi/Schemas/Forum/ForumDiscussion.php index d095325..ebd3fee 100644 --- a/lib/classes/JsonApi/Schemas/Forum/ForumDiscussion.php +++ b/lib/classes/JsonApi/Schemas/Forum/ForumDiscussion.php @@ -12,6 +12,7 @@ class ForumDiscussion extends SchemaProvider const REL_POSTINGS = 'postings'; const REL_TOPIC = 'topic'; const REL_CATEGORY = 'category'; + const REL_USER = 'user'; const REL_DISCUSSION_TYPE = 'discussion-type'; const REL_MEMBERS = 'members'; const REL_TAGS = 'tags'; @@ -57,6 +58,7 @@ class ForumDiscussion extends SchemaProvider $relationships = $this->addPostingsRelationship($relationships, $discussion, $this->shouldInclude($context, self::REL_POSTINGS)); $relationships = $this->addTopicRelationship($relationships, $discussion, $this->shouldInclude($context, self::REL_TOPIC)); $relationships = $this->addCategoryRelationship($relationships, $discussion, $this->shouldInclude($context, self::REL_CATEGORY)); + $relationships = $this->addUserRelationship($relationships, $discussion, $this->shouldInclude($context, self::REL_USER)); $relationships = $this->addDiscussionTypeRelationship($relationships, $discussion, $this->shouldInclude($context, self::REL_DISCUSSION_TYPE)); $relationships = $this->addMembersRelationship($relationships, $discussion, $this->shouldInclude($context, self::REL_MEMBERS)); $relationships = $this->addTagsRelationship($relationships, $discussion, $this->shouldInclude($context, self::REL_TAGS)); @@ -96,7 +98,6 @@ class ForumDiscussion extends SchemaProvider { $category = $discussion->category; if ($withCategory && $category) { - $relationships[self::REL_CATEGORY] = [ self::RELATIONSHIP_LINKS => [ Link::RELATED => $this->createLinkToResource($category) @@ -108,6 +109,21 @@ class ForumDiscussion extends SchemaProvider return $relationships; } + private function addUserRelationship(array $relationships, $discussion, bool $withUser = false) + { + if ($withUser) { + $user = $discussion->user; + $relationships[self::REL_USER] = [ + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->createLinkToResource($user) + ], + self::RELATIONSHIP_DATA => $user + ]; + } + + return $relationships; + } + private function addDiscussionTypeRelationship(array $relationships, $discussion, bool $withDiscussionType = false) { $discussionType = $discussion->discussion_type; diff --git a/lib/models/Forum/ForumDiscussion.php b/lib/models/Forum/ForumDiscussion.php index 70aeab5..ce648fa 100644 --- a/lib/models/Forum/ForumDiscussion.php +++ b/lib/models/Forum/ForumDiscussion.php @@ -20,6 +20,7 @@ use Forum\Service\DiscussionNotification; * @property int $chdate * * @property ForumTopic $topic + * @property User $user * @property ForumDiscussionType $discussion_type * @property ForumPosting[] $postings * @property ForumSubscription[] $subscribers @@ -59,6 +60,12 @@ class ForumDiscussion extends SimpleORMap 'assoc_foreign_key' => 'discussion_id' ]; + $config['belongs_to']['user'] = [ + 'class_name' => User::class, + 'foreign_key' => 'user_id', + 'assoc_foreign_key' => 'user_id' + ]; + $config['additional_fields']['range_id']['get'] = 'getRangeId'; $config['additional_fields']['category']['get'] = 'getCategory'; $config['additional_fields']['tags']['get'] = 'getTags'; @@ -169,6 +176,7 @@ class ForumDiscussion extends SimpleORMap 'discussion_id' => $this->discussion_id, 'topic_id' => $this->topic_id, 'type_id' => $this->type_id, + 'user_id' => $this->user_id, 'title' => $this->title, 'sticky' => (int) $this->sticky, 'closed_at' => $this->closed_at ? date('c', $this->closed_at) : '', diff --git a/resources/vue/apps/forum/discussions/Edit.vue b/resources/vue/apps/forum/discussions/Edit.vue index 4531ce1..ed8ab6b 100644 --- a/resources/vue/apps/forum/discussions/Edit.vue +++ b/resources/vue/apps/forum/discussions/Edit.vue @@ -7,7 +7,9 @@ import StudipIcon from "../../../components/StudipIcon.vue"; import StudipWysiwyg from "../../../components/StudipWysiwyg.vue"; import StudipSwitch from "../../../components/StudipSwitch.vue"; import {$gettext} from "../../../../assets/javascripts/lib/gettext"; +import {useForumConfig} from "../../../store/pinia/forum/ForumConfig"; +const forumConfig = useForumConfig(); const CSRF = STUDIP.CSRF_TOKEN; const props = defineProps({ @@ -140,7 +142,7 @@ onMounted(() => { <section class="mt-10"> <StudipSwitch name="closed_at" v-model="discussionForm.closed_at" :label="$gettext('Diskussion schließen')" /> </section> - <section class="mt-10"> + <section v-if="forumConfig.isModerator" class="mt-10"> <StudipSwitch name="sticky" v-model="discussionForm.sticky" :label="$gettext('Anpinnen')" /> </section> </fieldset> diff --git a/resources/vue/apps/forum/discussions/Index.vue b/resources/vue/apps/forum/discussions/Index.vue index 07f7ee2..4845f16 100644 --- a/resources/vue/apps/forum/discussions/Index.vue +++ b/resources/vue/apps/forum/discussions/Index.vue @@ -27,7 +27,7 @@ const fetchDiscussions = async (_, offset = 0) => { const response = await STUDIP.jsonapi.withPromises().GET( `courses/${STUDIP.URLHelper.parameters.cid}/forum-discussions`, { - data: { include: 'category,discussion-type,members,tags', page: { offset } } + data: { include: 'category,discussion-type,members,tags,user&fields[users]=id', page: { offset } } } ); diff --git a/resources/vue/apps/forum/discussions/Show.vue b/resources/vue/apps/forum/discussions/Show.vue index ad9a716..ed5043c 100644 --- a/resources/vue/apps/forum/discussions/Show.vue +++ b/resources/vue/apps/forum/discussions/Show.vue @@ -74,6 +74,10 @@ const goBackURL = computed(() => { } }); +const canEditDiscussion = computed(() => { + return forumConfig.isModerator || props.discussion.user_id === STUDIP.USER_ID +}) + const fetchPostings = async () => { let allPostings = []; let offset = 0; @@ -190,7 +194,7 @@ onMounted(async () => { </em> <StudipIcon shape="lock-locked2" :size="20" role="inactive" /> </div> - <button v-if="forumConfig.isModerator" @click="editDiscussion(discussion.discussion_id)" type="button" :title="$gettext('Diskussion bearbeiten')" class="icon-button"> + <button v-if="canEditDiscussion" @click="editDiscussion(discussion.discussion_id)" type="button" :title="$gettext('Diskussion bearbeiten')" class="icon-button"> <StudipIcon shape="edit" :size="20" /> </button> <SubscriptionDropdown diff --git a/resources/vue/apps/forum/recent/Index.vue b/resources/vue/apps/forum/recent/Index.vue index f615eb8..4346a05 100644 --- a/resources/vue/apps/forum/recent/Index.vue +++ b/resources/vue/apps/forum/recent/Index.vue @@ -23,7 +23,7 @@ const fetchDiscussions = async (_, offset = 0) => { `courses/${STUDIP.URLHelper.parameters.cid}/forum-discussions`, { data: { - include: 'category,discussion-type,members,tags', + include: 'category,discussion-type,members,tags,user&fields[users]=id', filter: { 'last-visit': props.last_visit }, @@ -53,7 +53,7 @@ onMounted(async () => { <template> <ForumApp class="use-utility-classes"> - <DiscussionIndex :discussions="discussions" :withActions="false" :isLoading="isLoading" redirect="recent"> + <DiscussionIndex :discussions="discussions" :withActions="true" :isLoading="isLoading" redirect="recent"> <template #pagination> <tfoot v-if="pagination && pagination.total > pagination.limit"> <tr> diff --git a/resources/vue/apps/forum/topics/Show.vue b/resources/vue/apps/forum/topics/Show.vue index 3d9adf3..619df47 100644 --- a/resources/vue/apps/forum/topics/Show.vue +++ b/resources/vue/apps/forum/topics/Show.vue @@ -41,7 +41,7 @@ const fetchDiscussions = async (_, offset = 0) => { const response = await STUDIP.jsonapi.withPromises().GET( `forum-topics/${props.topic.topic_id}/discussions`, { - data: { include: 'category,discussion-type,members,tags', page: { offset } } + data: { include: 'category,discussion-type,members,tags,user&fields[users]=id', page: { offset } } } ); diff --git a/resources/vue/components/forum/discussions/Create.vue b/resources/vue/components/forum/discussions/Create.vue index f4d3fca..1d88d78 100644 --- a/resources/vue/components/forum/discussions/Create.vue +++ b/resources/vue/components/forum/discussions/Create.vue @@ -1,11 +1,9 @@ <script setup> -import {useForumConfig} from "../../../store/pinia/forum/ForumConfig"; import StudipIcon from "@/vue/components/StudipIcon.vue"; import {computed} from "vue"; import {$gettext} from "@/assets/javascripts/lib/gettext"; -const forumConfig = useForumConfig(); const props = defineProps({ topic_id: { type: String, @@ -19,7 +17,6 @@ const discussionCreateURL = computed(() => { <template> <a - v-if="forumConfig.isModerator" :href="discussionCreateURL" :title="$gettext('Neue Diskussion starten')" data-dialog="width=900;height=750" diff --git a/resources/vue/components/forum/discussions/DiscussionIndex.vue b/resources/vue/components/forum/discussions/DiscussionIndex.vue index 266e1b7..e9665e3 100644 --- a/resources/vue/components/forum/discussions/DiscussionIndex.vue +++ b/resources/vue/components/forum/discussions/DiscussionIndex.vue @@ -42,8 +42,8 @@ const { getAriaSortLabel } = useSortable(discussionsRef); -const getActionMenusItems = () => { - if (forumConfig.isModerator) { +const getActionMenusItems = discussion => { + if (forumConfig.isModerator || discussion.user.id === STUDIP.USER_ID) { return [ { label: $gettext('Bearbeiten'), icon: 'edit', emit: 'edit'}, { label: $gettext('Löschen'), icon: 'trash', emit: 'delete'} |
