js/base/services/ModuleService.js
'use strict';
import {convertToObject} from '../Utilities';
var ModuleService = ($q, DataService, RegistrationService, LoggerService, _SF, $filter, safo, SynthError, SynthesisRESTClient) => {
var LOG = LoggerService('ModuleService');
// Cache of module data
var moduleDataCache = {};
// Return the factory
class ModuleServiceImpl {
/**
* Return the modules the user has linked with this application
*
* @returns an array of modules that are linked to the application
* [
* {
* "id": "module1",
* "name": "Course 1",
* "description": "Course 1",
* "createdDate": "20140627145828000",
* "isRegistered": true
* },
* {
* "id": "module2",
* "name": "Course 2",
* "description": "",
* "createdDate": "20141128133105000",
* "isRegistered": true
* }
* ]
*/
getLinkedModules(){
return RegistrationService.getRegistration().then((registrationData) => {
var filteredModules = [];
if(registrationData && registrationData.modules){
var modulesArray = $filter('object2Array')(registrationData.modules);
filteredModules = _.filter(modulesArray, 'registered', true);
}
return filteredModules;
});
}
/**
* Gets all the currently known modules. This include ones that that use
* is registered for or not
*/
getCurrentModules(){
return RegistrationService.getRegistration().then((registrationData) => {
if(registrationData.modules){
return $filter('object2Array')(registrationData.modules);
}
return [];
});
}
/**
* Returns an array of modules that are newly available from the
* Synthesis Server that we do not currently have knowledge of
*/
getNewModules(){
var availableModules;
const self = this;
function getCurrentlyKnownModules(synthesisModules){
availableModules = synthesisModules;
return self.getCurrentModules();
}
function findNewArray(currentModules){
// If we currently have no modules, all available morules are new
if(currentModules.length === 0){
return $q.when(availableModules);
}
var newModules = [];
_.forEach(availableModules, (availableModule) => {
// look in our current array if we have such an item
var matchedModule = _.find(currentModules, 'id', availableModule.id);
// If none matched, its a new matchedModule
if(matchedModule == null){
newModules.push(availableModule);
}
});
return $q.when(newModules);
}
return SynthesisRESTClient.getAllowedSites()
.then(getCurrentlyKnownModules)
.then(findNewArray);
}
hasNewModules(){
return this.getNewModules()
.then((newModules) => {
return newModules.length > 0;
});
}
/**
* Sets a property on the specified module
*/
setModuleProperty(moduleId, property, value){
var mergeData = { 'modules' : {}};
mergeData.modules[moduleId] = {};
mergeData.modules[moduleId][property] = value;
return RegistrationService.mergeRegistration(mergeData);
}
/**
* Returns the modules that are available that we know of, and what
* the Syntehsis Server has to offer
*
* @returns a array of modules that are linked to the application
* [{
* "id": "module1",
* "name": "Course 1",
* "description": "Course 1",
* "createdDate": "20140627145828000",
* "isRegistered": true
* },{
* "id": "module2",
* "name": "Course 2",
* "description": "",
* "createdDate": "20141128133105000",
* "isRegistered": false | undefined
* }
*]
'getAvailableModules' : function(){
var service = this;
// Calculate what the new map should look like
function calculateNewMap(newModules){
return service.getLinkedModules().then((currentModulesArray) => {
// If there are no new modules, we can return what we currently have
if(newModules.length == 0){
return currentModulesArray;
}
// Else we need to merge the new modules
var mergeMap = { modules : {}};
_.forEach(newModules, (newModule) => {
// look in our current array if we have such an item
var matchedModule = _.find(currentModulesArray, 'id', newModule.id);
if(matchedModule == null){
mergeMap.modules[newModule.id] = newModule;
}
});
return mergeNewModules(mergeMap);
});
}
// Merge the new modules that we calculated to the registration data
function mergeNewModules(newMergeData){
return RegistrationService.mergeRegistration(newMergeData).then((registrationData) => {
return $filter('object2Array')(registrationData.modules);
});
}
return this.getNewModules().then(calculateNewMap);
},
*/
/**
* Gets all the tools of linked modules. This data return will be in a similar format as:
* [{
* 'id': 'trailrunning',
* 'name': 'Trailrunning 201',
* 'description': '',
* 'createdDate': '20141128133105000',
* 'tools :
* [{
* 'defaultPage': '#tool/faq',
* 'name': 'faq',
* 'label': 'FAQs',
* 'heading': 'FAQs',
* 'icon': 'icon-sakai-help',
* 'description': '',
* 'menu': false,
* 'seq': 40
* },
* {
* 'defaultPage': '#tool/forums',
* 'name': 'forums',
* 'label': 'Discussions',
* 'heading': 'Discussions',
* 'icon': 'icon-sakai-forums',
* 'description': '',
* 'menu': false,
* 'seq': 60
* }]
* }]
*/
getAllHomeToolsSorted(){
const self = this;
function getLoopModulesPromise(availableModules){
let promise = $q.when();
let moduleTools = [];
angular.forEach(availableModules, function(module){
promise = promise.then(function(){
return self.getModuleHomeToolsSorted(module.id)
.then((tools) => {
moduleTools.push(module);
moduleTools[moduleTools.length - 1].tools = tools;
});
});
});
return promise.then(() => {
return moduleTools;
});
}
return this.getLinkedModules().then(getLoopModulesPromise);
}
/**
* Creates the default module.json file for the module
*/
createDefaultModuleFile(moduleId){
return DataService.copyFromWebToFile('base/data/module.json', 'data', `${moduleId}.json`);
}
/**
* Gets the data for the specified module ID
*/
getModuleData(moduleId){
if(moduleDataCache[moduleId] != null){
return $q.when(moduleDataCache[moduleId]);
}
else{
return DataService.getDataFile(`${moduleId}.json`).then((moduleData) => {
moduleDataCache[moduleId] = moduleData;
return moduleData;
});
}
}
/**
* Return the proper display name for a module
*/
getModuleName(moduleId){
return this.getLinkedModules().then((registrationData) => {
var theModule = _.find(registrationData, { 'id' : moduleId});
return theModule ? theModule.name : null;
});
}
/**
* Return the proper display name for a module's tool
*/
getToolName(moduleId, toolId){
return this.getModuleData(moduleId).then((moduleData) => {
// First check if we have such a field
if(moduleData && moduleData.toolDescriptions && moduleData.toolDescriptions[toolId]){
return moduleData.toolDescriptions[toolId].heading;
}
return null;
});
}
/**
* Get the home tools for a module
*/
getModuleHomeTools(moduleId){
return this.getModuleData(moduleId)
.then((moduleData) => {
var tools = moduleData.toolDescriptions;
var availableTools = $filter('object2Array')(tools);
availableTools = $filter('filter')(availableTools, {menu : true});
safo(availableTools, 'moduleId', moduleId);
return availableTools;
});
}
/**
* Get the home tools for a module sorted
*/
getModuleHomeToolsSorted(moduleId){
return this.getModuleHomeTools(moduleId)
.then(function(tools){
// TODO implement user custom sorting
return $filter('orderBy')(tools, 'seq');
});
}
/**
* Merge data to a module's data file.
*
* @param moduleId - ID of the module to merge too
* @jsonData - Data to merge. Data can be a JSON string or a JSON object
*/
mergeToModuleData(moduleId, jsonData){
return DataService.mergeDataFile(`${moduleId}.json`, jsonData).then((data) => {
moduleDataCache[moduleId] = data;
return data;
});
}
/**
* Gets the data for a tool
* @param moduleId - ID of the module in which the tool is
* @param toolname - Name of the tool to get data of
* @param isUploadData - Indication if the data is the upload data (optional, default=false)
*/
getToolData(moduleId, toolname, isUploadData){
LOG.debug('Getting data for tool : ' + moduleId + ' - ' + toolname);
var deferred = $q.defer();
DataService.getToolDataFile(moduleId, toolname, isUploadData)
.then(
// Success
function(fileEntry){
DataService.getFileAsObject(fileEntry)
.then(
// Success
function(object){
deferred.resolve(object);
}, fail);
}, fail);
function fail(error){
deferred.reject(error);
}
return deferred.promise;
}
/**
* Gets a merge of the downloaded and (still-to) upload data for a tool
*
* @param moduleId Module in which the tool is
* @param toolname Name of the tool
*/
getMergedToolData(moduleId, toolname){
var toolData, toolUploadData;
const self = this;
function getToolDataPromise(){
return self.getToolData(moduleId, toolname, true).then((data) => {
toolData = data;
});
}
function getToolUploadDataPromise(){
return self.getToolData(moduleId, toolname, false).then((data) => {
toolUploadData = data;
});
}
function getMergedDataPromise(){
var mergedData = angular.merge(toolData, toolUploadData);
return $q.when(mergedData);
}
return getToolDataPromise()
.then(getToolUploadDataPromise)
.then(getMergedDataPromise);
}
/**
* Merges data to a tool's data file.
* This will typically by used when downloading sync'd content and merge it to a file
*
* @param moduleId - Module ID in which the tool is
* @param toolname - Name of the tool to write data too
* @param jsonData - Either a JSON String, or a JSON Object representing the data to write
* @param isUploadData - Flag if the data should be merged to the upload data of the tool
* @returns A promise with the data that was merged as the parameters
*/
mergeToToolData(moduleId, toolname, jsonData, isUploadData){
var deferred = $q.defer();
this.getToolData(moduleId, toolname, isUploadData).then(
// Success
function(data){
var jsonObject = convertToObject(jsonData);
var writeObject = angular.merge(data, jsonObject);
// Write the merged data to the file
DataService.writeToolData(moduleId, toolname, writeObject, isUploadData).then(
// Success
function(){
deferred.resolve(writeObject);
},
//Fail
function (){
deferred.reject(SynthError(1004));
}
);
}
);
return deferred.promise;
}
}
return new ModuleServiceImpl();
};
ModuleService.$inject = ['$q', 'DataService', 'RegistrationService', 'LoggerService', 'SynthFail', '$filter', 'safo', 'SynthError', 'SynthesisRESTClient'];
export default ModuleService;