Newer
Older
/* eslint-disable no-await-in-loop */
import { mapActions, mapGetters } from 'vuex';
import JSZip from 'jszip';
import FileSaver from 'file-saver';
import axios from 'axios';
export default {
computed: {
...mapGetters({
courseware: 'courseware',
containerById: 'courseware-containers/byId',
folderById: 'folders/byId',
filesById: 'files/byId',
fileRefsById: 'file-refs/byId',
structuralElementById: 'courseware-structural-elements/byId',
allStructuralElements: 'courseware-structural-elements/all',
allBlocks: 'courseware-blocks/all',
}),
},
data() {
return {
exportFiles: {
json: [],
download: [],
},
initData() {
this.exportFiles = { json: [], download: [] };
this.elementCounter = 0;
this.exportElementCounter = 0;
},
async sendExportZip(root_id = null, options) {
let zip = await this.createExportFile(root_id, options);
this.setExportState(this.$gettext('Erstelle Zip-Archiv'));
this.setExportProgress(0);
await zip.generateAsync({ type: 'blob' }, function updateCallback(metadata) {
view.setExportProgress(metadata.percent.toFixed(0));
}).then(function (content) {
view.setExportState('');
view.setExportProgress(0);
FileSaver.saveAs(content, 'courseware-export-' + new Date().toISOString().slice(0, 10) + '.zip');
});
},
async createExportFile(root_id = null, options) {
if (!options || !options.completeExport) {
options.completeExport = false;
}
if (!root_id) {
root_id = this.courseware.relationships.root.data.id;
options.completeExport = true;
this.setExportState(this.$gettext('Exportiere Elemente'));
this.setExportProgress(0);
let exportData = await this.exportCourseware(root_id, options);
let zip = new JSZip();
zip.file('courseware.json', JSON.stringify(exportData.json));
zip.file('files.json', JSON.stringify(exportData.files.json));
if (options.completeExport) {
zip.file('settings.json', JSON.stringify(exportData.settings));
}
// add all additional files from blocks
let i = 1;
let filesCounter = Object.keys(exportData.files.download).length;
this.setExportState(this.$gettext('Lade Dateien'));
this.setExportProgress(0);
for (let id in exportData.files.download) {
zip.file(
id,
await fetch(exportData.files.download[id].url)
.then((response) => response.blob())
.then((textString) => {
return textString;
})
);
this.setExportProgress(parseInt(i / filesCounter * 100));
i++;
}
return zip;
},
async exportCourseware(root_id, options) {
let withChildren = false;
if (options && options.withChildren === true) {
withChildren = true;
}
await this.loadStructuralElement(root_id);
let root_element = await this.structuralElementById({id: root_id});
//prevent loss of data
root_element = JSON.parse(JSON.stringify(root_element));
// load whole courseware nonetheless, only export relevant elements
let elements = await this.allStructuralElements;
if (withChildren) {
this.elementCounter = this.countElements(elements);
} else {
this.elementCounter = root_element.relationships.containers.length;
}
root_element.containers = [];
if (root_element.relationships.containers?.data?.length) {
for (var j = 0; j < root_element.relationships.containers.data.length; j++) {
root_element.containers.push(
await this.exportContainer(
this.containerById({
id: root_element.relationships.containers.data[j].id,
})
)
);
}
}
if (withChildren && elements !== []) {
let children = await this.exportStructuralElement(root_id, elements);
root_element.children = children;
}
}
[root_element.imageId, root_element.imageType ] = await this.exportStructuralElementImage(root_element);
delete root_element.relationships;
delete root_element.links;
let settings = {
'editing-permission-level': 'tutor',
'sequential-progression': '0'
if (this.courseware != null) {
settings = {
'editing-permission-level': this.courseware.attributes['editing-permission-level'],
'sequential-progression': this.courseware.attributes['sequential-progression']
};
}
if (options && options.settings) {
settings = {
'editing-permission-level': options.settings['editing-permission-level'],
'sequential-progression': options.settings['sequential-progression']
};
}
return {
json: root_element,
files: this.exportFiles,
settings: settings
};
},
for (var i = 0; i < elements.length; i++) {
counter++;
counter += elements[i].relationships.containers.data.length;
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
async exportToOER(element, options) {
let formData = new FormData();
let exportZip = await this.createExportFile(element.id, options);
let zip = await exportZip.generateAsync({ type: 'blob' });
let description = element.attributes.payload.description ? element.attributes.payload.description : '';
let difficulty_start = element.attributes.payload.difficulty_start ? element.attributes.payload.difficulty_start : '1';
let difficulty_end = element.attributes.payload.difficulty_end ? element.attributes.payload.difficulty_end : '12';
if (element.relationships.image.data !== null) {
let image = {};
await axios.get(element.relationships.image.meta['download-url'] , {responseType: 'blob'}).then(response => { image = response.data });
formData.append("image", image);
}
formData.append("data[name]", element.attributes.title);
formData.append("tags[]", "Lernmaterial");
formData.append("file", zip, (element.attributes.title).replace(/\s+/g, '_') + '.zip');
formData.append("data[description]", description);
formData.append("data[difficulty_start]", difficulty_start);
formData.append("data[difficulty_end]", difficulty_end);
formData.append("data[category]", 'elearning');
axios({
method: 'post',
url: STUDIP.URLHelper.getURL('dispatch.php/oer/mymaterial/edit/'),
data: formData,
headers: { "Content-Type": "multipart/form-data"}
}).then( () => {
this.companionInfo({ info: this.$gettext('Die Seite wurde an den OER Campus gesendet.') });
}).catch(error => {
this.companionError({ info: this.$gettext('Beim Veröffentlichen der Seite ist ein Fehler aufgetreten.') });
});
},
async exportStructuralElement(parentId, data) {
let children = [];
for (var i = 0; i < data.length; i++) {
if (data[i].relationships.parent.data?.id === parentId && data[i].attributes['can-edit']) {
const content = { ...data[i] };
await this.loadStructuralElement(content.id);
let new_childs = await this.exportStructuralElement(data[i].id, data);
content.containers = [];
let element = this.structuralElementById({ id: content.id });
// load containers, if there are any for this struct
if (element.relationships.containers?.data?.length) {
for (var j = 0; j < element.relationships.containers.data.length; j++) {
content.containers.push(
await this.exportContainer(
this.containerById({
id: element.relationships.containers.data[j].id,
})
)
);
[content.imageId, content.imageType ] = await this.exportStructuralElementImage(element);
delete content.relationships;
content.children = new_childs;
children.push(content);
}
}
return children;
},
const fileId = element.relationships.image?.data?.id;
const fileType = element.relationships.image?.data?.type;
if (fileType === 'file-refs') {
await this.loadFileRefsById({id: fileId});
let fileRef = this.fileRefsById({id: fileId});
let fileRefData = {};
fileRefData.id = fileRef.id;
fileRefData.attributes = fileRef.attributes;
fileRefData.related_element_id = element.id;
fileRefData.folder = null;
this.exportFiles.json.push(fileRefData);
this.exportFiles.download[fileRef.id] = {
folder: null,
url: fileRef.meta['download-url']
};
}
return [fileId, fileType];
async exportContainer(container_ref) {
// make a local copy of the container
let container = { ...container_ref };
container.blocks = [];
let blocks = this.allBlocks;
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
// now, load the blocks for this container, if there are any
if (blocks.length) {
for (var k = 0; k < blocks.length; k++) {
if (blocks[k].relationships.container?.data.id === container.id) {
container.blocks.push(await this.exportBlock(blocks[k]));
}
}
}
delete container.relationships;
return container;
},
async exportBlock(block_ref) {
// make a local copy of the block
let block = { ...block_ref };
// export file data (if any)
if (block_ref.relationships['file-refs']?.links?.related) {
await this.exportFileRefs(block_ref.id);
}
delete block.relationships;
return block;
},
async exportFileRefs(block_id) {
// load file-ref data
let refs = []
try {
refs = await this.loadFileRefs(block_id);
} catch(e) {
//TODO: Companion explains error
}
// add infos to exportFiles JSON
for (let ref_id in refs) {
let folderId = refs[ref_id].relationships.parent.data.id;
fileref.attributes = refs[ref_id].attributes;
fileref.related_block_id = block_id;
fileref.id = refs[ref_id].id;
// Create an empty relationships object to pick and hold selected relationships of the fileref. Because not all of
// them are necessary.
let relationships = {};
// Get terms-of-use id from relationships.
if (refs[ref_id].relationships?.['terms-of-use']?.data?.id) {
let terms = {'data' : refs[ref_id].relationships['terms-of-use'].data};
relationships['terms-of-use'] = terms;
}
// Add relationships to the fileref object if it has some values.
if (Object.keys(relationships).length > 0) {
fileref.relationships = relationships;
}
try {
await this.loadFolder(folderId);
folder = this.folderById({id: folderId});
} catch(e) {
//TODO: Companion explains error
}
if (folder) {
let folderName = 'Unnamed Folder';
if (folder?.attributes?.name) {
folderName = folder.attributes.name;
}
type: folder.attributes['folder-type']
}
} else {
fileref.folder = {
id: folderId,
name: 'Unknown',
type: 'StandardFolder'
}
}
this.exportFiles.json.push(fileref);
// prevent multiple downloads of the same file
this.exportFiles.download[refs[ref_id].id] = {
folder: folderId,
url: refs[ref_id].meta['download-url']
};
}
},
...mapActions({
loadStructuralElement: 'loadStructuralElement',
loadFileRefs: 'loadFileRefs',
loadFolder: 'loadFolder',
companionInfo: 'companionInfo',
setExportState: 'setExportState',
setExportProgress: 'setExportProgress',
loadFileRefsById: 'file-refs/loadById'
}),
watch: {
exportElementCounter(counter) {
if (this.elementCounter !== 0) {
this.setExportProgress(parseInt(counter / this.elementCounter * 100));
}
}
},