/*
Copyright (C) 2016
Developed at University of Toronto
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const uuidv1 = require('uuid/v1');
const date = require('moment');
const errorFile = require('./errors');
// <Global Constants> ------------------------------------------
// Common errors
const errors = errorFile.errors;
const defaultError = errorFile.defaultError;
exports.errors = errors;
exports.defaultError = defaultError;
// common path shared across the backend
const vfsTree = Object.freeze({
ROOT : __dirname + '/..',
HOME : __dirname + '/../FileSystem',
USERS : __dirname + '/../FileSystem/Users',
QUESTIONS : __dirname + '/../FileSystem/Questions'
});
exports.vfsTree = vfsTree;
// common permission on files
const vfsPermission = Object.freeze({
PUBLIC : 'public',
OWNER : 'owner',
SYSTEM : 'system'
});
exports.vfsPermission = vfsPermission;
// common item types
const vfsTypes = Object.freeze({
FILE : 'file',
DIRECTORY : 'directory'
});
exports.vfsTypes = vfsTypes;
// all user types
const userTypes = Object.freeze({
ADMIN : 0,
STUDENT : 1
});
exports.userTypes = userTypes;
// all types of visibility status for the dicussionboard
const discussionboardVisibility = Object.freeze({
NONE : 'NONE',
ANSWERED : 'ANSWERED',
ALL : 'ALL'
});
exports.discussionboardVisibility = discussionboardVisibility;
// all question types
const questionTypes = Object.freeze({
MULTIPLECHOICE : {name: 'Multiple Choice', value: 'mc', template: 'question_types/mc-answer', icon: 'format_list_bulleted'},
REGULAR : {name: 'Regular Question', value: 're', template: 'question_types/regex-answer', icon: 'font_download'},
TRUEFALSE : {name: 'True and False', value: 'tf', template: 'question_types/tf-answer', icon: 'check_circle'},
MATCHING : {name: 'Matching', value: 'matching', template: 'question_types/matching-answer', icon: 'dashboard'},
CHOOSEALL : {name: 'Choose All That Apply', value: 'ca', template: 'question_types/chooseAll-answer', icon: 'format_list_bulleted'},
ORDERING : {name: 'Order the List', value: 'ordering', template: 'question_types/ordering-answer', icon: 'format_list_bulleted'}
});
exports.questionTypes = questionTypes;
/* the field to sort by */
const sortTypes = Object.freeze({
SORT_NOSORT : 0x0,
SORT_DEFAULT : 0x1,
SORT_RANDOM : 0x2,
SORT_TOPIC : 0x4,
SORT_POINTS : 0x8,
QUERY_ANSWERED : 0x10,
QUERY_ANSONLY : 0x20
});
exports.sortTypes = sortTypes;
// all question attributes of any question object in the database
const questionAttributes = Object.freeze({
DEFAULT: {
topic : {type:'[object String]'},
title : {type:'[object String]'},
text : {type:'[object String]'},
hint : {type:'[object String]'},
minpoints : {type:'[object Number]'},
maxpoints : {type:'[object Number]'},
visible : {type:'[object Boolean]'},
type : {type:'[object String]'}
},
SERVER: {
_id : {type:'[object String]'},
correctAttempts : {type:'[object Array]'},
wrongAttempts : {type:'[object Array]'},
totalAttempts : {type:'[object Array]'},
correctAttemptsCount : {type:'[object Number]'},
wrongAttemptsCount : {type:'[object Number]'},
totalAttemptsCount : {type:'[object Number]'},
ctime : {type:'[object String]'},
mtime : {type:'[object String]'},
ratings : {type:'[object Array]'},
userSubmissionTime : {type:'[object Array]'},
deleted : {type:'[object Boolean]'}
},
REGULAR: {
answer : {type:'[object String]'}
},
MULTIPLECHOICE: {
choices : {type:'[object Array]'},
answer : {type:'[object String]'}
},
TRUEFALSE: {
answer : {type:'[object String]'}
},
MATCHING: {
leftSide : {type:'[object Array]'},
rightSide : {type:'[object Array]'}
},
CHOOSEALL: {
choices : {type:'[object Array]'},
answer : {type:'[object Array]'}
},
ORDERING: {
answer : {type:'[object Array]'}
},
DATATYPES: {
Array : {type:'[object Array]'},
String : {type:'[object String]'},
Number : {type:'[object Number]'},
Boolean : {type:'[object Boolean]'},
Object : {type:'[object Object]'}
}
});
exports.questionAttributes = questionAttributes;
// </Global Constants> ------------------------------------------
// <Global Function> --------------------------------------------
/**
* return an object of error code and message
*
* @param {number} errorCode
* @return {object}
*/
var getError = function(errorCode) {
return {
code: errorCode,
message: errors[errorCode] || defaultError
}
}
exports.getError = getError;
/**
* shuffle the given list and return the result as a new list
*
* @return {array}
*/
var randomizeList = function (data) {
var oldIndex, newIndex, tempHolder;
for (oldIndex = data.length-1; oldIndex > 0; oldIndex--) {
newIndex = Math.floor(Math.random() * (oldIndex + 1));
tempHolder = data[oldIndex];
data[oldIndex] = data[newIndex];
data[newIndex] = tempHolder;
}
return data;
};
exports.randomizeList = randomizeList;
/**
* given a list of JSON objects that have Id as one of their feilds, return a list of Ids
*
* @return {array}
*/
var getIdsListFromJSONList = function (JSONList, idType) {
var list = [];
for (i in JSONList) {
list.push(JSONList[i][idType]);
}
return list;
}
exports.getIdsListFromJSONList = getIdsListFromJSONList;
/**
* return a number as the sum of all numbers in a list
*
* @param {list} list
*/
var sumListOfNumbers = function (list) {
return list.reduce((x, y) => {
return parseInt(x) + parseInt(y);
});
}
exports.sumListOfNumbers = sumListOfNumbers;
/**
* check if json obejct is empty
*
* @return {boolean}
*/
var isEmptyObject = function (obj) {
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
return false;
}
}
return true;
}
exports.isEmptyObject = isEmptyObject;
/**
* return the current date
*
* @return {string}
*/
var getDate = function () {
return getDateByFormat('YYYY-MM-DD hh:mm:ss A');
}
exports.getDate = getDate;
/**
* return the current date
*
* @return {date}
*/
var getDateObject = function () {
return new Date();
}
exports.getDateObject = getDateObject;
/**
* return the current date
*
* @param {number} mins
* @param {string} format
* @return {string}
*/
var getDateFormatedMinutesAgo = function (format, mins) {
return date().subtract(mins, "minutes").format(format);
}
exports.getDateFormatedMinutesAgo = getDateFormatedMinutesAgo;
/**
* return the time in "<0> days, <0> hours, <0> minutes, <0> seconds" format
*
* @return {string}
*/
var getTime = function(time){
const date = new Date(time);
var timeString = '';
const days = date.getUTCDate()-1;
const hours = date.getUTCHours();
const minutes = date.getUTCMinutes();
const seconds = date.getUTCSeconds();
if (days){
timeString += date.getUTCDate()-1 + " days, ";
}
if (hours){
timeString += date.getUTCHours() + " hours, ";
}
if (minutes){
timeString += date.getUTCMinutes() + " minutes, ";
}
if (seconds){
timeString += date.getUTCSeconds() + " seconds";
}
return timeString;
}
exports.getTime = getTime;
/**
* return the current date with format
*
* @return {string}
*/
var getDateByFormat = function (format) {
return date().format(format);
}
exports.getDateByFormat = getDateByFormat;
/**
* get a unique Id
*
* @return {string}
*/
var getUUID = function () {
return uuidv1();
}
exports.getUUID = getUUID;
/**
* get variable type
*
* @param {*} variable
*/
var getVariableType = function (variable) {
return Object.prototype.toString.call(variable);
}
exports.getVariableType = getVariableType;
/**
* formating a string based on an array of parts of the string
*
* @return {string}
*/
var formatString = function (text, args) {
var regex = new RegExp('{-?[0-9]+}', 'g');
return text.replace(regex, function(item) {
var intVal = parseInt(item.substring(1, item.length - 1));
var replace;
if (intVal >= 0) {
replace = args[intVal];
} else if (intVal === -1) {
replace = '{';
} else if (intVal === -2) {
replace = '}';
} else {
replace = '';
}
return replace;
});
};
exports.formatString = formatString;
/**
* Returns a JSON from a list of JSONs given a key, value to search for
*
* @param {list} list
* @param {string} field
* @param {string} value
* @return {boolean}
*/
var isKeyValuePairInJsonList = function(list, field, value) {
for (var i = 0; i < list.length; i++) {
if (list[i][field] === value) {
return true;
}
}
return false;
}
exports.isKeyValuePairInJsonList = isKeyValuePairInJsonList;
// </Global Function> -----------------------------------------------