Source: common.js

/*
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> -----------------------------------------------