From 5da08f6c40f714fd37860f3ac19662888aa3780b Mon Sep 17 00:00:00 2001 From: Ron Lucke Date: Thu, 22 Jun 2023 10:36:07 +0000 Subject: =?UTF-8?q?Courseware:=20=C3=9Cbersichtsseite=20=C3=BCber=20Feedba?= =?UTF-8?q?ck=20und=20Kommentare?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #2689 Merge request studip/studip!1754 --- app/controllers/course/courseware.php | 192 ++++++++++++++ app/views/course/courseware/comments_overview.php | 5 + lib/modules/CoursewareModule.class.php | 4 + .../assets/javascripts/bootstrap/courseware.js | 11 + resources/assets/stylesheets/scss/courseware.scss | 34 ++- .../vue/components/courseware/CommentsApp.vue | 46 ++++ .../courseware/CoursewareBlockComments.vue | 7 + .../courseware/CoursewareBlockCommentsOverview.vue | 282 +++++++++++++++++++++ .../courseware/CoursewareBlockFeedback.vue | 7 + .../CoursewareCommentsOverviewDialog.vue | 98 +++++++ ...ursewareCommentsOverviewWidgetFilterCreated.vue | 51 ++++ .../CoursewareCommentsOverviewWidgetFilterType.vue | 51 ++++ .../CoursewareCommentsOverviewWidgetFilterUnit.vue | 60 +++++ .../CoursewareStructuralElementComments.vue | 7 + ...CoursewareStructuralElementCommentsOverview.vue | 267 +++++++++++++++++++ .../CoursewareStructuralElementFeedback.vue | 7 + resources/vue/courseware-comments-app.js | 114 +++++++++ .../mixins/courseware/comments-overview-helper.js | 16 ++ .../store/courseware/courseware-comments.module.js | 146 +++++++++++ 19 files changed, 1395 insertions(+), 10 deletions(-) create mode 100644 app/views/course/courseware/comments_overview.php create mode 100644 resources/vue/components/courseware/CommentsApp.vue create mode 100644 resources/vue/components/courseware/CoursewareBlockCommentsOverview.vue create mode 100644 resources/vue/components/courseware/CoursewareCommentsOverviewDialog.vue create mode 100644 resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterCreated.vue create mode 100644 resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterType.vue create mode 100644 resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterUnit.vue create mode 100644 resources/vue/components/courseware/CoursewareStructuralElementCommentsOverview.vue create mode 100644 resources/vue/courseware-comments-app.js create mode 100644 resources/vue/mixins/courseware/comments-overview-helper.js create mode 100644 resources/vue/store/courseware/courseware-comments.module.js diff --git a/app/controllers/course/courseware.php b/app/controllers/course/courseware.php index f35483f..29c48d9 100644 --- a/app/controllers/course/courseware.php +++ b/app/controllers/course/courseware.php @@ -91,6 +91,190 @@ class Course_CoursewareController extends CoursewareController $this->render_pdf($element->pdfExport($user, $with_children), trim($element->title).'.pdf'); } + public function comments_overview_action(): void + { + Navigation::activateItem('course/courseware/comments'); + $this->setCommentsOverviewSidebar(); + } + + public function comments_overview_data_action() + { + $user = User::findCurrent(); + $cid = Request::get('cid'); + $units = []; + $elements = []; + $containers = []; + $blocks = []; + $block_comments = []; + $block_feedbacks = []; + $element_comments = []; + $element_feedbacks = []; + + $statement = DBManager::get()->prepare(" + SELECT elem.id AS elem_id, container.id AS container_id, block.id AS block_id, comment.id AS comment_id + FROM `cw_block_comments` AS comment + INNER JOIN `cw_blocks` AS block ON (block.id = comment.block_id) + INNER JOIN `cw_containers` AS container ON (container.id = block.container_id) + INNER JOIN `cw_structural_elements` AS elem ON (elem.id = container.structural_element_id) + WHERE elem.range_type = 'course' + AND elem.range_id = :range_id + "); + + $statement->execute(['range_id' => $cid]); + $cw_block_comments = $statement->fetchAll(); + + foreach ($cw_block_comments as $row) { + $element = \Courseware\StructuralElement::find($row['elem_id']); + if (!$element->canRead($user)) { + continue; + } + if (!$this->arrayHasDataForId($elements, $row['elem_id'])) { + $elements[] = $element; + $unit = $element->findUnit(); + $unitElement = $unit->structural_element; + if (!$this->arrayHasDataForId($elements, $unitElement->id)) { + $elements[] = $unitElement; + } + if (!$this->arrayHasDataForId($units, $unit->id)) { + $units[] = $unit; + } + } + if (!$this->arrayHasDataForId($containers, $row['container_id'])) { + $containers[] = \Courseware\Container::find($row['container_id']); + } + if (!$this->arrayHasDataForId($blocks, $row['block_id'])) { + $blocks[] = \Courseware\Block::find($row['block_id']); + } + if (!$this->arrayHasDataForId($block_comments, $row['comment_id'])) { + $block_comments[] = \Courseware\BlockComment::find($row['comment_id']); + } + } + + $statement = DBManager::get()->prepare(" + SELECT elem.id AS elem_id, container.id AS container_id, block.id AS block_id, feedback.id AS feedback_id + FROM `cw_block_feedbacks` AS feedback + INNER JOIN `cw_blocks` AS block ON (block.id = feedback.block_id) + INNER JOIN `cw_containers` AS container ON (container.id = block.container_id) + INNER JOIN `cw_structural_elements` AS elem ON (elem.id = container.structural_element_id) + WHERE elem.range_type = 'course' + AND elem.range_id = :range_id + "); + + $statement->execute(['range_id' => $cid]); + $cw_block_feedbacks = $statement->fetchAll(); + + foreach ($cw_block_feedbacks as $row) { + $element = \Courseware\StructuralElement::find($row['elem_id']); + if (!$element->canEdit($user)) { + continue; + } + if (!$this->arrayHasDataForId($elements, $row['elem_id'])) { + $elements[] = $element; + $unit = $element->findUnit(); + $unitElement = $unit->structural_element; + if (!$this->arrayHasDataForId($elements, $unitElement->id)) { + $elements[] = $unitElement; + } + if (!$this->arrayHasDataForId($units, $unit->id)) { + $units[] = $unit; + } + } + if (!$this->arrayHasDataForId($containers, $row['container_id'])) { + $containers[] = \Courseware\Container::find($row['container_id']); + } + if (!$this->arrayHasDataForId($blocks, $row['block_id'])) { + $blocks[] = \Courseware\Block::find($row['block_id']); + } + if (!$this->arrayHasDataForId($block_feedbacks, $row['feedback_id'])) { + $block_feedbacks[] = \Courseware\BlockFeedback::find($row['feedback_id']); + } + } + + $statement = DBManager::get()->prepare(" + SELECT elem.id AS elem_id, comment.id AS comment_id + FROM `cw_structural_element_comments` AS comment + INNER JOIN `cw_structural_elements` AS elem ON (elem.id = comment.structural_element_id) + WHERE elem.range_type = 'course' + AND elem.range_id = :range_id + "); + + $statement->execute(['range_id' => $cid]); + $cw_structural_element_comments = $statement->fetchAll(); + + foreach ($cw_structural_element_comments as $row) { + $element = \Courseware\StructuralElement::find($row['elem_id']); + if (!$element->canRead($user)) { + continue; + } + if (!$this->arrayHasDataForId($elements, $row['elem_id'])) { + $elements[] = $element; + $unit = $element->findUnit(); + $unitElement = $unit->structural_element; + if (!$this->arrayHasDataForId($elements, $unitElement->id)) { + $elements[] = $unitElement; + } + if (!$this->arrayHasDataForId($units, $unit->id)) { + $units[] = $unit; + } + } + if (!$this->arrayHasDataForId($element_comments, $row['comment_id'])) { + $element_comments[] = \Courseware\StructuralElementComment::find($row['comment_id']); + } + } + + $statement = DBManager::get()->prepare(" + SELECT elem.id AS elem_id, feedback.id AS feedback_id + FROM `cw_structural_element_feedbacks` AS feedback + INNER JOIN `cw_structural_elements` AS elem ON (elem.id = feedback.structural_element_id) + WHERE elem.range_type = 'course' + AND elem.range_id = :range_id + "); + + $statement->execute(['range_id' => $cid]); + $cw_structural_element_feedbacks = $statement->fetchAll(); + + foreach ($cw_structural_element_feedbacks as $row) { + $element = \Courseware\StructuralElement::find($row['elem_id']); + if (!$element->canEdit($user)) { + continue; + } + if (!$this->arrayHasDataForId($elements, $row['elem_id'])) { + $elements[] = $element; + $unit = $element->findUnit(); + $unitElement = $unit->structural_element; + if (!$this->arrayHasDataForId($elements, $unitElement->id)) { + $elements[] = $unitElement; + } + if (!$this->arrayHasDataForId($units, $unit->id)) { + $units[] = $unit; + } + } + if (!$this->arrayHasDataForId($element_feedbacks, $row['feedback_id'])) { + $element_feedbacks[] = \Courseware\StructuralElementFeedback::find($row['feedback_id']); + } + } + + $encoder = app(\Neomerx\JsonApi\Contracts\Encoder\EncoderInterface::class); + + $data = [ + 'units' => $encoder->encodeData($units), + 'elements' => $encoder->encodeData($elements), + 'containers' => $encoder->encodeData($containers), + 'blocks' => $encoder->encodeData($blocks), + 'block_comments' => $encoder->encodeData($block_comments), + 'block_feedbacks' => $encoder->encodeData($block_feedbacks), + 'element_comments' => $encoder->encodeData($element_comments), + 'element_feedbacks' => $encoder->encodeData($element_feedbacks), + ]; + $this->render_json($data); + } + + private function arrayHasDataForId(array $array, $id): bool + { + $ids = array_column($array, null, 'id'); + return !empty($ids[$id]); + } + private function setIndexSidebar(): void { $sidebar = Sidebar::Get(); @@ -112,4 +296,12 @@ class Course_CoursewareController extends CoursewareController $sidebar->addWidget(new VueWidget('courseware-activities-widget-filter-type')); $sidebar->addWidget(new VueWidget('courseware-activities-widget-filter-unit')); } + + private function setCommentsOverviewSidebar(): void + { + $sidebar = Sidebar::Get(); + $sidebar->addWidget(new VueWidget('courseware-comments-overview-widget-filter-type')); + $sidebar->addWidget(new VueWidget('courseware-comments-overview-widget-filter-created')); + $sidebar->addWidget(new VueWidget('courseware-comments-overview-widget-filter-unit')); + } } diff --git a/app/views/course/courseware/comments_overview.php b/app/views/course/courseware/comments_overview.php new file mode 100644 index 0000000..358a5e5 --- /dev/null +++ b/app/views/course/courseware/comments_overview.php @@ -0,0 +1,5 @@ +
\ No newline at end of file diff --git a/lib/modules/CoursewareModule.class.php b/lib/modules/CoursewareModule.class.php index 56a205c..d085de2 100644 --- a/lib/modules/CoursewareModule.class.php +++ b/lib/modules/CoursewareModule.class.php @@ -67,6 +67,10 @@ class CoursewareModule extends CorePlugin implements SystemPlugin, StudipModule 'tasks', new Navigation(_('Aufgaben'), 'dispatch.php/course/courseware/tasks?cid=' . $courseId) ); + $navigation->addSubNavigation( + 'comments', + new Navigation(_('Kommentare und Feedback'), 'dispatch.php/course/courseware/comments_overview?cid=' . $courseId) + ); return ['courseware' => $navigation]; } diff --git a/resources/assets/javascripts/bootstrap/courseware.js b/resources/assets/javascripts/bootstrap/courseware.js index ccb7892..d24bd4d 100644 --- a/resources/assets/javascripts/bootstrap/courseware.js +++ b/resources/assets/javascripts/bootstrap/courseware.js @@ -86,4 +86,15 @@ STUDIP.domReady(() => { }); }); } + + if (document.getElementById('courseware-comments-app')) { + STUDIP.Vue.load().then(({ createApp }) => { + import( + /* webpackChunkName: "courseware-comments-app" */ + '@/vue/courseware-comments-app.js' + ).then(({ default: mountApp }) => { + return mountApp(STUDIP, createApp, '#courseware-comments-app'); + }); + }); + } }); diff --git a/resources/assets/stylesheets/scss/courseware.scss b/resources/assets/stylesheets/scss/courseware.scss index 09a3a7e..964d1bf 100644 --- a/resources/assets/stylesheets/scss/courseware.scss +++ b/resources/assets/stylesheets/scss/courseware.scss @@ -2254,15 +2254,21 @@ c o m m e n t s & f e e d b a c k scroll-behavior: smooth; } +.studip-dialog-content { + .cw-structural-element-feedback-items, + .cw-structural-element-comments-items, + .cw-block-feedback-items, + .cw-block-comments-items { + max-height: unset; + } +} + .cw-talk-bubble { margin: 10px 20px; position: relative; width: 85%; height: auto; - background-color: $dark-gray-color-10; - border-radius: 5px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; + background-color: var(--dark-gray-color-10); float: left; .cw-talk-bubble-talktext { @@ -2271,7 +2277,7 @@ c o m m e n t s & f e e d b a c k line-height: 1.5em; .cw-talk-bubble-talktext-time { - color: $dark-gray-color-45; + color: var(--dark-gray-color-80); text-align: right; font-size: 0.8em; margin-bottom: -0.5em; @@ -2290,10 +2296,7 @@ c o m m e n t s & f e e d b a c k top: 0px; bottom: auto; border: 22px solid; - border-color: $dark-gray-color-10 transparent transparent transparent; - border-radius: 5px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; + border-color: var(--dark-gray-color-10) transparent transparent transparent; left: -20px; right: auto; } @@ -2312,7 +2315,7 @@ c o m m e n t s & f e e d b a c k span { padding-left: 4px; - color: $dark-gray-color-45; + color: var(--dark-gray-color-45); font-weight: 600; vertical-align: top; } @@ -5697,3 +5700,14 @@ r a d i o s e t /* * * * * * * * * * * * r a d i o s e t e n d * * * * * * * * * * * */ +/* * * * * * * * * * * * * * * * +c o m m e n t s o v e r v i e w +* * * * * * * * * * * * * * * */ + +.cw-comments-overview-dialog-comments-context { + margin: 0 0 1.5em 0; +} + +/* * * * * * * * * * * * * * * * * * * * +c o m m e n t s o v e r v i e w e n d +* * * * * * * * * * * * * * * * * * * */ diff --git a/resources/vue/components/courseware/CommentsApp.vue b/resources/vue/components/courseware/CommentsApp.vue new file mode 100644 index 0000000..1716d4d --- /dev/null +++ b/resources/vue/components/courseware/CommentsApp.vue @@ -0,0 +1,46 @@ + + + \ No newline at end of file diff --git a/resources/vue/components/courseware/CoursewareBlockComments.vue b/resources/vue/components/courseware/CoursewareBlockComments.vue index 8e18909..6ef3322 100644 --- a/resources/vue/components/courseware/CoursewareBlockComments.vue +++ b/resources/vue/components/courseware/CoursewareBlockComments.vue @@ -1,5 +1,6 @@ + + diff --git a/resources/vue/components/courseware/CoursewareBlockFeedback.vue b/resources/vue/components/courseware/CoursewareBlockFeedback.vue index 88ac2d7..a34ad8f 100644 --- a/resources/vue/components/courseware/CoursewareBlockFeedback.vue +++ b/resources/vue/components/courseware/CoursewareBlockFeedback.vue @@ -4,6 +4,7 @@ class="cw-block-feedback" :class="[emptyFeedback ? 'cw-block-feedback-empty' : '']" > + {{ srMessage }}
+ + + + + + diff --git a/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterCreated.vue b/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterCreated.vue new file mode 100644 index 0000000..96074cd --- /dev/null +++ b/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterCreated.vue @@ -0,0 +1,51 @@ + + + diff --git a/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterType.vue b/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterType.vue new file mode 100644 index 0000000..9aaf617 --- /dev/null +++ b/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterType.vue @@ -0,0 +1,51 @@ + + + diff --git a/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterUnit.vue b/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterUnit.vue new file mode 100644 index 0000000..4d0afd1 --- /dev/null +++ b/resources/vue/components/courseware/CoursewareCommentsOverviewWidgetFilterUnit.vue @@ -0,0 +1,60 @@ + + + diff --git a/resources/vue/components/courseware/CoursewareStructuralElementComments.vue b/resources/vue/components/courseware/CoursewareStructuralElementComments.vue index 197d1bf..d1f48b5 100644 --- a/resources/vue/components/courseware/CoursewareStructuralElementComments.vue +++ b/resources/vue/components/courseware/CoursewareStructuralElementComments.vue @@ -3,6 +3,7 @@ class="cw-structural-element-comments" :class="[emptyComments ? 'cw-structural-element-comments-empty' : '']" > + {{ srMessage }}
+ + + + diff --git a/resources/vue/components/courseware/CoursewareStructuralElementFeedback.vue b/resources/vue/components/courseware/CoursewareStructuralElementFeedback.vue index 249b13a..3fa2c3c 100644 --- a/resources/vue/components/courseware/CoursewareStructuralElementFeedback.vue +++ b/resources/vue/components/courseware/CoursewareStructuralElementFeedback.vue @@ -4,6 +4,7 @@ class="cw-structural-element-feedback" :class="[emptyFeedback ? 'cw-structural-element-feedback-empty' : '']" > + {{ srMessage }}
{ + const getHttpClient = () => + axios.create({ + baseURL: STUDIP.URLHelper.getURL(`jsonapi.php/v1`, {}, true), + headers: { + 'Content-Type': 'application/vnd.api+json', + }, + }); + + let elem = document.getElementById(element.substring(1)); + let entry_id = null; + let entry_type = null; + + if (elem !== undefined) { + if (elem.attributes !== undefined) { + if (elem.attributes['entry-type'] !== undefined) { + entry_type = elem.attributes['entry-type'].value; + } + if (elem.attributes['entry-id'] !== undefined) { + entry_id = elem.attributes['entry-id'].value; + } + } + } + + const httpClient = getHttpClient(); + + const store = new Vuex.Store({ + modules: { + 'courseware-comments': CoursewareCommentsModule, + ...mapResourceModules({ + names: [ + 'courseware-blocks', + 'courseware-block-comments', + 'courseware-block-feedback', + 'courseware-containers', + 'courseware-units', + 'courseware-structural-elements', + 'courseware-structural-element-comments', + 'courseware-structural-element-feedback', + 'users', + 'course-memberships', + 'institutes', + 'institute-memberships', + ], + httpClient, + }), + }, + }); + store.dispatch('setHttpClient', httpClient); + store.dispatch('setContext', { + id: entry_id, + type: entry_type, + }); + store.dispatch('setUserId', STUDIP.USER_ID); + await store.dispatch('users/loadById', { id: STUDIP.USER_ID }); + await store.dispatch('loadTeacherStatus', STUDIP.USER_ID); + + const data = await axios(STUDIP.URLHelper.getURL('dispatch.php/course/courseware/comments_overview_data/')); + store.commit( + 'courseware-units/REPLACE_ALL_RECORDS', + JSON.parse(data.data['units']).data, + { root: true } + ); + store.commit( + 'courseware-structural-elements/REPLACE_ALL_RECORDS', + JSON.parse(data.data['elements']).data, + { root: true } + ); + store.commit( + 'courseware-containers/REPLACE_ALL_RECORDS', + JSON.parse(data.data['containers']).data, + { root: true } + ); + store.commit( + 'courseware-blocks/REPLACE_ALL_RECORDS', + JSON.parse(data.data['blocks']).data, + { root: true } + ); + store.commit( + 'courseware-block-comments/REPLACE_ALL_RECORDS', + JSON.parse(data.data['block_comments']).data, + { root: true } + ); + store.commit( + 'courseware-block-feedback/REPLACE_ALL_RECORDS', + JSON.parse(data.data['block_feedbacks']).data, + { root: true } + ); + store.commit( + 'courseware-structural-element-comments/REPLACE_ALL_RECORDS', + JSON.parse(data.data['element_comments']).data, + { root: true } + ); + store.commit( + 'courseware-structural-element-feedback/REPLACE_ALL_RECORDS', + JSON.parse(data.data['element_feedbacks']).data, + { root: true } + ); + + const app = createApp({ + render: (h) => h(CommentsApp), + store, + }); + + app.$mount(element); +}; + +export default mountApp; diff --git a/resources/vue/mixins/courseware/comments-overview-helper.js b/resources/vue/mixins/courseware/comments-overview-helper.js new file mode 100644 index 0000000..f45d6ea --- /dev/null +++ b/resources/vue/mixins/courseware/comments-overview-helper.js @@ -0,0 +1,16 @@ +export default { + methods: { + calcCreated(mkdate) { + let created = {oneDay: false, oneWeek: false}; + const delta = (new Date() - new Date(mkdate)) / 1000 / 60 / 60 / 24; + if (delta < 2) { + created.oneDay = true; + } + if (delta < 8) { + created.oneWeek = true; + } + + return created; + } + } +} \ No newline at end of file diff --git a/resources/vue/store/courseware/courseware-comments.module.js b/resources/vue/store/courseware/courseware-comments.module.js new file mode 100644 index 0000000..c65ee11 --- /dev/null +++ b/resources/vue/store/courseware/courseware-comments.module.js @@ -0,0 +1,146 @@ +const getDefaultState = () => { + return { + context: null, + httpClient: null, + userId: null, + userIsTeacher: false, + teacherStatusLoaded: false, + typeFilter: 'all', // all, blocks, elements + createdFilter: 'all', // all, oneDay, oneWeek + unitFilter: 'all', // all or unit id + }; +}; + +const initialState = getDefaultState(); + +const getters = { + context(state) { + return state.context; + }, + httpClient(state) { + return state.httpClient; + }, + userId(state) { + return state.userId; + }, + userIsTeacher(state) { + return state.userIsTeacher; + }, + teacherStatusLoaded(state) { + return state.teacherStatusLoaded; + }, + typeFilter(state) { + return state.typeFilter; + }, + createdFilter(state) { + return state.createdFilter; + }, + unitFilter(state) { + return state.unitFilter; + } +}; + +export const state = { ...initialState }; + +export const actions = { + // setters + setContext({ commit }, context) { + commit('setContext', context); + }, + setHttpClient({ commit }, httpClient) { + commit('setHttpClient', httpClient); + }, + setUserId({ commit }, id) { + commit('setUserId', id); + }, + setTypeFilter({ commit }, type) { + commit('setTypeFilter', type); + }, + setCreatedFilter({ commit }, created) { + commit('setCreatedFilter', created); + }, + setUnitFilter({ commit }, id) { + commit('setUnitFilter', id); + }, + // other actions + async loadTeacherStatus({ dispatch, rootGetters, state, commit, getters }, userId) { + const user = rootGetters['users/byId']({ id: userId }); + + if (user.attributes.permission === 'root') { + commit('setUserIsTeacher', true); + return; + } + if (user.attributes.permission === 'admin') { + await dispatch('courses/loadById', { id: state.context.id }); + const course = rootGetters['courses/byId']({id: state.context.id }); + const instituteId = course.relationships.institute.data.id; + + const parent = { type: 'users', id: `${userId}` }; + const relationship = 'institute-memberships'; + const options = {}; + await dispatch('institute-memberships/loadRelated', { parent, relationship, options }, { root: true }); + const instituteMemberships = rootGetters['institute-memberships/all']; + const instituteMembership = instituteMemberships.filter(membership => membership.relationships.institute.data.id === instituteId); + + if (instituteMembership.length > 0 && instituteMembership[0].attributes.permission === 'admin') { + commit('setUserIsTeacher', true); + return; + } + } + + const membershipId = `${state.context.id}_${userId}`; + try { + await dispatch('course-memberships/loadById', { id: membershipId }); + } catch (error) { + console.error(`Could not find course membership for ${membershipId}.`); + commit('setUserIsTeacher', false); + + return false; + } + const membership = rootGetters['course-memberships/byId']({ id: membershipId }); + if (membership) { + const membershipPermission = membership.attributes.permission; + const isTeacher = membershipPermission === 'dozent' || membershipPermission === 'tutor'; + commit('setUserIsTeacher', isTeacher); + + return true; + } else { + console.error(`Could not find course membership for ${membershipId}.`); + commit('setUserIsTeacher', false); + + return false; + } + }, +}; + +export const mutations = { + setContext(state, data) { + state.context = data; + }, + setHttpClient(state, data) { + state.httpClient = data; + }, + setUserId(state, data) { + state.userId = data; + }, + setTypeFilter(state, data) { + state.typeFilter = data; + }, + setCreatedFilter(state, data) { + state.createdFilter = data; + }, + setUnitFilter(state, data) { + state.unitFilter = data; + }, + setUserIsTeacher(state, isTeacher) { + state.teacherStatusLoaded = true; + state.userIsTeacher = isTeacher; + }, +}; + +export default { + state, + actions, + mutations, + getters, +}; \ No newline at end of file -- cgit v1.0