Forked from
Stud.IP / Stud.IP
-
Jan-Hendrik Willms authoredJan-Hendrik Willms authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
courseware.module.js 30.19 KiB
import axios from 'axios';
const getDefaultState = () => {
return {
blockAdder: {},
containerAdder: false,
consumeMode: false,
context: {},
courseware: {},
currentElement: {},
oerTitle: null,
licenses: null, // we need a route for License SORM
httpClient: null,
lastElement: null,
msg: 'Dehydrated',
msgCompanionOverlay:
'Hallo! Ich bin Ihr persönlicher Companion. Wussten Sie schon, dass Courseware jetzt noch einfacher zu bedienen ist?',
styleCompanionOverlay: 'default',
pluginManager: null,
showCompanionOverlay: false,
showToolbar: false,
urlHelper: null,
userId: null,
viewMode: 'read',
filingData: {},
userIsTeacher: false,
showStructuralElementEditDialog: false,
showStructuralElementAddDialog: false,
showStructuralElementExportDialog: false,
showStructuralElementInfoDialog: false,
showStructuralElementDeleteDialog: false,
showStructuralElementOerDialog: false,
};
};
const initialState = getDefaultState();
const getters = {
msg(state) {
return state.msg;
},
lastElement(state) {
return state.lastElement;
},
courseware(state) {
return state.courseware;
},
currentElement(state) {
return state.currentElement;
},
oerTitle(state) {
return state.oerTitle;
},
licenses(state) {
return state.licenses;
},
context(state) {
return state.context;
},
blockTypes(state) {
return state.courseware?.attributes?.['block-types'] ?? [];
},
containerTypes(state) {
return state.courseware?.attributes?.['container-types'] ?? [];
},
favoriteBlockTypes(state) {
const allBlockTypes = state.courseware?.attributes?.['block-types'] ?? [];
const favorites = state.courseware?.attributes?.['favorite-block-types'] ?? [];
return allBlockTypes.filter(({ type }) => favorites.includes(type));
},
viewMode(state) {
return state.viewMode;
},
showToolbar(state) {
return state.showToolbar;
},
blockAdder(state) {
return state.blockAdder;
},
containerAdder(state) {
return state.containerAdder;
},
showCompanionOverlay(state) {
return state.showCompanionOverlay;
},
msgCompanionOverlay(state) {
return state.msgCompanionOverlay;
},
styleCompanionOverlay(state) {
return state.styleCompanionOverlay;
},
consumeMode(state) {
return state.consumeMode;
},
httpClient(state) {
return state.httpClient;
},
urlHelper(state) {
return state.urlHelper;
},
userId(state) {
return state.userId;
},
userIsTeacher(state) {
return state.userIsTeacher;
},
pluginManager(state) {
return state.pluginManager;
},
filingData(state) {
return state.filingData;
},
showStructuralElementEditDialog(state) {
return state.showStructuralElementEditDialog;
},
showStructuralElementAddDialog(state) {
return state.showStructuralElementAddDialog;
},
showStructuralElementExportDialog(state) {
return state.showStructuralElementExportDialog;
},
showStructuralElementInfoDialog(state) {
return state.showStructuralElementInfoDialog;
},
showStructuralElementOerDialog(state) {
return state.showStructuralElementOerDialog;
},
showStructuralElementDeleteDialog(state) {
return state.showStructuralElementDeleteDialog;
}
};
export const state = { ...initialState };
export const actions = {
async loadCoursewareStructure({ commit, dispatch, state, rootGetters }) {
const parent = state.context;
const relationship = 'courseware';
const options = {
include: 'bookmarks,root,root.descendants',
};
await dispatch(`courseware-instances/loadRelated`, { parent, relationship, options }, { root: true });
return commit('coursewareSet', rootGetters['courseware-instances/all'][0]);
},
loadContainer({ dispatch }, containerId) {
const options = {
include: 'blocks',
};
return dispatch('courseware-containers/loadById', { id: containerId, options }, { root: true });
},
loadStructuralElement({ dispatch }, structuralElementId) {
const options = {
include:
'ancestors,containers,containers.blocks,containers.blocks.editor,containers.blocks.owner,containers.blocks.user-data-field,containers.blocks.user-progress,descendants,editor,owner',
'fields[users]': 'formatted-name',
};
return dispatch(
'courseware-structural-elements/loadById',
{ id: structuralElementId, options },
{ root: true }
);
},
loadFileRefs({ dispatch, rootGetters }, block_id) {
const parent = {
type: 'courseware-blocks',
id: block_id,
};
const relationship = 'file-refs';
return dispatch('courseware-blocks/loadRelated', { parent, relationship }, { root: true }).then(() => {
const refs = rootGetters['courseware-blocks/related']({
parent,
relationship,
});
return refs;
});
},
async createFile(context, { file, filedata, folder }) {
const formData = new FormData();
formData.append('file', filedata, file.attributes.name);
const url = `folders/${folder.id}/file-refs`;
let request = await state.httpClient.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return state.httpClient.get(request.headers.location).then((response) => {
return response.data.data;
});
},
async createRootFolder({ dispatch, rootGetters }, { context, folder }) {
// get root folder for this context
await dispatch(
'courses/loadRelated',
{
parent: context,
relationship: 'folders',
},
{ root: true }
);
let folders = await rootGetters['courses/related']({
parent: context,
relationship: 'folders',
});
let rootFolder = null;
for (let i = 0; i < folders.length; i++) {
if (folders[i].attributes['folder-type'] === 'RootFolder') {
rootFolder = folders[i];
}
}
const newFolder = {
data: {
type: 'folders',
attributes: {
name: folder.name,
'folder-type': 'StandardFolder',
},
relationships: {
parent: {
data: {
type: 'folders',
id: rootFolder.id,
},
},
},
},
};
return state.httpClient.post(`courses/${context.id}/folders`, newFolder).then((response) => {
return response.data.data;
});
},
async createFolder(store, { context, parent, folder }) {
const newFolder = {
data: {
type: 'folders',
attributes: {
name: folder.name,
'folder-type': folder.type,
},
relationships: {
parent: parent,
},
},
};
return state.httpClient.post(`courses/${context.id}/folders`, newFolder).then((response) => {
return response.data.data;
});
},
loadFolder({ dispatch }, folderId) {
const options = {};
return dispatch('folders/loadById', { id: folderId, options }, { root: true });
},
copyBlock({ getters }, { parentId, block }) {
const copy = {
data: {
block: block,
parent_id: parentId,
},
};
return state.httpClient.post(`courseware-blocks/${block.id}/copy`, copy).then((resp) => {
// console.log(resp);
});
},
copyContainer({ getters }, { parentId, container }) {
const copy = {
data: {
container: container,
parent_id: parentId,
},
};
return state.httpClient.post(`courseware-containers/${container.id}/copy`, copy).then((resp) => {
// console.log(resp);
});
},
copyStructuralElement({ getters }, { parentId, element }) {
const copy = {
data: {
element: element,
parent_id: parentId,
},
};
return state.httpClient.post(`courseware-structural-elements/${element.id}/copy`, copy).then((resp) => {
// console.log(resp);
});
},
lockObject({ dispatch, getters }, { id, type }) {
return dispatch(`${type}/setRelated`, {
parent: { id, type },
relationship: 'edit-blocker',
data: {
type: 'users',
id: getters.userId,
},
});
},
async createBlockInContainer({ dispatch }, { container, blockType }) {
const block = {
attributes: {
'block-type': blockType,
payload: null,
},
relationships: {
container: {
data: { type: container.type, id: container.id },
},
},
};
await dispatch('courseware-blocks/create', block, { root: true });
return dispatch('loadContainer', container.id);
},
async deleteBlockInContainer({ dispatch }, { containerId, blockId }) {
const data = {
id: blockId,
};
await dispatch('courseware-blocks/delete', data, { root: true });
//TODO throws TypeError: block is undefined after delete
return dispatch('loadContainer', containerId);
},
async updateBlockInContainer({ dispatch }, { attributes, blockId, containerId }) {
const container = {
type: 'courseware-containers',
id: containerId,
};
const block = {
type: 'courseware-blocks',
attributes: attributes,
id: blockId,
relationships: {
container: {
data: { type: container.type, id: container.id },
},
},
};
await dispatch('courseware-blocks/update', block, { root: true });
await dispatch('unlockObject', { id: blockId, type: 'courseware-blocks' });
return dispatch('loadContainer', containerId);
},
async updateBlock({ dispatch }, { block, containerId }) {
const container = {
type: 'courseware-containers',
id: containerId,
};
const updateBlock = {
type: 'courseware-blocks',
attributes: block.attributes,
id: block.id,
relationships: {
container: {
data: { type: container.type, id: container.id },
},
},
};
await dispatch('courseware-blocks/update', updateBlock, { root: true });
return dispatch('loadContainer', containerId);
},
async deleteBlock({ dispatch }, { containerId, blockId }) {
const data = {
id: blockId,
};
await dispatch('courseware-blocks/delete', data, { root: true });
//TODO throws TypeError: block is undefined after delete
return dispatch('loadContainer', containerId);
},
async storeCoursewareSettings({ dispatch, getters }, { permission, progression }) {
const courseware = getters.courseware;
courseware.attributes['editing-permission-level'] = permission;
courseware.attributes['sequential-progression'] = progression;
return dispatch('courseware-instances/update', courseware, { root: true });
},
sortChildrenInStructualElements({ dispatch }, { parent, children }) {
const childrenResourceIdentifiers = children.map(({ type, id }) => ({ type, id }));
return dispatch(
`courseware-structural-elements/setRelated`,
{
parent: { type: parent.type, id: parent.id },
relationship: 'children',
data: childrenResourceIdentifiers,
},
{ root: true }
);
},
async createStructuralElement({ dispatch }, { attributes, parentId, currentId }) {
const data = {
attributes,
relationships: {
parent: {
data: {
type: 'courseware-structural-elements',
id: parentId,
},
},
},
};
await dispatch('courseware-structural-elements/create', data, { root: true });
return dispatch('loadStructuralElement', currentId);
},
async deleteStructuralElement({ dispatch }, { id, parentId }) {
const data = {
id: id,
};
await dispatch('courseware-structural-elements/delete', data, { root: true });
return dispatch('loadStructuralElement', parentId);
},
async updateStructuralElement({ dispatch }, { element, id }) {
await dispatch('courseware-structural-elements/update', element, { root: true });
return dispatch('loadStructuralElement', id);
},
sortContainersInStructualElements({ dispatch }, { structuralElement, containers }) {
const containerResourceIdentifiers = containers.map(({ type, id }) => ({ type, id }));
return dispatch(
`courseware-structural-elements/setRelated`,
{
parent: { type: structuralElement.type, id: structuralElement.id },
relationship: 'containers',
data: containerResourceIdentifiers,
},
{ root: true }
);
},
async createContainer({ dispatch }, { attributes, structuralElementId }) {
const data = {
attributes,
relationships: {
'structural-element': {
data: {
type: 'courseware-structural-elements',
id: structuralElementId,
},
},
},
};
await dispatch('courseware-containers/create', data, { root: true });
return dispatch('loadStructuralElement', structuralElementId);
},
async deleteContainer({ dispatch }, { containerId, structuralElementId }) {
const data = {
id: containerId,
};
await dispatch('courseware-containers/delete', data, { root: true });
//TODO throws TypeError: container is undefined after delete
return dispatch('loadStructuralElement', structuralElementId);
},
async updateContainer({ dispatch }, { container, structuralElementId }) {
await dispatch('courseware-containers/update', container, { root: true });
return dispatch('loadStructuralElement', structuralElementId);
},
sortBlocksInContainer({ dispatch }, { container, sections }) {
let blockResourceIdentifiers = [];
sections.forEach((section) => {
blockResourceIdentifiers.push(...section.blocks.map(({ type, id }) => ({ type, id })));
});
return dispatch(
`courseware-containers/setRelated`,
{
parent: { type: container.type, id: container.id },
relationship: 'blocks',
data: blockResourceIdentifiers,
},
{ root: true }
);
},
lockObject({ dispatch, getters }, { id, type }) {
return dispatch(`${type}/setRelated`, {
parent: { id, type },
relationship: 'edit-blocker',
data: {
type: 'users',
id: getters.userId,
},
});
},
unlockObject({ dispatch }, { id, type }) {
return dispatch(`${type}/setRelated`, {
parent: { id, type },
relationship: 'edit-blocker',
data: null,
});
},
async companionInfo({ dispatch }, { info }) {
await dispatch('coursewareStyleCompanionOverlay', 'default');
await dispatch('coursewareMsgCompanionOverlay', info);
return dispatch('coursewareShowCompanionOverlay', true);
},
async companionSuccess({ dispatch }, { info }) {
await dispatch('coursewareStyleCompanionOverlay', 'happy');
await dispatch('coursewareMsgCompanionOverlay', info);
return dispatch('coursewareShowCompanionOverlay', true);
},
async companionError({ dispatch }, { info }) {
await dispatch('coursewareStyleCompanionOverlay', 'sad');
await dispatch('coursewareMsgCompanionOverlay', info);
return dispatch('coursewareShowCompanionOverlay', true);
},
async companionWarning({ dispatch }, { info }) {
await dispatch('coursewareStyleCompanionOverlay', 'alert');
await dispatch('coursewareMsgCompanionOverlay', info);
return dispatch('coursewareShowCompanionOverlay', true);
},
async companionSpecial({ dispatch }, { info }) {
await dispatch('coursewareStyleCompanionOverlay', 'special');
await dispatch('coursewareMsgCompanionOverlay', info);
return dispatch('coursewareShowCompanionOverlay', true);
},
// adds a favorite block type using the `type` of the BlockType
async addFavoriteBlockType({ dispatch, getters }, blockType) {
const blockTypes = new Set(getters.favoriteBlockTypes.map(({ type }) => type));
blockTypes.add(blockType);
return dispatch('storeFavoriteBlockTypes', [...blockTypes]);
},
// removes a favorite block type using the `type` of the BlockType
async removeFavoriteBlockType({ dispatch, getters }, blockType) {
const blockTypes = new Set(getters.favoriteBlockTypes.map(({ type }) => type));
blockTypes.delete(blockType);
return dispatch('storeFavoriteBlockTypes', [...blockTypes]);
},
// sets the favorite block types using an array of the `type`s of those BlockTypes
async storeFavoriteBlockTypes({ dispatch, getters }, favoriteBlockTypes) {
const courseware = getters.courseware;
courseware.attributes['favorite-block-types'] = favoriteBlockTypes;
return dispatch('courseware-instances/update', courseware, { root: true });
},
coursewareCurrentElement(context, id) {
context.commit('coursewareCurrentElementSet', id);
},
coursewareContext(context, id) {
context.commit('coursewareContextSet', id);
},
oerTitle(context, title) {
context.commit('oerTitleSet', title);
},
licenses(context, licenses) {
context.commit('licensesSet', licenses);
},
coursewareViewMode(context, view) {
context.commit('coursewareViewModeSet', view);
},
coursewareShowToolbar(context, toolbar) {
context.commit('coursewareShowToolbarSet', toolbar);
},
coursewareBlockAdder(context, adder) {
context.commit('coursewareBlockAdderSet', adder);
},
coursewareContainerAdder(context, adder) {
context.commit('coursewareContainerAdderSet', adder);
},
coursewareShowCompanionOverlay(context, companion_overlay) {
context.commit('coursewareShowCompanionOverlaySet', companion_overlay);
},
coursewareMsgCompanionOverlay(context, companion_overlay_msg) {
context.commit('coursewareMsgCompanionOverlaySet', companion_overlay_msg);
},
coursewareStyleCompanionOverlay(context, companion_overlay_style) {
context.commit('coursewareStyleCompanionOverlaySet', companion_overlay_style);
},
coursewareConsumeMode(context, mode) {
context.commit('coursewareConsumeModeSet', mode);
},
setHttpClient({ commit }, httpClient) {
commit('setHttpClient', httpClient);
},
setUrlHelper({ commit }, urlHelper) {
commit('setUrlHelper', urlHelper);
},
setUserId({ commit }, userId) {
commit('setUserId', userId);
},
showElementEditDialog(context, bool) {
context.commit('setShowStructuralElementEditDialog', bool)
},
showElementAddDialog(context, bool) {
context.commit('setShowStructuralElementAddDialog', bool)
},
showElementExportDialog(context, bool) {
context.commit('setShowStructuralElementExportDialog', bool)
},
showElementInfoDialog(context, bool) {
context.commit('setShowStructuralElementInfoDialog', bool)
},
showElementOerDialog(context, bool) {
context.commit('setShowStructuralElementOerDialog', bool)
},
showElementDeleteDialog(context, bool) {
context.commit('setShowStructuralElementDeleteDialog', bool)
},
addBookmark({ dispatch, rootGetters }, structuralElement) {
const cw = rootGetters['courseware'];
// get existing bookmarks
const bookmarks =
rootGetters['courseware-structural-elements/related']({
parent: cw,
relationship: 'bookmarks',
})?.map(({ type, id }) => ({ type, id })) ?? [];
// add a new bookmark
const data = [...bookmarks, { type: structuralElement.type, id: structuralElement.id }];
// send them home
return dispatch(
`courseware-structural-elements/setRelated`,
{
parent: { type: cw.type, id: cw.id },
relationship: 'bookmarks',
data,
},
{ root: true }
);
},
removeBookmark({ dispatch, rootGetters }, structuralElement) {
const cw = rootGetters['courseware'];
// get existing bookmarks
const bookmarks =
rootGetters['courseware-structural-elements/related']({
parent: cw,
relationship: 'bookmarks',
})?.map(({ type, id }) => ({ type, id })) ?? [];
// filter bookmark that must be removed
const data = bookmarks.filter(({ id }) => id !== structuralElement.id);
// send them home
return dispatch(
`courseware-structural-elements/setRelated`,
{
parent: { type: cw.type, id: cw.id },
relationship: 'bookmarks',
data,
},
{ root: true }
);
},
setPluginManager({ commit }, pluginManager) {
commit('setPluginManager', pluginManager);
},
uploadImageForStructuralElement({ dispatch, state }, { structuralElement, file }) {
const formData = new FormData();
formData.append('image', file);
const url = `courseware-structural-elements/${structuralElement.id}/image`;
return state.httpClient.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
},
async deleteImageForStructuralElement({ dispatch, state }, structuralElement) {
const url = `courseware-structural-elements/${structuralElement.id}/image`;
await state.httpClient.delete(url);
return dispatch('loadStructuralElement', structuralElement.id);
},
cwManagerFilingData(context, msg) {
context.commit('cwManagerFilingDataSet', msg);
},
loadUsersCourses({ dispatch, rootGetters, state }, userId) {
const parent = {
type: 'users',
id: userId,
};
const relationship = 'course-memberships';
const options = {
include: 'course',
};
return dispatch('course-memberships/loadRelated', { parent, relationship, options }, { root: true }).then(
() => {
const memberships = rootGetters['course-memberships/related']({
parent,
relationship,
});
let courses = [];
memberships.forEach((membership) => {
if (
membership.attributes.permission === 'dozent' &&
state.context.id !== membership.relationships.course.data.id
) {
courses.push(rootGetters['courses/related']({ parent: membership, relationship: 'course' }));
}
});
return courses;
}
);
},
loadRemoteCoursewareStructure({ dispatch, rootGetters }, { rangeId, rangeType }) {
const parent = {
id: rangeId,
type: rangeType,
};
const relationship = 'courseware';
return dispatch(`courseware-instances/loadRelated`, { parent, relationship }, { root: true }).then(
(response) => {
const instance = rootGetters['courseware-instances/related']({
parent: parent,
relationship: relationship,
});
return instance;
},
(error) => {
return null;
}
);
},
loadTeacherStatus({ dispatch, rootGetters, state, commit, getters }, userId) {
const parent = {
type: 'users',
id: userId,
};
const relationship = 'course-memberships';
const options = {
include: 'course',
};
return dispatch('course-memberships/loadRelated', { parent, relationship, options }, { root: true }).then(
() => {
const memberships = rootGetters['course-memberships/related']({
parent,
relationship,
});
let isTeacher = false;
memberships.forEach((membership) => {
if (getters.courseware.attributes['editing-permission-level'] === 'dozent') {
if (
membership.attributes.permission === 'dozent' &&
state.context.id === membership.relationships.course.data.id
) {
isTeacher = true;
}
}
if (getters.courseware.attributes['editing-permission-level'] === 'tutor') {
if (
(membership.attributes.permission === 'dozent' ||
membership.attributes.permission === 'tutor') &&
state.context.id === membership.relationships.course.data.id
) {
isTeacher = true;
}
}
});
return commit('setUserIsTeacher', isTeacher);
}
);
},
loadFeedback({ dispatch }, blockId) {
const parent = { type: 'courseware-blocks', id: `${blockId}` };
const relationship = 'feedback';
const options = {
include: 'user',
};
return dispatch('courseware-block-feedback/loadRelated', { parent, relationship, options }, { root: true });
},
async createFeedback({ dispatch }, { blockId, feedback }) {
const data = {
attributes: {
feedback,
},
relationships: {
block: {
data: {
type: 'courseware-blocks',
id: blockId,
},
},
},
};
await dispatch('courseware-block-feedback/create', data, { root: true });
return dispatch('loadFeedback', blockId);
},
};
/* eslint no-param-reassign: ["error", { "props": false }] */
export const mutations = {
coursewareSet(state, data) {
state.courseware = data;
},
coursewareCurrentElementSet(state, data) {
state.lastElement = state.currentElement;
state.currentElement = data;
},
coursewareContextSet(state, data) {
state.context = data;
},
oerTitleSet(state, data) {
state.oerTitle = data;
},
licensesSet(state, data) {
state.licenses = data;
},
coursewareViewModeSet(state, data) {
state.viewMode = data;
},
coursewareShowToolbarSet(state, data) {
state.showToolbar = data;
},
coursewareBlockAdderSet(state, data) {
state.blockAdder = data;
},
coursewareContainerAdderSet(state, data) {
state.containerAdder = data;
},
coursewareShowCompanionOverlaySet(state, data) {
state.showCompanionOverlay = data;
},
coursewareMsgCompanionOverlaySet(state, data) {
state.msgCompanionOverlay = data;
},
coursewareStyleCompanionOverlaySet(state, data) {
state.styleCompanionOverlay = data;
},
coursewareConsumeModeSet(state, data) {
state.consumeMode = data;
},
setHttpClient(state, httpClient) {
state.httpClient = httpClient;
},
setUrlHelper(state, urlHelper) {
state.urlHelper = urlHelper;
},
setUserId(state, userId) {
state.userId = userId;
},
setUserIsTeacher(state, isTeacher) {
state.userIsTeacher = isTeacher;
},
setPluginManager(state, pluginManager) {
state.pluginManager = pluginManager;
},
cwManagerFilingDataSet(state, data) {
state.filingData = data;
},
setShowStructuralElementEditDialog(state, showEdit) {
state.showStructuralElementEditDialog = showEdit;
},
setShowStructuralElementAddDialog(state, showAdd) {
state.showStructuralElementAddDialog = showAdd;
},
setShowStructuralElementExportDialog(state, showExport) {
state.showStructuralElementExportDialog = showExport;
},
setShowStructuralElementInfoDialog(state, showInfo) {
state.showStructuralElementInfoDialog = showInfo;
},
setShowStructuralElementOerDialog(state, showOer) {
state.showStructuralElementOerDialog = showOer;
},
setShowStructuralElementDeleteDialog(state, showDelete) {
state.showStructuralElementDeleteDialog = showDelete;
}
};
export default {
state,
actions,
mutations,
getters,
};