<commit_before>/**
 *      States DB in memory - Server
 *
 *      Copyright 2013-2022 bluefox <dogafox@gmail.com>
 *
 *      MIT License
 *
 */

/** @module inMemoryFileDB */

/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
'use strict';

const fs = require('fs-extra');
const path = require('path');
const tools = require('./tools.js');

// settings = {
//    change:    function (id, state) {},
//    connected: function (nameOfServer) {},
//    logger: {
//           silly: function (msg) {},
//           debug: function (msg) {},
//           info:  function (msg) {},
//           warn:  function (msg) {},
//           error: function (msg) {}
//    },
//    connection: {
//           dataDir: 'relative path'
//    },
//    auth: null, //unused
//    secure: true/false,
//    certificates: as required by createServer
//    port: 9000,
//    host: localhost
// };
//

/**
 * The parent of the class structure, which provides basic JSON storage
 * and general subscription and publish functionality
 **/
class InMemoryFileDB {
    constructor(settings) {
        this.settings = settings || {};

        this.change = this.settings.change;

        this.dataset = {};

        this.namespace = this.settings.namespace || '';
        this.lastSave = null;
        this.zlib = null;
        this.callbackSubscriptionClient = {};

        this.settings.backup = this.settings.connection.backup || {
            disabled: false, // deactivates
            files: 24, // minimum number of files
            hours: 48, // hours
            period: 120, // minutes
            path: '' // use default path
        };

        this.dataDir = this.settings.connection.dataDir || tools.getDefaultDataDir();
        if (!path.isAbsolute(this.dataDir)) {
            this.dataDir = path.normalize(path.join(tools.getControllerDir(), this.dataDir));
        }
        this.dataDir = this.dataDir.replace(/\\/g, '/');

        const fileName = this.settings.jsonlDB ? this.settings.jsonlDB.fileName : this.settings.fileDB.fileName;
        this.datasetName = path.join(this.dataDir, fileName);
        const parts = path.dirname(this.datasetName);
        fs.ensureDirSync(parts);

        this.stateTimer = null;

        this.backupDir = this.settings.backup.path || path.join(this.dataDir, this.settings.fileDB.backupDirName);

        if (!this.settings.backup.disabled) {
            this.initBackupDir();
        }

        this.log = tools.getLogger(this.settings.logger);

        this.log.debug(`${this.namespace} Data File: ${this.datasetName}`);
    }

    /** @returns {Promise<void>} */
    async open() {
        // load values from file
        this.dataset = await this.loadDataset(this.datasetName);
    }

    /**
     * Loads a dataset file
     *
     * @param datasetName {string} Filename of the file to load
     * @returns {Promise<Record<string, any>>} read data, normally as object
     */
    async loadDatasetFile(datasetName) {
        if (!(await fs.pathExists(datasetName))) {
            throw new Error(`Database file ${datasetName} does not exists.`);
        }
        return fs.readJSON(datasetName);
    }

    /**
     * Loads the dataset including pot. Fallback handling
     *
     * @param datasetName {string} Filename of the file to load
     * @returns {Promise<Record<string, any>>} dataset read as object
     */
    async loadDataset(datasetName) {
        let ret = {};
        try {
            ret = await this.loadDatasetFile(datasetName);

            // loading worked, make sure that "bak" File is not broken
            try {
                await fs.readJSON(`${datasetName}.bak`);
            } catch (e) {
                this.log.info(
                    `${this.namespace} Rewrite bak file, because error on verify ${datasetName}.bak: ${e.message}`
                );
                try {
                    const jsonString = JSON.stringify(ret);
                    await fs.writeFile(`${datasetName}.bak`, jsonString);
                } catch (e) {
                    this.log.error(`${this.namespace} Cannot save ${datasetName}.bak: ${e.message}`);
                }
            }
        } catch (err) {
            this.log.error(`${this.namespace} Cannot load ${datasetName}: ${err.message}. We try last Backup!`);

            try {
                ret = await this.loadDatasetFile(`${datasetName}.bak`);

                // it worked, lets overwrite old file and store the broken one for pot. forensic check
                try {
                    if (await fs.pathExists(datasetName)) {
                        try {
                            await fs.move(datasetName, `${datasetName}.broken`, { overwrite: true });
                        } catch (e) {
                            this.log.error(
                                `${this.namespace} Cannot copy the broken file ${datasetName} to ${datasetName}.broken ${e.message}`
                            );
                        }
                        try {
                            await fs.writeFile(datasetName, JSON.stringify(ret));
                        } catch (e) {
                            this.log.error(
                                `${this.namespace} Cannot restore backup file as new main ${datasetName}: ${e.message}`
                            );
                        }
                    }
                } catch {
                    // ignore, file does not exist
                }
            } catch (err) {
                this.log.error(
                    `${this.namespace} Cannot load ${datasetName}.bak: ${err.message}. Continue with empty dataset!`
                );
                this.log.error(
                    `${this.namespace} If this is no Migration or initial start please restore the last backup from ${this.backupDir}`
                );
            }
        }
        return ret;
    }

    initBackupDir() {
        this.zlib = this.zlib || require('zlib');
        // Interval in minutes => to milliseconds
        this.settings.backup.period =
            this.settings.backup.period === undefined ? 120 : parseInt(this.settings.backup.period);
        if (isNaN(this.settings.backup.period)) {
            this.settings.backup.period = 120;
        }
        // Node.js timeouts overflow after roughly 24 days, defaulting to 1 millisecond, which causes chaos.
        // If a user configured the backup this way, we use our default of 120 minutes instead.
        const maxTimeoutMinutes = Math.floor((2 ** 31 - 1) / 60000);
        if (this.settings.backup.period > maxTimeoutMinutes) {
            this.settings.backup.period = 120;
            this.log.warn(
                `${this.namespace} Configured backup period ${this.settings.backup.period} is larger than the supported maximum of ${maxTimeoutMinutes} minutes. Defaulting to 120 minutes.`
            );
        }
        this.settings.backup.period *= 60000;

        this.settings.backup.files =
            this.settings.backup.files === undefined ? 24 : parseInt(this.settings.backup.files);
        if (isNaN(this.settings.backup.files)) {
            this.settings.backup.files = 24;
        }

        this.settings.backup.hours =
            this.settings.backup.hours === undefined ? 48 : parseInt(this.settings.backup.hours);
        if (isNaN(this.settings.backup.hours)) {
            this.settings.backup.hours = 48;
        }
        // Create backup directory
        fs.ensureDirSync(this.backupDir);
    }

    handleSubscribe(client, type, pattern, options, cb) {
        if (typeof options === 'function') {
            cb = options;
            options = undefined;
        }
        client._subscribe = client._subscribe || {};
        client._subscribe[type] = client._subscribe[type] || [];

        const s = client._subscribe[type];

        if (pattern instanceof Array) {
            pattern.forEach(pattern => {
                if (s.find(sub => sub.pattern === pattern)) {
                    return;
                }

                s.push({ pattern: pattern, regex: new RegExp(tools.pattern2RegEx(pattern)), options: options });
            });
        } else {
            if (!s.find(sub => sub.pattern === pattern)) {
                s.push({ pattern: pattern, regex: new RegExp(tools.pattern2RegEx(pattern)), options: options });
            }
        }
        typeof cb === 'function' && cb();
    }

    handleUnsubscribe(client, type, pattern, cb) {
        if (!client._subscribe || !client._subscribe[type]) {
            if (typeof cb === 'function') {
                cb();
            }
            return;
        }
        const s = client._subscribe[type];
        if (pattern instanceof Array) {
            pattern.forEach(pattern => {
                const index = s.findIndex(sub => sub.pattern === pattern);
                if (index > -1) {
                    s.splice(index, 1);
                }
            });
        } else {
            const index = s.findIndex(sub => sub.pattern === pattern);
            if (index > -1) {
                s.splice(index, 1);
                return typeof cb === 'function' && cb();
            }
        }
        typeof cb === 'function' && cb();
    }

    /** @returns {number} */
    publishToClients(_client, _type, _id, _obj) {
        throw new Error('no communication handling implemented');
    }

    deleteOldBackupFiles(baseFilename) {
        // delete files only if settings.backupNumber is not 0
        let files = fs.readdirSync(this.backupDir);
        files.sort();
        const limit = Date.now() - this.settings.backup.hours * 3600000;

        files = files.filter(f => f.endsWith(baseFilename + '.gz'));

        while (files.length > this.settings.backup.files) {
            const file = files.shift();
            if (!file) {
                continue;
            }
            // extract time
            const ms = new Date(`${file.substring(0, 10)} ${file.substring(11, 16).replace('-', ':')}:00`).getTime();
            if (limit > ms) {
                try {
                    fs.unlinkSync(path.join(this.backupDir, file));
                } catch (e) {
                    this.log.error(
                        `${this.namespace} Cannot delete file "${path.join(this.backupDir, file)}: ${e.message}`
                    );
                }
            }
        }
    }

    getTimeStr(date) {
        const dateObj = new Date(date);

        let text = dateObj.getFullYear().toString() + '-';
        let v = dateObj.getMonth() + 1;
        if (v < 10) {
            text += '0';
        }
        text += v.toString() + '-';

        v = dateObj.getDate();
        if (v < 10) {
            text += '0';
        }
        text += v.toString() + '_';

        v = dateObj.getHours();
        if (v < 10) {
            text += '0';
        }
        text += v.toString() + '-';

        v = dateObj.getMinutes();
        if (v < 10) {
            text += '0';
        }
        text += v.toString();

        return text;
    }

    /**
     * Handle saving the dataset incl. backups
     */
    async saveState() {
        try {
            const jsonString = await this.saveDataset();

            if (!this.settings.backup.disabled && jsonString) {
                this.saveBackup(jsonString);
            }
        } finally {
            if (this.stateTimer) {
                clearTimeout(this.stateTimer);
                this.stateTimer = null;
            }
        }
    }

    /**
     * Saves the dataset into File incl. handling of a fallback backup file
     *
     * @returns {Promise<string>} JSON string of the complete dataset to also be stored into a compressed backup file
     */
    async saveDataset() {
        const jsonString = JSON.stringify(this.dataset);

        try {
            await fs.writeFile(`${this.datasetName}.new`, jsonString);
        } catch (e) {
            this.log.error(`${this.namespace} Cannot save Dataset to ${this.datasetName}.new: ${e.message}`);
            return jsonString;
        }

        let bakOk = true;
        try {
            if (await fs.pathExists(this.datasetName)) {
                try {
                    await fs.move(this.datasetName, `${this.datasetName}.bak`, { overwrite: true });
                } catch (e) {
                    bakOk = false;
                    this.log.error(`${this.namespace} Cannot backup file ${this.datasetName}.bak: ${e.message}`);
                }
            } else {
                bakOk = false;
            }
        } catch {
            bakOk = false;
            // ignore, file does not exist
        }

        try {
            await fs.move(`${this.datasetName}.new`, this.datasetName, { overwrite: true });
        } catch (e) {
            this.log.error(
                `${this.namespace} Cannot move ${this.datasetName}.new to ${this.datasetName}: ${e.message}. Try direct write as fallback`
            );
            try {
                await fs.writeFile(this.datasetName, jsonString);
            } catch (e) {
                this.log.error(`${this.namespace} Cannot directly write Dataset to ${this.datasetName}: ${e.message}`);
                return jsonString;
            }
        }

        if (!bakOk) {
            // it seems the bak File is not successfully there, write current content again
            try {
                await fs.writeFile(`${this.datasetName}.bak`, jsonString);
            } catch (e) {
                this.log.error(`${this.namespace} Cannot save ${this.datasetName}.bak: ${e.message}`);
            }
        }

        return jsonString;
    }

    /**
     * Stores a compressed backup of the DB in definable intervals
     *
     * @param jsonString {string} JSON string of the complete dataset to also be stored into a compressed backup file
     */
    saveBackup(jsonString) {
        // save files for the last x hours
        const now = Date.now();

        // makes backups only if settings.backupInterval is not 0
        if (this.settings.backup.period && (!this.lastSave || now - this.lastSave > this.settings.backup.period)) {
            this.lastSave = now;
            const backFileName = path.join(
                this.backupDir,
                this.getTimeStr(now) + '_' + this.settings.fileDB.fileName + '.gz'
            );

            try {
                if (!fs.existsSync(backFileName)) {
                    this.zlib = this.zlib || require('zlib');
                    const output = fs.createWriteStream(backFileName);
                    output.on('error', err => {
                        this.log.error(`${this.namespace} Cannot save ${this.datasetName}: ${err}`);
                    });
                    const compress = this.zlib.createGzip();
                    /* The following line will pipe everything written into compress to the file stream */
                    compress.pipe(output);
                    /* Since we're piped through the file stream, the following line will do:
                       'Hello World!'->gzip compression->file which is the desired effect */
                    compress.write(jsonString);
                    compress.end();

                    // analyse older files
                    this.deleteOldBackupFiles(this.settings.fileDB.fileName);
                }
            } catch (e) {
                this.log.error(`${this.namespace} Cannot save backup ${backFileName}: ${e.message}`);
            }
        }
    }

    getStatus() {
        return { type: 'file', server: true };
    }

    /** @returns {object} */
    getClients() {
        return {};
    }

    publishAll(type, id, obj) {
        if (id === undefined) {
            this.log.error(`${this.namespace} Can not publish empty ID`);
            return 0;
        }

        const clients = this.getClients();
        let publishCount = 0;

        if (clients && typeof clients === 'object') {
            for (const i of Object.keys(clients)) {
                publishCount += this.publishToClients(clients[i], type, id, obj);
            }
        }

        // local subscriptions
        if (
            this.change &&
            this.callbackSubscriptionClient._subscribe &&
            this.callbackSubscriptionClient._subscribe[type]
        ) {
            for (let j = 0; j < this.callbackSubscriptionClient._subscribe[type].length; j++) {
                if (this.callbackSubscriptionClient._subscribe[type][j].regex.test(id)) {
                    setImmediate(() => this.change(id, obj));
                    break;
                }
            }
        }
        return publishCount;
    }

    // Destructor of the class. Called by shutting down.
    async destroy() {
        if (this.stateTimer) {
            clearTimeout(this.stateTimer);
            await this.saveState();
        }
    }
}

module.exports = InMemoryFileDB;
<commit_msg>init logger before usage (#1847)<commit_after>/**
 *      States DB in memory - Server
 *
 *      Copyright 2013-2022 bluefox <dogafox@gmail.com>
 *
 *      MIT License
 *
 */

/** @module inMemoryFileDB */

/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
'use strict';

const fs = require('fs-extra');
const path = require('path');
const tools = require('./tools.js');

// settings = {
//    change:    function (id, state) {},
//    connected: function (nameOfServer) {},
//    logger: {
//           silly: function (msg) {},
//           debug: function (msg) {},
//           info:  function (msg) {},
//           warn:  function (msg) {},
//           error: function (msg) {}
//    },
//    connection: {
//           dataDir: 'relative path'
//    },
//    auth: null, //unused
//    secure: true/false,
//    certificates: as required by createServer
//    port: 9000,
//    host: localhost
// };
//

/**
 * The parent of the class structure, which provides basic JSON storage
 * and general subscription and publish functionality
 **/
class InMemoryFileDB {
    constructor(settings) {
        this.settings = settings || {};

        this.change = this.settings.change;

        this.dataset = {};

        this.namespace = this.settings.namespace || '';
        this.lastSave = null;
        this.zlib = null;
        this.callbackSubscriptionClient = {};

        this.settings.backup = this.settings.connection.backup || {
            disabled: false, // deactivates
            files: 24, // minimum number of files
            hours: 48, // hours
            period: 120, // minutes
            path: '' // use default path
        };

        this.dataDir = this.settings.connection.dataDir || tools.getDefaultDataDir();
        if (!path.isAbsolute(this.dataDir)) {
            this.dataDir = path.normalize(path.join(tools.getControllerDir(), this.dataDir));
        }
        this.dataDir = this.dataDir.replace(/\\/g, '/');

        const fileName = this.settings.jsonlDB ? this.settings.jsonlDB.fileName : this.settings.fileDB.fileName;
        this.datasetName = path.join(this.dataDir, fileName);
        const parts = path.dirname(this.datasetName);
        fs.ensureDirSync(parts);

        this.stateTimer = null;

        this.backupDir = this.settings.backup.path || path.join(this.dataDir, this.settings.fileDB.backupDirName);

        this.log = tools.getLogger(this.settings.logger);

        if (!this.settings.backup.disabled) {
            this.initBackupDir();
        }

        this.log.debug(`${this.namespace} Data File: ${this.datasetName}`);
    }

    /** @returns {Promise<void>} */
    async open() {
        // load values from file
        this.dataset = await this.loadDataset(this.datasetName);
    }

    /**
     * Loads a dataset file
     *
     * @param datasetName {string} Filename of the file to load
     * @returns {Promise<Record<string, any>>} read data, normally as object
     */
    async loadDatasetFile(datasetName) {
        if (!(await fs.pathExists(datasetName))) {
            throw new Error(`Database file ${datasetName} does not exists.`);
        }
        return fs.readJSON(datasetName);
    }

    /**
     * Loads the dataset including pot. Fallback handling
     *
     * @param datasetName {string} Filename of the file to load
     * @returns {Promise<Record<string, any>>} dataset read as object
     */
    async loadDataset(datasetName) {
        let ret = {};
        try {
            ret = await this.loadDatasetFile(datasetName);

            // loading worked, make sure that "bak" File is not broken
            try {
                await fs.readJSON(`${datasetName}.bak`);
            } catch (e) {
                this.log.info(
                    `${this.namespace} Rewrite bak file, because error on verify ${datasetName}.bak: ${e.message}`
                );
                try {
                    const jsonString = JSON.stringify(ret);
                    await fs.writeFile(`${datasetName}.bak`, jsonString);
                } catch (e) {
                    this.log.error(`${this.namespace} Cannot save ${datasetName}.bak: ${e.message}`);
                }
            }
        } catch (err) {
            this.log.error(`${this.namespace} Cannot load ${datasetName}: ${err.message}. We try last Backup!`);

            try {
                ret = await this.loadDatasetFile(`${datasetName}.bak`);

                // it worked, lets overwrite old file and store the broken one for pot. forensic check
                try {
                    if (await fs.pathExists(datasetName)) {
                        try {
                            await fs.move(datasetName, `${datasetName}.broken`, { overwrite: true });
                        } catch (e) {
                            this.log.error(
                                `${this.namespace} Cannot copy the broken file ${datasetName} to ${datasetName}.broken ${e.message}`
                            );
                        }
                        try {
                            await fs.writeFile(datasetName, JSON.stringify(ret));
                        } catch (e) {
                            this.log.error(
                                `${this.namespace} Cannot restore backup file as new main ${datasetName}: ${e.message}`
                            );
                        }
                    }
                } catch {
                    // ignore, file does not exist
                }
            } catch (err) {
                this.log.error(
                    `${this.namespace} Cannot load ${datasetName}.bak: ${err.message}. Continue with empty dataset!`
                );
                this.log.error(
                    `${this.namespace} If this is no Migration or initial start please restore the last backup from ${this.backupDir}`
                );
            }
        }
        return ret;
    }

    initBackupDir() {
        this.zlib = this.zlib || require('zlib');
        // Interval in minutes => to milliseconds
        this.settings.backup.period =
            this.settings.backup.period === undefined ? 120 : parseInt(this.settings.backup.period);
        if (isNaN(this.settings.backup.period)) {
            this.settings.backup.period = 120;
        }
        // Node.js timeouts overflow after roughly 24 days, defaulting to 1 millisecond, which causes chaos.
        // If a user configured the backup this way, we use our default of 120 minutes instead.
        const maxTimeoutMinutes = Math.floor((2 ** 31 - 1) / 60000);
        if (this.settings.backup.period > maxTimeoutMinutes) {
            this.settings.backup.period = 120;
            this.log.warn(
                `${this.namespace} Configured backup period ${this.settings.backup.period} is larger than the supported maximum of ${maxTimeoutMinutes} minutes. Defaulting to 120 minutes.`
            );
        }
        this.settings.backup.period *= 60000;

        this.settings.backup.files =
            this.settings.backup.files === undefined ? 24 : parseInt(this.settings.backup.files);
        if (isNaN(this.settings.backup.files)) {
            this.settings.backup.files = 24;
        }

        this.settings.backup.hours =
            this.settings.backup.hours === undefined ? 48 : parseInt(this.settings.backup.hours);
        if (isNaN(this.settings.backup.hours)) {
            this.settings.backup.hours = 48;
        }
        // Create backup directory
        fs.ensureDirSync(this.backupDir);
    }

    handleSubscribe(client, type, pattern, options, cb) {
        if (typeof options === 'function') {
            cb = options;
            options = undefined;
        }
        client._subscribe = client._subscribe || {};
        client._subscribe[type] = client._subscribe[type] || [];

        const s = client._subscribe[type];

        if (pattern instanceof Array) {
            pattern.forEach(pattern => {
                if (s.find(sub => sub.pattern === pattern)) {
                    return;
                }

                s.push({ pattern: pattern, regex: new RegExp(tools.pattern2RegEx(pattern)), options: options });
            });
        } else {
            if (!s.find(sub => sub.pattern === pattern)) {
                s.push({ pattern: pattern, regex: new RegExp(tools.pattern2RegEx(pattern)), options: options });
            }
        }
        typeof cb === 'function' && cb();
    }

    handleUnsubscribe(client, type, pattern, cb) {
        if (!client._subscribe || !client._subscribe[type]) {
            if (typeof cb === 'function') {
                cb();
            }
            return;
        }
        const s = client._subscribe[type];
        if (pattern instanceof Array) {
            pattern.forEach(pattern => {
                const index = s.findIndex(sub => sub.pattern === pattern);
                if (index > -1) {
                    s.splice(index, 1);
                }
            });
        } else {
            const index = s.findIndex(sub => sub.pattern === pattern);
            if (index > -1) {
                s.splice(index, 1);
                return typeof cb === 'function' && cb();
            }
        }
        typeof cb === 'function' && cb();
    }

    /** @returns {number} */
    publishToClients(_client, _type, _id, _obj) {
        throw new Error('no communication handling implemented');
    }

    deleteOldBackupFiles(baseFilename) {
        // delete files only if settings.backupNumber is not 0
        let files = fs.readdirSync(this.backupDir);
        files.sort();
        const limit = Date.now() - this.settings.backup.hours * 3600000;

        files = files.filter(f => f.endsWith(baseFilename + '.gz'));

        while (files.length > this.settings.backup.files) {
            const file = files.shift();
            if (!file) {
                continue;
            }
            // extract time
            const ms = new Date(`${file.substring(0, 10)} ${file.substring(11, 16).replace('-', ':')}:00`).getTime();
            if (limit > ms) {
                try {
                    fs.unlinkSync(path.join(this.backupDir, file));
                } catch (e) {
                    this.log.error(
                        `${this.namespace} Cannot delete file "${path.join(this.backupDir, file)}: ${e.message}`
                    );
                }
            }
        }
    }

    getTimeStr(date) {
        const dateObj = new Date(date);

        let text = dateObj.getFullYear().toString() + '-';
        let v = dateObj.getMonth() + 1;
        if (v < 10) {
            text += '0';
        }
        text += v.toString() + '-';

        v = dateObj.getDate();
        if (v < 10) {
            text += '0';
        }
        text += v.toString() + '_';

        v = dateObj.getHours();
        if (v < 10) {
            text += '0';
        }
        text += v.toString() + '-';

        v = dateObj.getMinutes();
        if (v < 10) {
            text += '0';
        }
        text += v.toString();

        return text;
    }

    /**
     * Handle saving the dataset incl. backups
     */
    async saveState() {
        try {
            const jsonString = await this.saveDataset();

            if (!this.settings.backup.disabled && jsonString) {
                this.saveBackup(jsonString);
            }
        } finally {
            if (this.stateTimer) {
                clearTimeout(this.stateTimer);
                this.stateTimer = null;
            }
        }
    }

    /**
     * Saves the dataset into File incl. handling of a fallback backup file
     *
     * @returns {Promise<string>} JSON string of the complete dataset to also be stored into a compressed backup file
     */
    async saveDataset() {
        const jsonString = JSON.stringify(this.dataset);

        try {
            await fs.writeFile(`${this.datasetName}.new`, jsonString);
        } catch (e) {
            this.log.error(`${this.namespace} Cannot save Dataset to ${this.datasetName}.new: ${e.message}`);
            return jsonString;
        }

        let bakOk = true;
        try {
            if (await fs.pathExists(this.datasetName)) {
                try {
                    await fs.move(this.datasetName, `${this.datasetName}.bak`, { overwrite: true });
                } catch (e) {
                    bakOk = false;
                    this.log.error(`${this.namespace} Cannot backup file ${this.datasetName}.bak: ${e.message}`);
                }
            } else {
                bakOk = false;
            }
        } catch {
            bakOk = false;
            // ignore, file does not exist
        }

        try {
            await fs.move(`${this.datasetName}.new`, this.datasetName, { overwrite: true });
        } catch (e) {
            this.log.error(
                `${this.namespace} Cannot move ${this.datasetName}.new to ${this.datasetName}: ${e.message}. Try direct write as fallback`
            );
            try {
                await fs.writeFile(this.datasetName, jsonString);
            } catch (e) {
                this.log.error(`${this.namespace} Cannot directly write Dataset to ${this.datasetName}: ${e.message}`);
                return jsonString;
            }
        }

        if (!bakOk) {
            // it seems the bak File is not successfully there, write current content again
            try {
                await fs.writeFile(`${this.datasetName}.bak`, jsonString);
            } catch (e) {
                this.log.error(`${this.namespace} Cannot save ${this.datasetName}.bak: ${e.message}`);
            }
        }

        return jsonString;
    }

    /**
     * Stores a compressed backup of the DB in definable intervals
     *
     * @param jsonString {string} JSON string of the complete dataset to also be stored into a compressed backup file
     */
    saveBackup(jsonString) {
        // save files for the last x hours
        const now = Date.now();

        // makes backups only if settings.backupInterval is not 0
        if (this.settings.backup.period && (!this.lastSave || now - this.lastSave > this.settings.backup.period)) {
            this.lastSave = now;
            const backFileName = path.join(
                this.backupDir,
                this.getTimeStr(now) + '_' + this.settings.fileDB.fileName + '.gz'
            );

            try {
                if (!fs.existsSync(backFileName)) {
                    this.zlib = this.zlib || require('zlib');
                    const output = fs.createWriteStream(backFileName);
                    output.on('error', err => {
                        this.log.error(`${this.namespace} Cannot save ${this.datasetName}: ${err}`);
                    });
                    const compress = this.zlib.createGzip();
                    /* The following line will pipe everything written into compress to the file stream */
                    compress.pipe(output);
                    /* Since we're piped through the file stream, the following line will do:
                       'Hello World!'->gzip compression->file which is the desired effect */
                    compress.write(jsonString);
                    compress.end();

                    // analyse older files
                    this.deleteOldBackupFiles(this.settings.fileDB.fileName);
                }
            } catch (e) {
                this.log.error(`${this.namespace} Cannot save backup ${backFileName}: ${e.message}`);
            }
        }
    }

    getStatus() {
        return { type: 'file', server: true };
    }

    /** @returns {object} */
    getClients() {
        return {};
    }

    publishAll(type, id, obj) {
        if (id === undefined) {
            this.log.error(`${this.namespace} Can not publish empty ID`);
            return 0;
        }

        const clients = this.getClients();
        let publishCount = 0;

        if (clients && typeof clients === 'object') {
            for (const i of Object.keys(clients)) {
                publishCount += this.publishToClients(clients[i], type, id, obj);
            }
        }

        // local subscriptions
        if (
            this.change &&
            this.callbackSubscriptionClient._subscribe &&
            this.callbackSubscriptionClient._subscribe[type]
        ) {
            for (let j = 0; j < this.callbackSubscriptionClient._subscribe[type].length; j++) {
                if (this.callbackSubscriptionClient._subscribe[type][j].regex.test(id)) {
                    setImmediate(() => this.change(id, obj));
                    break;
                }
            }
        }
        return publishCount;
    }

    // Destructor of the class. Called by shutting down.
    async destroy() {
        if (this.stateTimer) {
            clearTimeout(this.stateTimer);
            await this.saveState();
        }
    }
}

module.exports = InMemoryFileDB;
<|endoftext|>


<commit_before>/** Turtle example for SoraMame.Block
	Copyright 2015 Yutaka Kachi under MIT License

	Modfied from HTML5 canvas turtle graphics
    Copyright 2012 Hannes Hirzel under CC by 3.0
	http://cnx.org/contents/85310cba-5bbc-4f1d-b437-778a1aef9d02@2/Turtle_graphics_with_the_HTML5
 */

 (function() {

	// JavaScript statements
	// =====================================================================================
	var turtle = {
		x: 0,
		y: 0,
		angleInRadians: 0,
		penDown: false,
		penColor: "#000000",
		lineWidth: 2
	};

	turtle.color = {
		black: "#000000",
		gray: "#808080",
		lightgray: "#C0C0C0",
		red: "#ff0000",
		green: "#00ff00",
		blue: "#0000ff",
		yellow: "#ffff00",
		fuchsia: "#ff00ff",
		aqua: "#00ffff"
	};

	var canvas = document.getElementById('myDrawing');

	if (canvas && canvas.getContext) { // does the browser support 'canvas'?
		turtle.ct = canvas.getContext("2d"); // get drawing context
	} else {
		alert('You need a browser which supports the HTML5 canvas!');
	}

	// =====================================================================================

	turtle.logPenStatus = function () {
		console.log('x=' + this.x + "; y=" + this.y + '; angle = ' + this.angle + '; penDown = ' + this.penDown);
	};

	turtle.forward = function (length) {
		// console.log('forward(' + length + ')');
		// this.logPenStatus();
		var x0 = this.x,
			y0 = this.y;
		this.x += length * Math.sin(this.angleInRadians);
		this.y += length * Math.cos(this.angleInRadians);
		if (this.ct) {
			if (this.penDown) {
				//this.logPenStatus();
				this.ct.beginPath();
				this.ct.lineWidth = this.lineWidth;
				this.ct.strokeStyle = this.penColor;
				this.ct.moveTo(x0, y0);
				this.ct.lineTo(this.x, this.y);
				this.ct.stroke();
			}
		} else {
			this.ct.moveTo(this.x, this.y);
		}
		return this;
	};

	turtle.backward = function (length) {
		this.forward(-length);
		return this;
	};

	turtle.left = function (angleInDegrees) {
		// console.log('left(' + angleInDegrees + ')');
		// A complete circle, 360o, is equivalent to 2 radians
		// angleInDegrees is an angle measure in degrees
		this.angleInRadians += angleInDegrees * Math.PI / 180.0;
		return this;
	};

	turtle.right = function (angleInDegrees) {
		this.left(-angleInDegrees);
		return this;
	};

	turtle.angle = function () {
		// the turtle status is hold in this.angleInRadians;
		// degrees are often more convenient for the display
		return this.angleInRadians * 180.0 / Math.PI;
	};

	turtle.clear = function () {
		// clear CANVAS
		this.ct.clearRect(0, 0, canvas.width, canvas.height);
	};

	turtle.mark = function () {
		// drawing turtle symbol.
		var path = 5;
		var angle2 = this.angleInRadians + Math.PI / 3;
		var angle3 = this.angleInRadians - Math.PI / 3;
		var x0 = this.x,
			y0 = this.y,
			x1 = x0 + path * 1.5 * Math.sin(this.angleInRadians),
			y1 = y0 + path * 1.5 * Math.cos(this.angleInRadians);

		this.ct.fillStyle = turtle.color.gray;
		this.ct.beginPath();
		this.ct.arc(x0, y0, path, 0, Math.PI*2, true);
		this.ct.fill();

		this.ct.strokeStyle = turtle.color.lightgray;
 		this.ct.beginPath();
		this.ct.moveTo(x0, y0);
		this.ct.lineTo(x1, y1);
		this.ct.stroke();
	};

	/** add Global Single var. */
	if (typeof window.TURTLE == "undefined") {
		window.TURTLE = turtle;
	}
})()

<commit_msg>These lines were not used.<commit_after>/** Turtle example for SoraMame.Block
	Copyright 2015 Yutaka Kachi under MIT License

	Modfied from HTML5 canvas turtle graphics
    Copyright 2012 Hannes Hirzel under CC by 3.0
	http://cnx.org/contents/85310cba-5bbc-4f1d-b437-778a1aef9d02@2/Turtle_graphics_with_the_HTML5
 */

 (function() {

	// JavaScript statements
	// =====================================================================================
	var turtle = {
		x: 0,
		y: 0,
		angleInRadians: 0,
		penDown: false,
		penColor: "#000000",
		lineWidth: 2
	};

	turtle.color = {
		black: "#000000",
		gray: "#808080",
		lightgray: "#C0C0C0",
		red: "#ff0000",
		green: "#00ff00",
		blue: "#0000ff",
		yellow: "#ffff00",
		fuchsia: "#ff00ff",
		aqua: "#00ffff"
	};

	var canvas = document.getElementById('myDrawing');

	if (canvas && canvas.getContext) { // does the browser support 'canvas'?
		turtle.ct = canvas.getContext("2d"); // get drawing context
	} else {
		alert('You need a browser which supports the HTML5 canvas!');
	}

	// =====================================================================================

	turtle.logPenStatus = function () {
		console.log('x=' + this.x + "; y=" + this.y + '; angle = ' + this.angle + '; penDown = ' + this.penDown);
	};

	turtle.forward = function (length) {
		// console.log('forward(' + length + ')');
		// this.logPenStatus();
		var x0 = this.x,
			y0 = this.y;
		this.x += length * Math.sin(this.angleInRadians);
		this.y += length * Math.cos(this.angleInRadians);
		if (this.ct) {
			if (this.penDown) {
				//this.logPenStatus();
				this.ct.beginPath();
				this.ct.lineWidth = this.lineWidth;
				this.ct.strokeStyle = this.penColor;
				this.ct.moveTo(x0, y0);
				this.ct.lineTo(this.x, this.y);
				this.ct.stroke();
			}
		} else {
			this.ct.moveTo(this.x, this.y);
		}
		return this;
	};

	turtle.backward = function (length) {
		this.forward(-length);
		return this;
	};

	turtle.left = function (angleInDegrees) {
		// console.log('left(' + angleInDegrees + ')');
		// A complete circle, 360o, is equivalent to 2 radians
		// angleInDegrees is an angle measure in degrees
		this.angleInRadians += angleInDegrees * Math.PI / 180.0;
		return this;
	};

	turtle.right = function (angleInDegrees) {
		this.left(-angleInDegrees);
		return this;
	};

	turtle.angle = function () {
		// the turtle status is hold in this.angleInRadians;
		// degrees are often more convenient for the display
		return this.angleInRadians * 180.0 / Math.PI;
	};

	turtle.clear = function () {
		// clear CANVAS
		this.ct.clearRect(0, 0, canvas.width, canvas.height);
	};

	turtle.mark = function () {
		// drawing turtle symbol.
		var path = 5;

		var x0 = this.x,
			y0 = this.y,
			x1 = x0 + path * 1.5 * Math.sin(this.angleInRadians),
			y1 = y0 + path * 1.5 * Math.cos(this.angleInRadians);

		this.ct.fillStyle = turtle.color.gray;
		this.ct.beginPath();
		this.ct.arc(x0, y0, path, 0, Math.PI*2, true);
		this.ct.fill();

		this.ct.strokeStyle = turtle.color.lightgray;
 		this.ct.beginPath();
		this.ct.moveTo(x0, y0);
		this.ct.lineTo(x1, y1);
		this.ct.stroke();
	};

	/** add Global Single var. */
	if (typeof window.TURTLE == "undefined") {
		window.TURTLE = turtle;
	}
})()

<|endoftext|>


<commit_before>import {
	GL,
	Renderer,
	Scene,
	PerspectiveCamera,
	GridHelper,
	OrbitControls,
	AxisHelper,
	OrthographicCamera,
	TextureCube,
	Shader,
	Mesh,
	ObjLoader,
	Geometry,
} from 'index';
import {
	guiController,
} from '../gui';

// Renderer
const renderer = new Renderer({
	ratio: window.innerWidth / window.innerHeight,
	prefferedContext: guiController.context,
});
renderer.setDevicePixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.canvas);

// Scene
const scene = new Scene();

// Camera
const cameras = {
	dev: new PerspectiveCamera({
		fov: 45,
	}),
	main: new OrthographicCamera({
		fov: 45,
	}),
};

cameras.dev.position.set(10, 5, 10);
cameras.dev.lookAt();

cameras.main.position.set(0, 0, 1);
cameras.main.lookAt(0, 0, 0);

// Helpers
const controls = new OrbitControls(cameras.dev, renderer.canvas);

const grid = new GridHelper(10);
scene.add(grid);

const axis = new AxisHelper(1);
scene.add(axis);

controls.update();

const texture = new TextureCube({
	src: [
		'/assets/textures/cube/px.jpg',
		'/assets/textures/cube/nx.jpg',
		'/assets/textures/cube/py.jpg',
		'/assets/textures/cube/ny.jpg',
		'/assets/textures/cube/pz.jpg',
		'/assets/textures/cube/nz.jpg',
	],
});

let mesh;

new ObjLoader('assets/models/mass.obj').then(objGeometry => {
	const geometry = new Geometry(objGeometry.vertices,
		objGeometry.indices, objGeometry.vertexNormals);

	const material = new Shader({
		hookVertexPre: GL.webgl2 ?
		'out vec3 vTexturePosition;' :
		'varying vec3 vTexturePosition;',
		hookVertexEnd: `
			vTexturePosition = (uModelMatrix * vec4(aVertexPosition, 1.0)).xyz;
		`,
		hookFragmentPre: GL.webgl2 ? `
			uniform samplerCube uTexture0;
			in vec3 vTexturePosition;
		` : `
			uniform samplerCube uTexture0;
			varying vec3 vTexturePosition;
		`,
		hookFragmentMain: GL.webgl2 ?
		'color = texture(uTexture0, vTexturePosition).rgb;' :
		'color = textureCube(uTexture0, vTexturePosition).rgb;',
		uniforms: {
			uTexture0: {
				type: 'tc',
				value: texture.texture,
				textureIndex: 0,
			},
		},
	});

	mesh = new Mesh(geometry, material);

	const scale = 0.25;
	mesh.scale.set(scale, scale, scale);
	scene.add(mesh);
}).catch(error => {
	console.log('error loading', error);
});

function resize() {
	const width = window.innerWidth;
	const height = window.innerHeight;
	renderer.setSize(width, height);
}
resize();

window.addEventListener('resize', resize);

function update() {
	requestAnimationFrame(update);

	if (mesh) {
		mesh.rotation.y += 0.003;
	}

	renderer.render(scene, cameras.dev);
}
update();
<commit_msg>omg, how I was wrong about textureCube<commit_after>import {
	GL,
	Renderer,
	Scene,
	PerspectiveCamera,
	GridHelper,
	OrbitControls,
	AxisHelper,
	OrthographicCamera,
	TextureCube,
	Shader,
	Mesh,
	ObjLoader,
	Geometry,
} from 'index';
import {
	guiController,
} from '../gui';

// Renderer
const renderer = new Renderer({
	ratio: window.innerWidth / window.innerHeight,
	prefferedContext: guiController.context,
});
renderer.setDevicePixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.canvas);

// Scene
const scene = new Scene();

// Camera
const cameras = {
	dev: new PerspectiveCamera({
		fov: 45,
	}),
	main: new OrthographicCamera({
		fov: 45,
	}),
};

cameras.dev.position.set(10, 5, 10);
cameras.dev.lookAt();

cameras.main.position.set(0, 0, 1);
cameras.main.lookAt(0, 0, 0);

// Helpers
const controls = new OrbitControls(cameras.dev, renderer.canvas);

const grid = new GridHelper(10);
scene.add(grid);

const axis = new AxisHelper(1);
scene.add(axis);

controls.update();

const texture = new TextureCube({
	src: [
		'/assets/textures/cube/blackice/px.jpg',
		'/assets/textures/cube/blackice/nx.jpg',
		'/assets/textures/cube/blackice/py.jpg',
		'/assets/textures/cube/blackice/ny.jpg',
		'/assets/textures/cube/blackice/pz.jpg',
		'/assets/textures/cube/blackice/nz.jpg',
	],
});

let mesh;

new ObjLoader('assets/models/mass.obj').then(objGeometry => {
	const geometry = new Geometry(objGeometry.vertices,
		objGeometry.indices, objGeometry.vertexNormals);

	const material = new Shader({
		hookFragmentPre: GL.webgl2 ? `
			uniform samplerCube uTexture0;
		` : `
			uniform samplerCube uTexture0;
		`,
		hookFragmentMain: GL.webgl2 ?
		'color = texture(uTexture0, vNormal).rgb;' :
		'color = textureCube(uTexture0, vNormal).rgb;',
		uniforms: {
			uTexture0: {
				type: 'tc',
				value: texture.texture,
				textureIndex: 0,
			},
		},
	});

	mesh = new Mesh(geometry, material);

	const scale = 0.25;
	mesh.scale.set(scale, scale, scale);
	scene.add(mesh);
}).catch(error => {
	console.log('error loading', error);
});

function resize() {
	const width = window.innerWidth;
	const height = window.innerHeight;
	renderer.setSize(width, height);
}
resize();

window.addEventListener('resize', resize);

function update() {
	requestAnimationFrame(update);

	if (mesh) {
		mesh.rotation.y += 0.003;
	}

	renderer.render(scene, cameras.dev);
}
update();
<|endoftext|>


<commit_before>'use strict';

const jsonParser = require('body-parser').json();
const {Router} = require('express');
const basicAuth = require('../lib/basic-auth-middleware.js');
const User = require('../model/user.js');

const profileRouter = module.exports = new Router();

profileRouter.post('/api/profile/:id', jsonParser, basicAuth, (req, res, next) => {

});

profileRouter.get('/api/profile/:id', (req, res, next) => {

});

petRouter.post('/api/pets', bearerAuth, s3Upload('image'), (req, res, next) => {
  new Pet({
    name: req.body.name,
    type: req.body.type,
    photoURI: req.s3Data.Location,
    userID: req.user._id.toString(),
  })
  .save()
  .then(pet => res.json(pet))
  .catch(next);
});
<commit_msg>everything for profile is done but the router<commit_after>'use strict';

const jsonParser = require('body-parser').json();
const {Router} = require('express');
const s3Upload = require('../lib/s3-upload-middleware.js');
const bearerAuth = require('../lib/bearer-auth-middleware.js');
const User = require('../model/user.js');

const profileRouter = module.exports = new Router();

profileRouter.post('/api/profile/:id', jsonParser, basicAuth, (req, res, next) => {

});

profileRouter.get('/api/profile/:id', (req, res, next) => {

});

petRouter.post('/api/pets', bearerAuth, s3Upload('image'), (req, res, next) => {
  new Pet({
    name: req.body.name,
    type: req.body.type,
    photoURI: req.s3Data.Location,
    userID: req.user._id.toString(),
  })
  .save()
  .then(pet => res.json(pet))
  .catch(next);
});
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var api = require('../lib/api');
var fs = require('fs');
var multer = require('multer');
var storage = multer.diskStorage({
  destination: function (req, file, callback) {
    callback(null, 'uploads/')
  },
  filename: function (req, file, callback) {
    callback(null, Date.now() + '.zip') //Appending .zip
  }
})
var upload = multer({ storage: storage });

/* GET a playlist by keyword*/
router.post('/with-words', function(req, res, next) {
  var words = req.body.words;
  var credentials = {
    access_token : req.body.access_token,
    refresh_token : req.body.refresh_token
  }

  api.createPlaylistFromWords(words, credentials, function(response) {
    res.send(response);
  });
});

router.post('/with-images',  upload.single('images_file'), function(req, res, next) {
  var images_file = fs.createReadStream(req.file.path);
  var credentials = {
    access_token : req.body.access_token,
    refresh_token : req.body.refresh_token
  }

  if(!images_file) {
    return next({ error:'The photo album zip file is not found.  Please try again.', code:404});
  }
  else {
    api.createPlaylistFromImages(images_file, credentials, function(response) {
      res.send(response);
    });
  }
});

module.exports = router;
<commit_msg>added logging for debugging pebble communication issues<commit_after>var express = require('express');
var router = express.Router();
var api = require('../lib/api');
var fs = require('fs');
var multer = require('multer');
var storage = multer.diskStorage({
  destination: function (req, file, callback) {
    callback(null, 'uploads/')
  },
  filename: function (req, file, callback) {
    callback(null, Date.now() + '.zip') //Appending .zip
  }
})
var upload = multer({ storage: storage });

/* GET a playlist by keyword*/
router.post('/with-words', function(req, res, next) {
  var words = req.body.words;
  var credentials = {
    access_token : req.body.access_token,
    refresh_token : req.body.refresh_token
  }

    console.log(req);
    console.log(words);
    console.log(credentials);

  api.createPlaylistFromWords(words, credentials, function(response) {
    res.send(response);
  });
});

router.post('/with-images',  upload.single('images_file'), function(req, res, next) {
  var images_file = fs.createReadStream(req.file.path);
  var credentials = {
    access_token : req.body.access_token,
    refresh_token : req.body.refresh_token
  }

  if(!images_file) {
    return next({ error:'The photo album zip file is not found.  Please try again.', code:404});
  }
  else {
    api.createPlaylistFromImages(images_file, credentials, function(response) {
      res.send(response);
    });
  }
});

module.exports = router;
<|endoftext|>


<commit_before>'use strict';

var handlers = require('../handlers/municipalities');
var routes;

routes = [
  {
    method: 'GET',
    path: '/municipalities',
    handler: handlers.getMunicipalities
  },
  {
    method: 'GET',
    path: '/municipality/{municipalityId}',
    handler: handlers.getMunicipality
  }
];

module.exports = routes;<commit_msg>Changes to please jscs<commit_after>'use strict';

var handlers = require('../handlers/municipalities');
var routes;

routes = [
  {
    method: 'GET',
    path: '/municipalities',
    handler: handlers.getMunicipalities
  },
  {
    method: 'GET',
    path: '/municipality/{municipalityId}',
    handler: handlers.getMunicipality
  }
];

module.exports = routes;
<|endoftext|>


<commit_before>var utils = require('../lib/utils');
var config = require('../config');
var dbUtils = require('../lib/dbUtils');
var middleware = require('../middleware');

var passport = require('passport');
var permission = require('permission');

exports.processMessages = processMessages;
exports.getMessageData = getMessageData;

/**
 * Adds routes for handling user sent messages
 * @param router
 */
function processMessages(router) {

    router.get('/sendMessage', function(req, res, next) {
        if(req.isAuthenticated()) {
            res.render('forms/sendmessage');
        }
    });
    /**
     * Take user details, and if all entered in properly save user to the database.
     * If something goes wrong we redirect back to the forms to try again, but with a message to the user too.
     */
    router.post('/message', function(req, res, next) {
        if(req.user && req.isAuthenticated()) {
            /**
             * Form must contain following components:
             * subject      IN message.subject
             * message text IN message.text
             * recipient    IN message.recipientID
             */
            var message = {};
            message['fromID']       = req.user.userID;
            message['subject']      = req.body.subject;
            message['recipientID']  = parseInt(req.body.recipientID);
            message['message']      = req.body.text;
            message['hasRead']      = false;

            var allFieldsExist = false;
            if(message['subject']       != null &&
               message['message']       != null &&
               message['recipientID']   != null) {
               allFieldsExist=true;
            } else {
                if(!allFieldsExist) {
                    req.flash('error', 'Required fields not filled');
                }
                req.flash('success', 'Message sent!');
                res.redirect('/inbox');
                return;
            }

            dbUtils.checkExist('users', {'userID': message['recipientID']}, function(err, recipientExists) {

                if(err) {
                    res.render('501', {status: 501, url: req.url});
                    return;
                }
                if(recipientExists && allFieldsExist) {
                    dbUtils.addMessage(message).then(function() {
                        res.redirect('/sendMessage');
                    });
                } else {
                    req.flash('error', 'Please enter a valid recipient');
                    res.redirect('/sendMessage');
                }
            });
        }
        else {
            res.render('501', {status: 501, url: req.url});
        }
    });
}

function getMessageData(router) {
    /**
     * Gets message list for a specified user either sending or recieving messages
     * Takes JSON request only
     * Client should post JSON containing user's ID
     */
     router.post('/getMessages', function(req, res) {
        //var byRecipient = req.body.bySender; //If false, assumed to be asking for emails by sender - ones that were send by user
        var byRecipient = true;
        var userID = req.user.userID;

        if(byRecipient) {
            dbUtils.getRecievedMessages(userID).then(function(messageList) {
                console.log('recieved request');
                messageList = formatMessageData(messageList);
                res.send(messageList);
            });
        } else {
            dbUtils.getUserMessages(userID).then(function(messageList) {
                messageList = formatMessageData(messageList);
                res.send(messageList);
            });
        }

     });

     /**
      * Gets address
      *
      */
     router.post('/getRelevantAddresses', function(req, res) {
     });
}

function formatMessageData(messageList) {
    var newList = [];
    for(var index in messageList) {
        var message = messageList[index];
        var column_array =[message.fromID, message.subject, message.createdAt];
        newList.push(column_array);
        console.log(message);
    }

    console.log(newList);
    return {"data": newList};
}
<commit_msg>added body to getMessages<commit_after>var utils = require('../lib/utils');
var config = require('../config');
var dbUtils = require('../lib/dbUtils');
var middleware = require('../middleware');

var passport = require('passport');
var permission = require('permission');

exports.processMessages = processMessages;
exports.getMessageData = getMessageData;

/**
 * Adds routes for handling user sent messages
 * @param router
 */
function processMessages(router) {

    router.get('/sendMessage', function(req, res, next) {
        if(req.isAuthenticated()) {
            res.render('forms/sendmessage');
        }
    });
    /**
     * Take user details, and if all entered in properly save user to the database.
     * If something goes wrong we redirect back to the forms to try again, but with a message to the user too.
     */
    router.post('/message', function(req, res, next) {
        if(req.user && req.isAuthenticated()) {
            /**
             * Form must contain following components:
             * subject      IN message.subject
             * message text IN message.text
             * recipient    IN message.recipientID
             */
            var message = {};
            message['fromID']       = req.user.userID;
            message['subject']      = req.body.subject;
            message['recipientID']  = parseInt(req.body.recipientID);
            message['message']      = req.body.text;
            message['hasRead']      = false;

            var allFieldsExist = false;
            if(message['subject']       != null &&
               message['message']       != null &&
               message['recipientID']   != null) {
               allFieldsExist=true;
            } else {
                if(!allFieldsExist) {
                    req.flash('error', 'Required fields not filled');
                }
                req.flash('success', 'Message sent!');
                res.redirect('/inbox');
                return;
            }

            dbUtils.checkExist('users', {'userID': message['recipientID']}, function(err, recipientExists) {

                if(err) {
                    res.render('501', {status: 501, url: req.url});
                    return;
                }
                if(recipientExists && allFieldsExist) {
                    dbUtils.addMessage(message).then(function() {
                        res.redirect('/sendMessage');
                    });
                } else {
                    req.flash('error', 'Please enter a valid recipient');
                    res.redirect('/sendMessage');
                }
            });
        }
        else {
            res.render('501', {status: 501, url: req.url});
        }
    });
}

function getMessageData(router) {
    /**
     * Gets message list for a specified user either sending or recieving messages
     * Takes JSON request only
     * Client should post JSON containing user's ID
     */
     router.post('/getMessages', function(req, res) {
        //var byRecipient = req.body.bySender; //If false, assumed to be asking for emails by sender - ones that were send by user
        var byRecipient = true;
        var userID = req.user.userID;

        if(byRecipient) {
            dbUtils.getRecievedMessages(userID).then(function(messageList) {
                console.log('recieved request');
                messageList = formatMessageData(messageList);
                res.send(messageList);
            });
        } else {
            dbUtils.getUserMessages(userID).then(function(messageList) {
                messageList = formatMessageData(messageList);
                res.send(messageList);
            });
        }

     });

     /**
      * Gets address
      *
      */
     router.post('/getRelevantAddresses', function(req, res) {
     });
}

function formatMessageData(messageList) {
    var newList = [];
    for(var index in messageList) {
        var message = messageList[index];
        var column_array =[message.fromID, message.subject, message.body, message.createdAt];
        newList.push(column_array);
        console.log(message);
    }

    console.log(newList);
    return {"data": newList};
}
<|endoftext|>


<commit_before>var mysql = require('mysql');
var config = require('../config');
var dateUtil = require('../utils/dates');

//connect to the mysql db
var connection;
module.exports.connect = function(){
    connection = mysql.createConnection(config.databaseConfig);
    connection.connect();
};

var linkCategoryToPage = function(categoryId, pageId) {
    connection.query('INSERT INTO `pages_categories` SET ?', {page_id: pageId, category_id: categoryId}, function (err, result) {
        if(err) {
            console.log(err);
        }
    })
};

module.exports.disconnect = function(){
    if (connection) {
        connection.end();
    }
};

module.exports.insertPage = function(element, callback) {
    if (connection) {
        var pageDAO = {title: element.title,
            timestamp: dateUtil.fromWikiTimestampToSqlTimestamp(element.timestamp),
            id: element.id,
            url: element.url,
            introduction: element.introduction
        };
        connection.query('INSERT INTO pages SET ?', pageDAO, function(err, result) {
            if(err){
                console.log(err);
            } else {
                callback(result.insertId);
            }
        });
    }
};

//can be used if all the sections of the page is being stored. This method is not tested properly
var insertSectionRecursive = function (sections, pageId, i, nameToIdMap) {
    if(i >= sections.length) {
        return;
    }

    var sectionDAO = { header: sections[i].header.headerText,
        content_markup: sections[i].content,
        content_plaintext: sections[i].plaintextContent,
        page_id: pageId,
        length: sections[i].content.length
    };
    var parentId = nameToIdMap.get(sectionDAO.parent)
    if(parentId) {
        sectionDAO.parent_section_id = parentId;
    } else {
        sectionDAO.parent_section_id = null;
    }

    connection.query('INSERT INTO page_sections SET ?', sectionDAO, function(err, result) {
        if(err){
            console.log(err);
        } else {
            nameToIdMap.set(sectionDAO.header, result.insertId);
            insertSectionRecursive(sections,pageId,++i,nameToIdMap);
        }
    });
}

module.exports.insertSections = function(sections, pageId, callback) {
    sections.forEach(function(entry){
        var sectionDAO = { header: entry.header.headerText,
            content_markup: entry.content,
            content_plaintext: entry.plaintextContent,
            page_id: pageId,
            length: entry.content.length,
            ancestors: entry.ancestorString,
            header_type: entry.header.type
        };
        connection.query('INSERT INTO page_sections SET ?', sectionDAO, function(err, result) {
            if(err){
                console.log(err);
            } else {
                callback(result.insertId, sectionDAO.header);
            }
        });
    })
};

module.exports.insertPageReferences = function (references, sectionId) {
    references.forEach(function(entry){
        entry.section_id = sectionId;
        connection.query('INSERT INTO page_references SET ?', entry, function(err, result) {
            if(err){
                console.log(err);
            }
        });
    })
};

module.exports.insertCategories = function(categories, pageId) {
    categories.forEach(function(entry){
        //check if the category already exists in the table
        connection.query('SELECT `id` FROM `categories` WHERE `name` = ?', [entry], function(err, results, fields){
            if(err){
                console.log(err)
            } else {
                //if the category exists already
                if (results.length > 0) {
                    linkCategoryToPage(results[0].id, pageId);
                //if it does not exist we insert it
                } else {
                    connection.query("INSERT INTO `categories` SET ?", {name: entry}, function (err, result) {
                        if(err){
                            console.log(err);
                        } else {
                            linkCategoryToPage(result.insertId, pageId);
                        }
                    })
                }
            }
        })

    })
};
<commit_msg>Fix bug where insertId no longer exists<commit_after>var mysql = require('mysql');
var config = require('../config');
var dateUtil = require('../utils/dates');

//connect to the mysql db
var connection;
module.exports.connect = function(){
    connection = mysql.createConnection(config.databaseConfig);
    connection.connect();
};

var linkCategoryToPage = function(categoryId, pageId) {
    connection.query('INSERT INTO `pages_categories` SET ?', {page_id: pageId, category_id: categoryId}, function (err, result) {
        if(err) {
            console.log(err);
        }
    })
};

module.exports.disconnect = function(){
    if (connection) {
        connection.end();
    }
};

module.exports.insertPage = function(element, callback) {
    if (connection) {
        var pageDAO = {title: element.title,
            timestamp: dateUtil.fromWikiTimestampToSqlTimestamp(element.timestamp),
            id: element.id,
            url: element.url,
            introduction: element.introduction
        };
        connection.query('INSERT INTO pages SET ?', pageDAO, function(err, result) {
            if(err){
                console.log(err);
            } else {
                callback(pageDAO.id);
            }
        });
    }
};

//can be used if all the sections of the page is being stored. This method is not tested properly
var insertSectionRecursive = function (sections, pageId, i, nameToIdMap) {
    if(i >= sections.length) {
        return;
    }

    var sectionDAO = { header: sections[i].header.headerText,
        content_markup: sections[i].content,
        content_plaintext: sections[i].plaintextContent,
        page_id: pageId,
        length: sections[i].content.length
    };
    var parentId = nameToIdMap.get(sectionDAO.parent)
    if(parentId) {
        sectionDAO.parent_section_id = parentId;
    } else {
        sectionDAO.parent_section_id = null;
    }

    connection.query('INSERT INTO page_sections SET ?', sectionDAO, function(err, result) {
        if(err){
            console.log(err);
        } else {
            nameToIdMap.set(sectionDAO.header, result.insertId);
            insertSectionRecursive(sections,pageId,++i,nameToIdMap);
        }
    });
}

module.exports.insertSections = function(sections, pageId, callback) {
    sections.forEach(function(entry){
        var sectionDAO = { header: entry.header.headerText,
            content_markup: entry.content,
            content_plaintext: entry.plaintextContent,
            page_id: pageId,
            length: entry.content.length,
            ancestors: entry.ancestorString,
            header_type: entry.header.type
        };
        connection.query('INSERT INTO page_sections SET ?', sectionDAO, function(err, result) {
            if(err){
                console.log(err);
            } else {
                callback(result.insertId, sectionDAO.header);
            }
        });
    })
};

module.exports.insertPageReferences = function (references, sectionId) {
    references.forEach(function(entry){
        entry.section_id = sectionId;
        connection.query('INSERT INTO page_references SET ?', entry, function(err, result) {
            if(err){
                console.log(err);
            }
        });
    })
};

module.exports.insertCategories = function(categories, pageId) {
    categories.forEach(function(entry){
        //check if the category already exists in the table
        connection.query('SELECT `id` FROM `categories` WHERE `name` = ?', [entry], function(err, results, fields){
            if(err){
                console.log(err)
            } else {
                //if the category exists already
                if (results.length > 0) {
                    linkCategoryToPage(results[0].id, pageId);
                //if it does not exist we insert it
                } else {
                    connection.query("INSERT INTO `categories` SET ?", {name: entry}, function (err, result) {
                        if(err){
                            console.log(err);
                        } else {
                            linkCategoryToPage(result.insertId, pageId);
                        }
                    })
                }
            }
        })

    })
};
<|endoftext|>


<commit_before>var NAMESPACE = 'enterprise-contact-me';

var Hoek = require('hoek'),
    Hapi = require('hapi'),
    log = require('bole')(NAMESPACE),
    uuid = require('node-uuid'),
    metrics = require('newww-metrics')();

var config = require('../../config').license;

// if they decide not to agree to the ULA
// hit the hubspot contact-me form instead, and thank them
module.exports = function contactMe (request, reply) {
  var postToHubspot = request.server.methods.npme.sendData,
      showError = request.server.methods.errors.showError(reply);

  var opts = {
    user: request.auth.credentials,

    namespace: NAMESPACE
  };

  var data = { email: request.payload.contact_customer_email };

  postToHubspot(config.hubspot.form_npme_contact_me, data, function(er) {

      if (er) {
        log.warn("Could not contact hubspot");

        return showError(er, 500, 'Could not register user to be contacted', opts);
      } else {

        opts.title = "We will contact you shortly";

        return reply.view('enterprise/contact-me', opts);
      }
    }
  );
}<commit_msg>validates email for enterprise contact form<commit_after>var NAMESPACE = 'enterprise-contact-me';

var Hoek = require('hoek'),
    Hapi = require('hapi'),
    Joi = require('joi'),
    log = require('bole')(NAMESPACE),
    uuid = require('node-uuid'),
    metrics = require('newww-metrics')();

var config = require('../../config').license;

// if they decide not to agree to the ULA
// hit the hubspot contact-me form instead, and thank them
module.exports = function contactMe (request, reply) {
  var postToHubspot = request.server.methods.npme.sendData,
      showError = request.server.methods.errors.showError(reply);

  var opts = {
    user: request.auth.credentials,

    namespace: NAMESPACE
  };

  // Is email invalid?
  if (Joi.validate(request.payload.contact_customer_email, Joi.string().regex(/^.+@.+\..+$/)).error) {
    return reply.view('enterprise/index').code(400);
  }

  var data = { email: request.payload.contact_customer_email };

  postToHubspot(config.hubspot.form_npme_contact_me, data, function(er) {

      if (er) {
        log.warn("Could not contact hubspot");

        return showError(er, 500, 'Could not register user to be contacted', opts);
      } else {

        opts.title = "We will contact you shortly";

        return reply.view('enterprise/contact-me', opts);
      }
    }
  );

}<|endoftext|>


<commit_before>import Ember from 'ember';
import Response from 'ember-cli-mirage/response';
import { HOSTS } from './common';
import { logFrames, logEncode } from './data/logs';

const { copy } = Ember;

export function findLeader(schema) {
  const agent = schema.agents.first();
  return `${agent.address}:${agent.tags.port}`;
}

export default function() {
  this.timing = 0; // delay for each request, automatically set to 0 during testing

  this.namespace = 'v1';
  this.trackRequests = Ember.testing;

  const nomadIndices = {}; // used for tracking blocking queries
  const server = this;
  const withBlockingSupport = function(fn) {
    return function(schema, request) {
      // Get the original response
      let { url } = request;
      url = url.replace(/index=\d+[&;]?/, '');
      const response = fn.apply(this, arguments);

      // Get and increment the appropriate index
      nomadIndices[url] || (nomadIndices[url] = 2);
      const index = nomadIndices[url];
      nomadIndices[url]++;

      // Annotate the response with the index
      if (response instanceof Response) {
        response.headers['X-Nomad-Index'] = index;
        return response;
      }
      return new Response(200, { 'x-nomad-index': index }, response);
    };
  };

  this.get(
    '/jobs',
    withBlockingSupport(function({ jobs }, { queryParams }) {
      const json = this.serialize(jobs.all());
      const namespace = queryParams.namespace || 'default';
      return json
        .filter(
          job =>
            namespace === 'default'
              ? !job.NamespaceID || job.NamespaceID === namespace
              : job.NamespaceID === namespace
        )
        .map(job => filterKeys(job, 'TaskGroups', 'NamespaceID'));
    })
  );

  this.get(
    '/job/:id',
    withBlockingSupport(function({ jobs }, { params, queryParams }) {
      const job = jobs.all().models.find(job => {
        const jobIsDefault = !job.namespaceId || job.namespaceId === 'default';
        const qpIsDefault = !queryParams.namespace || queryParams.namespace === 'default';
        return (
          job.id === params.id &&
          (job.namespaceId === queryParams.namespace || (jobIsDefault && qpIsDefault))
        );
      });

      return job ? this.serialize(job) : new Response(404, {}, null);
    })
  );

  this.get(
    '/job/:id/summary',
    withBlockingSupport(function({ jobSummaries }, { params }) {
      return this.serialize(jobSummaries.findBy({ jobId: params.id }));
    })
  );

  this.get('/job/:id/allocations', function({ allocations }, { params }) {
    return this.serialize(allocations.where({ jobId: params.id }));
  });

  this.get('/job/:id/versions', function({ jobVersions }, { params }) {
    return this.serialize(jobVersions.where({ jobId: params.id }));
  });

  this.get('/job/:id/deployments', function({ deployments }, { params }) {
    return this.serialize(deployments.where({ jobId: params.id }));
  });

  this.post('/job/:id/periodic/force', function(schema, { params }) {
    // Create the child job
    const parent = schema.jobs.find(params.id);

    // Use the server instead of the schema to leverage the job factory
    server.create('job', 'periodicChild', {
      parentId: parent.id,
      namespaceId: parent.namespaceId,
      namespace: parent.namespace,
      createAllocations: parent.createAllocations,
    });

    // Return bogus, since the response is normally just eval information
    return new Response(200, {}, '{}');
  });

  this.delete('/job/:id', function(schema, { params }) {
    const job = schema.jobs.find(params.id);
    job.update({ status: 'dead' });
    return new Response(204, {}, '');
  });

  this.get('/deployment/:id');

  this.get('/job/:id/evaluations', function({ evaluations }, { params }) {
    return this.serialize(evaluations.where({ jobId: params.id }));
  });

  this.get('/evaluation/:id');

  this.get('/deployment/allocations/:id', function(schema, { params }) {
    const job = schema.jobs.find(schema.deployments.find(params.id).jobId);
    const allocations = schema.allocations.where({ jobId: job.id });

    return this.serialize(allocations.slice(0, 3));
  });

  this.get('/nodes', function({ nodes }) {
    const json = this.serialize(nodes.all());
    return json;
  });

  this.get('/node/:id');

  this.get('/node/:id/allocations', function({ allocations }, { params }) {
    return this.serialize(allocations.where({ nodeId: params.id }));
  });

  this.get('/allocations');

  this.get('/allocation/:id');

  this.get('/namespaces', function({ namespaces }) {
    const records = namespaces.all();

    if (records.length) {
      return this.serialize(records);
    }

    return new Response(501, {}, null);
  });

  this.get('/namespace/:id', function({ namespaces }, { params }) {
    if (namespaces.all().length) {
      return this.serialize(namespaces.find(params.id));
    }

    return new Response(501, {}, null);
  });

  this.get('/agent/members', function({ agents }) {
    return {
      Members: this.serialize(agents.all()),
    };
  });

  this.get('/status/leader', function(schema) {
    return JSON.stringify(findLeader(schema));
  });

  this.get('/acl/token/self', function({ tokens }, req) {
    const secret = req.requestHeaders['X-Nomad-Token'];
    const tokenForSecret = tokens.findBy({ secretId: secret });

    // Return the token if it exists
    if (tokenForSecret) {
      return this.serialize(tokenForSecret);
    }

    // Client error if it doesn't
    return new Response(400, {}, null);
  });

  this.get('/acl/token/:id', function({ tokens }, req) {
    const token = tokens.find(req.params.id);
    const secret = req.requestHeaders['X-Nomad-Token'];
    const tokenForSecret = tokens.findBy({ secretId: secret });

    // Return the token only if the request header matches the token
    // or the token is of type management
    if (token.secretId === secret || (tokenForSecret && tokenForSecret.type === 'management')) {
      return this.serialize(token);
    }

    // Return not authorized otherwise
    return new Response(403, {}, null);
  });

  this.get('/acl/policy/:id', function({ policies, tokens }, req) {
    const policy = policies.find(req.params.id);
    const secret = req.requestHeaders['X-Nomad-Token'];
    const tokenForSecret = tokens.findBy({ secretId: secret });

    // Return the policy only if the token that matches the request header
    // includes the policy or if the token that matches the request header
    // is of type management
    if (
      tokenForSecret &&
      (tokenForSecret.policies.includes(policy) || tokenForSecret.type === 'management')
    ) {
      return this.serialize(policy);
    }

    // Return not authorized otherwise
    return new Response(403, {}, null);
  });

  const clientAllocationStatsHandler = function({ clientAllocationStats }, { params }) {
    return this.serialize(clientAllocationStats.find(params.id));
  };

  const clientAllocationLog = function(server, { params, queryParams }) {
    const allocation = server.allocations.find(params.allocation_id);
    const tasks = allocation.taskStateIds.map(id => server.taskStates.find(id));

    if (!tasks.mapBy('name').includes(queryParams.task)) {
      return new Response(400, {}, 'must include task name');
    }

    if (queryParams.plain) {
      return logFrames.join('');
    }

    return logEncode(logFrames, logFrames.length - 1);
  };

  // Client requests are available on the server and the client
  this.get('/client/allocation/:id/stats', clientAllocationStatsHandler);
  this.get('/client/fs/logs/:allocation_id', clientAllocationLog);

  this.get('/client/v1/client/stats', function({ clientStats }, { queryParams }) {
    return this.serialize(clientStats.find(queryParams.node_id));
  });

  // TODO: in the future, this hack may be replaceable with dynamic host name
  // support in pretender: https://github.com/pretenderjs/pretender/issues/210
  HOSTS.forEach(host => {
    this.get(`http://${host}/v1/client/allocation/:id/stats`, clientAllocationStatsHandler);
    this.get(`http://${host}/v1/client/fs/logs/:allocation_id`, clientAllocationLog);

    this.get(`http://${host}/v1/client/stats`, function({ clientStats }) {
      return this.serialize(clientStats.find(host));
    });
  });
}

function filterKeys(object, ...keys) {
  const clone = copy(object, true);

  keys.forEach(key => {
    delete clone[key];
  });

  return clone;
}
<commit_msg>Support the /job/:id/deployment endpoint in mirage<commit_after>import Ember from 'ember';
import Response from 'ember-cli-mirage/response';
import { HOSTS } from './common';
import { logFrames, logEncode } from './data/logs';

const { copy } = Ember;

export function findLeader(schema) {
  const agent = schema.agents.first();
  return `${agent.address}:${agent.tags.port}`;
}

export default function() {
  this.timing = 0; // delay for each request, automatically set to 0 during testing

  this.namespace = 'v1';
  this.trackRequests = Ember.testing;

  const nomadIndices = {}; // used for tracking blocking queries
  const server = this;
  const withBlockingSupport = function(fn) {
    return function(schema, request) {
      // Get the original response
      let { url } = request;
      url = url.replace(/index=\d+[&;]?/, '');
      const response = fn.apply(this, arguments);

      // Get and increment the appropriate index
      nomadIndices[url] || (nomadIndices[url] = 2);
      const index = nomadIndices[url];
      nomadIndices[url]++;

      // Annotate the response with the index
      if (response instanceof Response) {
        response.headers['X-Nomad-Index'] = index;
        return response;
      }
      return new Response(200, { 'x-nomad-index': index }, response);
    };
  };

  this.get(
    '/jobs',
    withBlockingSupport(function({ jobs }, { queryParams }) {
      const json = this.serialize(jobs.all());
      const namespace = queryParams.namespace || 'default';
      return json
        .filter(
          job =>
            namespace === 'default'
              ? !job.NamespaceID || job.NamespaceID === namespace
              : job.NamespaceID === namespace
        )
        .map(job => filterKeys(job, 'TaskGroups', 'NamespaceID'));
    })
  );

  this.get(
    '/job/:id',
    withBlockingSupport(function({ jobs }, { params, queryParams }) {
      const job = jobs.all().models.find(job => {
        const jobIsDefault = !job.namespaceId || job.namespaceId === 'default';
        const qpIsDefault = !queryParams.namespace || queryParams.namespace === 'default';
        return (
          job.id === params.id &&
          (job.namespaceId === queryParams.namespace || (jobIsDefault && qpIsDefault))
        );
      });

      return job ? this.serialize(job) : new Response(404, {}, null);
    })
  );

  this.get(
    '/job/:id/summary',
    withBlockingSupport(function({ jobSummaries }, { params }) {
      return this.serialize(jobSummaries.findBy({ jobId: params.id }));
    })
  );

  this.get('/job/:id/allocations', function({ allocations }, { params }) {
    return this.serialize(allocations.where({ jobId: params.id }));
  });

  this.get('/job/:id/versions', function({ jobVersions }, { params }) {
    return this.serialize(jobVersions.where({ jobId: params.id }));
  });

  this.get('/job/:id/deployments', function({ deployments }, { params }) {
    return this.serialize(deployments.where({ jobId: params.id }));
  });

  this.get('/job/:id/deployment', function({ deployments }, { params }) {
    return this.serialize(deployments.where({ jobId: params.id }).models[0]);
  });

  this.post('/job/:id/periodic/force', function(schema, { params }) {
    // Create the child job
    const parent = schema.jobs.find(params.id);

    // Use the server instead of the schema to leverage the job factory
    server.create('job', 'periodicChild', {
      parentId: parent.id,
      namespaceId: parent.namespaceId,
      namespace: parent.namespace,
      createAllocations: parent.createAllocations,
    });

    // Return bogus, since the response is normally just eval information
    return new Response(200, {}, '{}');
  });

  this.delete('/job/:id', function(schema, { params }) {
    const job = schema.jobs.find(params.id);
    job.update({ status: 'dead' });
    return new Response(204, {}, '');
  });

  this.get('/deployment/:id');

  this.get('/job/:id/evaluations', function({ evaluations }, { params }) {
    return this.serialize(evaluations.where({ jobId: params.id }));
  });

  this.get('/evaluation/:id');

  this.get('/deployment/allocations/:id', function(schema, { params }) {
    const job = schema.jobs.find(schema.deployments.find(params.id).jobId);
    const allocations = schema.allocations.where({ jobId: job.id });

    return this.serialize(allocations.slice(0, 3));
  });

  this.get('/nodes', function({ nodes }) {
    const json = this.serialize(nodes.all());
    return json;
  });

  this.get('/node/:id');

  this.get('/node/:id/allocations', function({ allocations }, { params }) {
    return this.serialize(allocations.where({ nodeId: params.id }));
  });

  this.get('/allocations');

  this.get('/allocation/:id');

  this.get('/namespaces', function({ namespaces }) {
    const records = namespaces.all();

    if (records.length) {
      return this.serialize(records);
    }

    return new Response(501, {}, null);
  });

  this.get('/namespace/:id', function({ namespaces }, { params }) {
    if (namespaces.all().length) {
      return this.serialize(namespaces.find(params.id));
    }

    return new Response(501, {}, null);
  });

  this.get('/agent/members', function({ agents }) {
    return {
      Members: this.serialize(agents.all()),
    };
  });

  this.get('/status/leader', function(schema) {
    return JSON.stringify(findLeader(schema));
  });

  this.get('/acl/token/self', function({ tokens }, req) {
    const secret = req.requestHeaders['X-Nomad-Token'];
    const tokenForSecret = tokens.findBy({ secretId: secret });

    // Return the token if it exists
    if (tokenForSecret) {
      return this.serialize(tokenForSecret);
    }

    // Client error if it doesn't
    return new Response(400, {}, null);
  });

  this.get('/acl/token/:id', function({ tokens }, req) {
    const token = tokens.find(req.params.id);
    const secret = req.requestHeaders['X-Nomad-Token'];
    const tokenForSecret = tokens.findBy({ secretId: secret });

    // Return the token only if the request header matches the token
    // or the token is of type management
    if (token.secretId === secret || (tokenForSecret && tokenForSecret.type === 'management')) {
      return this.serialize(token);
    }

    // Return not authorized otherwise
    return new Response(403, {}, null);
  });

  this.get('/acl/policy/:id', function({ policies, tokens }, req) {
    const policy = policies.find(req.params.id);
    const secret = req.requestHeaders['X-Nomad-Token'];
    const tokenForSecret = tokens.findBy({ secretId: secret });

    // Return the policy only if the token that matches the request header
    // includes the policy or if the token that matches the request header
    // is of type management
    if (
      tokenForSecret &&
      (tokenForSecret.policies.includes(policy) || tokenForSecret.type === 'management')
    ) {
      return this.serialize(policy);
    }

    // Return not authorized otherwise
    return new Response(403, {}, null);
  });

  const clientAllocationStatsHandler = function({ clientAllocationStats }, { params }) {
    return this.serialize(clientAllocationStats.find(params.id));
  };

  const clientAllocationLog = function(server, { params, queryParams }) {
    const allocation = server.allocations.find(params.allocation_id);
    const tasks = allocation.taskStateIds.map(id => server.taskStates.find(id));

    if (!tasks.mapBy('name').includes(queryParams.task)) {
      return new Response(400, {}, 'must include task name');
    }

    if (queryParams.plain) {
      return logFrames.join('');
    }

    return logEncode(logFrames, logFrames.length - 1);
  };

  // Client requests are available on the server and the client
  this.get('/client/allocation/:id/stats', clientAllocationStatsHandler);
  this.get('/client/fs/logs/:allocation_id', clientAllocationLog);

  this.get('/client/v1/client/stats', function({ clientStats }, { queryParams }) {
    return this.serialize(clientStats.find(queryParams.node_id));
  });

  // TODO: in the future, this hack may be replaceable with dynamic host name
  // support in pretender: https://github.com/pretenderjs/pretender/issues/210
  HOSTS.forEach(host => {
    this.get(`http://${host}/v1/client/allocation/:id/stats`, clientAllocationStatsHandler);
    this.get(`http://${host}/v1/client/fs/logs/:allocation_id`, clientAllocationLog);

    this.get(`http://${host}/v1/client/stats`, function({ clientStats }) {
      return this.serialize(clientStats.find(host));
    });
  });
}

function filterKeys(object, ...keys) {
  const clone = copy(object, true);

  keys.forEach(key => {
    delete clone[key];
  });

  return clone;
}
<|endoftext|>


<commit_before><commit_msg>Added case test to transformer<commit_after><|endoftext|>


<commit_before>import Ember from 'ember';

// Formats titles similar to the way they're displayed in the dashboard.  For example, Root Name / ... / Parent Name / Node Name.
export function getAncestorDescriptor(params/*, hash*/) {
    // TODO consolidate this function
    var node = params[0];
    var nodeId = node.get('id');
    var rootId = node.get('root.id');
    var parentId = node.get('parent.id');
    var rootDescriptor;

    if (typeof rootId !== 'undefined') {
        if (typeof parentId !== 'undefined') {
            if (parentId === rootId) {
                rootDescriptor = node.get('root.title') + ' / ';
            } else {
                if (node.get('parent.parent.id') === rootId) {
                    rootDescriptor = node.get('root.title') + ' / ' + node.get('parent.title') + ' / ';
                } else {
                    rootDescriptor = node.get('root.title') + ' /.../ ' + node.get('parent.title') + ' / ';
                }
            }
        } else {
            if (rootId === nodeId) {
                rootDescriptor = '';
            } else {
                rootDescriptor = node.get('root.title') + '/.../ ';
            }
        }
    } else {
        if (typeof parentId !== 'undefined') {
            if (node.get('parent.parent.id')) {
                rootDescriptor = 'Private / ... / ' + node.get('parent.title') + ' / ';

            } else {
                rootDescriptor = 'Private / ' + node.get('parent.title') + ' / ';
            }
        } else {
            rootDescriptor = 'Private / ';
        }
    }

    return rootDescriptor + node.get('title');
}

export default Ember.Helper.helper(getAncestorDescriptor);
<commit_msg>Make behavior equal to dashboard<commit_after>import Ember from 'ember';

// Formats titles similar to the way they're displayed in the dashboard.  For example, Root Name / ... / Parent Name / Node Name.
export function getAncestorDescriptor(params/*, hash*/) {
    // TODO consolidate this function
    var node = params[0];
    var nodeId = node.get('id');
    var rootId = node.get('root.id');
    var parentId = node.get('parent.id');
    var rootDescriptor;

    if (typeof rootId !== 'undefined') {
        if (typeof parentId !== 'undefined') {
            if (parentId === rootId) {
                rootDescriptor = node.get('root.title') + ' / ';
            } else {
                if (node.get('parent.parent.id') === rootId) {
                    rootDescriptor = node.get('root.title') + ' / ' + node.get('parent.title') + ' / ';
                } else {
                    rootDescriptor = node.get('root.title') + ' /.../ ' + node.get('parent.title') + ' / ';
                }
            }
        } else {
            if (rootId === nodeId) {
                rootDescriptor = '';
            } else {
                rootDescriptor = node.get('root.title') + '/Private/ ';
            }
        }
    } else {
        if (typeof parentId !== 'undefined') {
            if (node.get('parent.parent.id')) {
                rootDescriptor = 'Private / ... / ' + node.get('parent.title') + ' / ';

            } else {
                rootDescriptor = 'Private / ' + node.get('parent.title') + ' / ';
            }
        } else {
            rootDescriptor = 'Private / ';
        }
    }

    return rootDescriptor + node.get('title');
}

export default Ember.Helper.helper(getAncestorDescriptor);
<|endoftext|>