From b89e123230bf4334d15b7e3e4135de8e4332ca11 Mon Sep 17 00:00:00 2001 From: "\\nrlucke" <rlucke@uos.de> Date: Fri, 27 Aug 2021 10:46:16 +0100 Subject: [PATCH] fixes #120 --- .../JsonApi/Schemas/Courseware/Block.php | 2 +- lib/models/Courseware/Block.php | 12 ++++ .../Courseware/BlockTypes/BlockType.php | 3 +- lib/models/Courseware/BlockTypes/Error.json | 8 +++ lib/models/Courseware/BlockTypes/Error.php | 58 +++++++++++++++++++ .../courseware/CoursewareBlockActions.vue | 51 +++++++++------- .../courseware/CoursewareCompanionBox.vue | 4 +- .../courseware/CoursewareDefaultBlock.vue | 8 ++- .../courseware/CoursewareErrorBlock.vue | 56 ++++++++++++++++++ .../courseware/container-components.js | 2 + 10 files changed, 178 insertions(+), 26 deletions(-) create mode 100644 lib/models/Courseware/BlockTypes/Error.json create mode 100644 lib/models/Courseware/BlockTypes/Error.php create mode 100644 resources/vue/components/courseware/CoursewareErrorBlock.vue diff --git a/lib/classes/JsonApi/Schemas/Courseware/Block.php b/lib/classes/JsonApi/Schemas/Courseware/Block.php index 89434d976f2..ba3e21fea69 100755 --- a/lib/classes/JsonApi/Schemas/Courseware/Block.php +++ b/lib/classes/JsonApi/Schemas/Courseware/Block.php @@ -37,7 +37,7 @@ class Block extends SchemaProvider { return [ 'position' => (int) $resource['position'], - 'block-type' => (string) $resource['block_type'], + 'block-type' => (string) $resource->getBlockType(), 'title' => (string) $resource->type->getTitle(), 'visible' => (bool) $resource['visible'], 'payload' => $resource->type->getPayload(), diff --git a/lib/models/Courseware/Block.php b/lib/models/Courseware/Block.php index 57471fc56d2..c168462f09a 100755 --- a/lib/models/Courseware/Block.php +++ b/lib/models/Courseware/Block.php @@ -191,4 +191,16 @@ class Block extends \SimpleORMap return $block; } + + public function getBlockType(): ?string + { + if ($this->type->findBlockType($this->block_type)) { + return $this->block_type; + } else { + $this->payload = json_encode(array( + 'original_block_type' => $this->block_type + )); + return 'error'; + } + } } diff --git a/lib/models/Courseware/BlockTypes/BlockType.php b/lib/models/Courseware/BlockTypes/BlockType.php index 58e12c0bd2d..a25672dd315 100755 --- a/lib/models/Courseware/BlockTypes/BlockType.php +++ b/lib/models/Courseware/BlockTypes/BlockType.php @@ -160,7 +160,8 @@ abstract class BlockType { if (!($class = self::findBlockType($block['block_type']))) { // TODO: Hier müsste es eine weniger allgemeine Exception geben. - throw new \RuntimeException('Invalid `block_type` attribute in database.'); + // throw new \RuntimeException('Invalid `block_type` attribute in database.'); + return new \Courseware\BlockTypes\Error($block); } return new $class($block); diff --git a/lib/models/Courseware/BlockTypes/Error.json b/lib/models/Courseware/BlockTypes/Error.json new file mode 100644 index 00000000000..eb2e49e8d46 --- /dev/null +++ b/lib/models/Courseware/BlockTypes/Error.json @@ -0,0 +1,8 @@ +{ + "title": "Payload schema of Courseware\\BlockType\\Error", + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false +} + diff --git a/lib/models/Courseware/BlockTypes/Error.php b/lib/models/Courseware/BlockTypes/Error.php new file mode 100644 index 00000000000..2e154562383 --- /dev/null +++ b/lib/models/Courseware/BlockTypes/Error.php @@ -0,0 +1,58 @@ +<?php + +namespace Courseware\BlockTypes; + +use Opis\JsonSchema\Schema; + +/** + * This class represents the content of a Courseware error block. + * + * @author Ron Lucke <lucke@elan-ev.de> + * @license GPL2 or any later version + * + * @since Stud.IP 5.0 + */ +class Error extends BlockType +{ + public static function getType(): string + { + return 'error'; + } + + public static function getTitle(): string + { + return _('Fehler'); + } + + public static function getDescription(): string + { + return _('Zeigt eine Fehlemeldung an.'); + } + + public function initialPayload(): array + { + return []; + } + + public static function getJsonSchema(): Schema + { + $schemaFile = __DIR__.'/Error.json'; + + return Schema::fromJsonString(file_get_contents($schemaFile)); + } + + public static function getCategories(): array + { + return []; + } + + public static function getContentTypes(): array + { + return []; + } + + public static function getFileTypes(): array + { + return []; + } +} diff --git a/resources/vue/components/courseware/CoursewareBlockActions.vue b/resources/vue/components/courseware/CoursewareBlockActions.vue index 5b638eeef79..2c4c12b0361 100755 --- a/resources/vue/components/courseware/CoursewareBlockActions.vue +++ b/resources/vue/components/courseware/CoursewareBlockActions.vue @@ -23,6 +23,10 @@ export default { }, props: { canEdit: Boolean, + deleteOnly: { + type: Boolean, + default: false + }, block: Object, }, data() { @@ -44,29 +48,34 @@ export default { }, }, mounted() { + if (this.deleteOnly) { + this.menuItems = []; + } if (this.canEdit) { - this.menuItems.push({ id: 1, label: this.$gettext('Block bearbeiten'), icon: 'edit', emit: 'editBlock' }); - this.menuItems.push({ - id: 2, - label: this.block.attributes.visible - ? this.$gettext('unsichtbar setzen') - : this.$gettext('sichtbar setzen'), - icon: this.block.attributes.visible ? 'visibility-visible' : 'visibility-invisible', // do we change the icons ? - emit: 'setVisibility', - }); - this.menuItems.push({ - id: 5, - label: this.$gettext('Feedback anzeigen'), - icon: 'comment', - emit: 'showFeedback', - }); + if (!this.deleteOnly) { + this.menuItems.push({ id: 1, label: this.$gettext('Block bearbeiten'), icon: 'edit', emit: 'editBlock' }); + this.menuItems.push({ + id: 2, + label: this.block.attributes.visible + ? this.$gettext('unsichtbar setzen') + : this.$gettext('sichtbar setzen'), + icon: this.block.attributes.visible ? 'visibility-visible' : 'visibility-invisible', // do we change the icons ? + emit: 'setVisibility', + }); + this.menuItems.push({ + id: 5, + label: this.$gettext('Feedback anzeigen'), + icon: 'comment', + emit: 'showFeedback', + }); + this.menuItems.push({ + id: 7, + label: this.$gettext('Informationen zum Block'), + icon: 'info', + emit: 'showInfo', + }); + } this.menuItems.push({ - id: 7, - label: this.$gettext('Informationen zum Block'), - icon: 'info', - emit: 'showInfo', - }); - this.menuItems.push({ id: 9, label: this.$gettext('Block löschen'), icon: 'trash', diff --git a/resources/vue/components/courseware/CoursewareCompanionBox.vue b/resources/vue/components/courseware/CoursewareCompanionBox.vue index 9d9c2c173ce..f8dbbde812e 100755 --- a/resources/vue/components/courseware/CoursewareCompanionBox.vue +++ b/resources/vue/components/courseware/CoursewareCompanionBox.vue @@ -1,7 +1,7 @@ <template> <div class="cw-companion-box" :class="[mood]"> <div> - <p>{{ msgCompanion }}</p> + <p v-html="msgCompanion"></p> <slot name="companionActions"></slot> </div> </div> @@ -21,4 +21,4 @@ export default { } }, }; -</script> \ No newline at end of file +</script> diff --git a/resources/vue/components/courseware/CoursewareDefaultBlock.vue b/resources/vue/components/courseware/CoursewareDefaultBlock.vue index ff9c66eefd7..341168784dd 100755 --- a/resources/vue/components/courseware/CoursewareDefaultBlock.vue +++ b/resources/vue/components/courseware/CoursewareDefaultBlock.vue @@ -12,6 +12,7 @@ <courseware-block-actions :block="block" :canEdit="canEdit" + :deleteOnly="deleteOnly" @editBlock="displayFeature('Edit')" @showFeedback="displayFeature('Feedback')" @showComments="displayFeature('Comments')" @@ -101,9 +102,14 @@ export default { props: { block: Object, canEdit: Boolean, + deleteOnly: { + type: Boolean, + default: false + }, isTeacher: Boolean, preview: Boolean, defaultGrade: { + type: Boolean, default: true, }, }, @@ -152,7 +158,7 @@ export default { blockTitle() { const type = this.block.attributes['block-type']; - return this.blockTypes.find((blockType) => blockType.type === type)?.title || ''; + return this.blockTypes.find((blockType) => blockType.type === type)?.title || this.$gettext('Fehler'); }, }, mounted() { diff --git a/resources/vue/components/courseware/CoursewareErrorBlock.vue b/resources/vue/components/courseware/CoursewareErrorBlock.vue new file mode 100644 index 00000000000..f0eb1f671fd --- /dev/null +++ b/resources/vue/components/courseware/CoursewareErrorBlock.vue @@ -0,0 +1,56 @@ +<template> + <div class="cw-block cw-block-error"> + <courseware-default-block + :block="block" + :canEdit="canEdit" + :deleteOnly="true" + :isTeacher="isTeacher" + :preview="false" + :defaultGrade="false" + > + <template #content> + <div class="cw-block-error-content"> + <courseware-companion-box + mood="sad" + :msgCompanion="errorMessage" + > + </courseware-companion-box> + </div> + </template> + </courseware-default-block> + </div> +</template> + +<script> +import CoursewareDefaultBlock from './CoursewareDefaultBlock.vue'; +import { blockMixin } from './block-mixin.js'; +import CoursewareCompanionBox from './CoursewareCompanionBox.vue'; + +export default { + name: 'courseware-error-block', + mixins: [blockMixin], + components: { + CoursewareDefaultBlock, + CoursewareCompanionBox, + }, + props: { + block: Object, + canEdit: Boolean, + isTeacher: Boolean, + }, + computed: { + originalBlockType() { + return this.block?.attributes?.payload?.original_block_type; + }, + errorMessage() { + let message = '<b>' + message += this.$gettext('Es ist ein Fehler aufgetretten! Der Block-Typ dieses Blocks ist nicht verfügbar.'); + message += '</b><br>' + message += 'block_type: ' + this.originalBlockType + ' not found'; + + return message; + } + }, + +}; +</script> diff --git a/resources/vue/components/courseware/container-components.js b/resources/vue/components/courseware/container-components.js index d3a4cf9d58f..7ce04e483fc 100755 --- a/resources/vue/components/courseware/container-components.js +++ b/resources/vue/components/courseware/container-components.js @@ -13,6 +13,7 @@ import CoursewareDialogCardsBlock from './CoursewareDialogCardsBlock.vue'; import CoursewareDocumentBlock from './CoursewareDocumentBlock.vue'; import CoursewareDownloadBlock from './CoursewareDownloadBlock.vue'; import CoursewareEmbedBlock from './CoursewareEmbedBlock.vue'; +import CoursewareErrorBlock from './CoursewareErrorBlock.vue'; import CoursewareFolderBlock from './CoursewareFolderBlock.vue'; import CoursewareGalleryBlock from './CoursewareGalleryBlock.vue'; import CoursewareHeadlineBlock from './CoursewareHeadlineBlock.vue'; @@ -41,6 +42,7 @@ const ContainerComponents = { CoursewareDocumentBlock, CoursewareDownloadBlock, CoursewareEmbedBlock, + CoursewareErrorBlock, CoursewareFolderBlock, CoursewareGalleryBlock, CoursewareHeadlineBlock, -- GitLab