Skip to content

Commit 4d9ce9b

Browse files
Merge pull request #2489 from CanStudios/issue/2487
Move course validation to back-end for efficiency
2 parents 9038313 + c94c8f2 commit 4d9ce9b

8 files changed

Lines changed: 83 additions & 64 deletions

File tree

frontend/src/core/helpers.js

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -228,37 +228,6 @@ define(function(require){
228228
return success;
229229
},
230230

231-
// checks for at least one child object
232-
validateCourseContent: function(currentCourse, callback) {
233-
var containsAtLeastOneChild = true;
234-
var alerts = [];
235-
var iterateOverChildren = function(model, index, doneIterator) {
236-
if(!model._childTypes) {
237-
return doneIterator();
238-
}
239-
model.fetchChildren(function(currentChildren) {
240-
if (currentChildren.length > 0) {
241-
return helpers.forParallelAsync(currentChildren, iterateOverChildren, doneIterator);
242-
}
243-
containsAtLeastOneChild = false;
244-
var children = _.isArray(model._childTypes) ? model._childTypes.join('/') : model._childTypes;
245-
alerts.push(model.get('_type') + " '" + model.get('title') + "' missing " + children);
246-
doneIterator();
247-
});
248-
};
249-
// start recursion
250-
iterateOverChildren(currentCourse, null, function() {
251-
var errorMessage = "";
252-
if(alerts.length > 0) {
253-
for(var i = 0, len = alerts.length; i < len; i++) {
254-
errorMessage += "<li>" + alerts[i] + "</li>";
255-
}
256-
return callback(new Error(errorMessage));
257-
}
258-
callback(null, true);
259-
});
260-
},
261-
262231
isValidEmail: function(value) {
263232
var regEx = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
264233
return value.length > 0 && regEx.test(value);

frontend/src/modules/editor/global/views/editorView.js

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,12 @@ define(function(require) {
4444
'editorView:copy': this.addToClipboard,
4545
'editorView:copyID': this.copyIdToClipboard,
4646
'editorView:paste': this.pasteFromClipboard,
47-
'editorCommon:download': function() {
48-
this.validateProject(function(error) {
49-
this.downloadProject();
50-
});
51-
},
47+
'editorCommon:download': this.downloadProject,
5248
'editorCommon:preview': function(isForceRebuild) {
5349
var previewWindow = window.open('loading', 'preview');
54-
this.validateProject(function(error) {
55-
if(error) {
56-
return previewWindow.close();
57-
}
58-
this.previewProject(previewWindow, isForceRebuild);
59-
});
50+
this.previewProject(previewWindow, isForceRebuild);
6051
},
61-
'editorCommon:export': function() {
62-
this.validateProject(function(error) {
63-
this.exportProject(error);
64-
});
65-
}
52+
'editorCommon:export': this.exportProject
6653
});
6754
this.render();
6855
this.setupEditor();
@@ -76,15 +63,6 @@ define(function(require) {
7663
this.renderCurrentEditorView();
7764
},
7865

79-
validateProject: function(next) {
80-
helpers.validateCourseContent(this.currentCourse, _.bind(function(error) {
81-
if(error) {
82-
Origin.Notify.alert({ type: 'error', text: "There's something wrong with your course:<br/><br/>" + error });
83-
}
84-
next.call(this, error);
85-
}, this));
86-
},
87-
8866
previewProject: function(previewWindow, forceRebuild) {
8967
if(Origin.editor.isPreviewPending) {
9068
return;

plugins/output/adapt/importsource.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const database = require("../../../lib/database");
77
const filestorage = require('../../../lib/filestorage');
88
const fs = require("fs-extra");
99
const glob = require('glob');
10-
const helpers = require('./helpers');
10+
const helpers = require('./outputHelpers');
1111
const logger = require("../../../lib/logger");
1212
const mime = require('mime');
1313
const path = require("path");

plugins/output/adapt/importsourcecheck.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const configuration = require('../../../lib/configuration');
66
const Constants = require('../../../lib/outputmanager').Constants;
77
const database = require("../../../lib/database");
88
const fs = require("fs-extra");
9-
const helpers = require('./helpers');
9+
const helpers = require('./outputHelpers');
1010
const IncomingForm = require('formidable').IncomingForm;
1111
const logger = require("../../../lib/logger");
1212
const path = require("path");
Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,63 @@ function getPluginFrameworkVersionCategory(serverFrameworkVersion, pluginMetaDat
277277
});
278278
};
279279

280+
function validateCourse(data, cb) {
281+
let errors = '';
282+
let contentObjects = data.contentobject;
283+
let articles = data.article;
284+
let blocks = data.block;
285+
let components = data.component;
286+
287+
if (typeof contentObjects === 'undefined') {
288+
let courseString = app.polyglot.t('app.course');
289+
errors += app.polyglot.t('app.doesnotcontain', {
290+
type: courseString[0].toUpperCase() + courseString.slice(1),
291+
title: data.course[0].title,
292+
childType: app.polyglot.t('app.page', 0)
293+
}) + '\n';
294+
return cb(errors, false);
295+
}
296+
297+
errors += iterateThroughChildren(contentObjects, articles);
298+
errors += iterateThroughChildren(articles, blocks);
299+
errors += iterateThroughChildren(blocks, components);
300+
301+
if (errors.length !== 0) return cb(errors, false);
302+
303+
return cb(null, true);
304+
}
305+
306+
function iterateThroughChildren(parents, children) {
307+
let errors = '';
308+
if (typeof parents === 'undefined') return errors;
309+
310+
const appendError = (parentType, parentTitle, childType) => {
311+
errors += app.polyglot.t('app.doesnotcontain', {
312+
type: parentType[0].toUpperCase() + parentType.slice(1),
313+
title: parentTitle,
314+
childType: childType
315+
}) + '\n';
316+
};
317+
318+
parents.forEach(parent => {
319+
let parentType = app.polyglot.t('app.' + parent._type, 1);
320+
let childType = app.polyglot.t('app.children');
321+
322+
if (typeof children === 'undefined') {
323+
appendError(parentType, parent.title, childType);
324+
return;
325+
}
326+
327+
if (children[0] && children[0]._type) childType = app.polyglot.t('app.' + children[0]._type, 0);
328+
let found = children.find(child => JSON.stringify(child._parentId) === JSON.stringify(parent._id));
329+
330+
if (typeof found === 'undefined') {
331+
appendError(parentType, parent.title, childType);
332+
}
333+
});
334+
return errors;
335+
}
336+
280337
function ImportError(message, httpStatus) {
281338
this.message = message || "Course import failed";
282339
this.httpStatus = httpStatus || 500;
@@ -322,5 +379,6 @@ exports = module.exports = {
322379
ImportError: ImportError,
323380
PartialImportError: PartialImportError,
324381
sortContentObjects: sortContentObjects,
325-
cleanUpImport: cleanUpImport
382+
cleanUpImport: cleanUpImport,
383+
validateCourse: validateCourse
326384
};

plugins/output/adapt/publish.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const helpers = require('../../../lib/helpers');
1212
const installHelpers = require('../../../lib/installHelpers');
1313
const logger = require('../../../lib/logger');
1414
const origin = require('../../../');
15+
const outputHelpers = require('./outputHelpers');
1516
const usermanager = require('../../../lib/usermanager');
1617

1718
function publishCourse(courseId, mode, request, response, next) {
@@ -59,6 +60,16 @@ function publishCourse(courseId, mode, request, response, next) {
5960
callback(null);
6061
});
6162
},
63+
// validate the course data
64+
function(callback) {
65+
outputHelpers.validateCourse(outputJson, function(error, isValid) {
66+
if (error || !isValid) {
67+
return callback({ message: error });
68+
}
69+
70+
callback(null);
71+
});
72+
},
6273
//
6374
function(callback) {
6475
var temporaryThemeFolder = path.join(SRC_FOLDER, Constants.Folders.Theme, customPluginName);

routes/import/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var permissions = require('../../lib/permissions');
33
var server = module.exports = require('express')();
44
var usermanager = require('../../lib/usermanager');
55
var util = require('util');
6-
var helpers = require('../../plugins/output/adapt/helpers');
6+
var helpers = require('../../plugins/output/adapt/outputHelpers');
77

88
// stop any auto permissions checks
99
permissions.ignoreRoute(/^\/import\/?.*$/);

routes/lang/en.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@
165165
"app.preview": "Preview course",
166166
"app.previewing": "Previewing...",
167167
"app.forcerebuild": "Force rebuild",
168+
"app.doesnotcontain": "%{type} '%{title}' does not contain any %{childType}",
169+
"app.children": "children",
168170
"app.editprofiletitle": "User profile",
169171
"app.editprofileinformation": "You can view and modify your user information below.",
170172
"app.firstname": "First name",
@@ -386,11 +388,12 @@
386388
"app.editormenusettings": "Menu picker",
387389
"app.editorextensions": "Manage extensions",
388390
"app.editing": "Editing %{type}: %{text}",
391+
"app.course": "course",
389392
"app.menu": "menu",
390-
"app.page": "page",
391-
"app.article": "article",
392-
"app.block": "block",
393-
"app.component": "component",
393+
"app.page": "page |||| pages",
394+
"app.article": "article |||| articles",
395+
"app.block": "block |||| blocks",
396+
"app.component": "component |||| components",
394397
"app.addedDefault": "Add to new courses by default?",
395398
"app.errorloadconfig": "Failed to load configuration settings for %{course}",
396399
"app.errorloadfiles": "Failed to load content files",

0 commit comments

Comments
 (0)