elevenetc/device-manager-back-end

View on GitHub
src/utils/utils.js

Summary

Maintainability
D
1 day
Test Coverage
/**
 * Created by eugene.levenetc on 30/11/2016.
 */

const utils = require('./utils');
const OrderedMap = require('./ordered-map');

const boolFieldsMap = {
    ble: 'hasBluetoothLowEnergy',
    bt: 'hasBluetooth',
    nfc: 'hasNfc',
    online: 'isOnline',
    fingerprint: 'hasFingerprintScanner'
};

const stringFieldsMap = {
    wifi: 'wifiSSID',
    platform: 'platform',
    model: 'model',
    manufacturer: 'manufacturer',
    cpuArch: 'cpuArch'
};

const numericFieldsMap = {
    battery: 'batteryLevel',
    screenWidth: 'screenWidth',
    screenHeight: 'screenHeight',
    screenSize: 'screenSize',
    cpuCoreNum: 'cpuCoreNum'
};


exports.capitalize = function (str) {
    return str && str[0].toUpperCase() + str.slice(1);
};

exports.checkNull = function (obj, key) {
    if (obj === null || obj === undefined)
        throw new Error(`obj is undefined or null:${obj}`);
    if (!obj.hasOwnProperty(key) || obj[key] === null || obj[key] === undefined)
        throw new Error(`${key} is undefined`);
};

exports.isPropDefined = function (obj, prop) {
    return prop in obj && obj[prop] !== null && obj[prop] !== undefined;
};

exports.isDefined = function (obj) {
    return obj !== null && obj !== undefined;
};

exports.cloneArray = function (arr) {
    return arr.slice();
};

exports.isNumber = function (n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
};

exports.isString = function (value) {
    return typeof value === 'string' || value instanceof String;
};

exports.contains = function (str, value) {
    if (!this.isString(str) || !this.isString(value)) return false;
    return str.indexOf(value) >= 0;
};

exports.isDeviceValid = function (device) {
    if (!this.isDefined(device)) {
        return false;
    } else {
        return this.isPropDefined(device, 'deviceId') &&
            this.isPropDefined(device, 'pushToken') &&
            this.isPropDefined(device, 'manufacturer') &&
            this.isPropDefined(device, 'model') &&
            this.isPropDefined(device, 'osVersion') &&
            this.isPropDefined(device, 'platform') &&
            this.isPropDefined(device, 'screenSize');
    }
};

exports.isOsMatch = function (dbVersion, filterPattern) {
    return isOsMatch(dbVersion, filterPattern);
};

exports.isValidOsFilter = function (filterPattern) {
    return isValidOsFilter(filterPattern);
};

/**
 *
 * @param devices
 * @param {string} [rawFilters]
 * @return {*}
 */
exports.filterDevices = filterDevices;
exports.fixDbVersion = fixDbVersion;
exports.isNumericFilterMatch = isNumericFilterMatch;
exports.fixNumericFilter = fixNumericFilter;

function isOsMatch(dbVersion, filterPattern) {
    dbVersion = fixDbVersion(dbVersion);
    if (!utils.isDefined(filterPattern)) return false;
    if (filterPattern === '') return false;
    if (dbVersion === filterPattern) return true;
    const regex = new RegExp(filterPattern.replace(/\./g, 'V').replace(`\*`, '.{1,}'));
    dbVersion = dbVersion.replace(/\./g, 'V');
    let result = dbVersion.match(regex);
    return result !== null;
}

function isValidOsFilter(filterPattern) {
    const aPattern = /^([0-9]+)$|^\*$/;
    const abPattern = /^(([0-9]+)|\*)\.(([0-9]+)|\*)$/;
    const abcPattern = /^(([0-9]+)|\*)\.(([0-9]+)|\*)\.(([0-9]+)|\*)$/;

    const checkA = filterPattern.match(aPattern);
    const checkAB = filterPattern.match(abPattern);
    const checkABC = filterPattern.match(abcPattern);

    return checkA !== null || checkAB !== null || checkABC !== null;
}

function isNumericFilterMatch(value, filter) {

    if (!utils.isNumber(value)) return false;

    filter = fixNumericFilter(filter);
    if (filter === '') return false;
    const sign = filter.charAt(0);
    const filterValue = parseFloat(filter.slice(1));

    //TODO: add support >= and <=
    if (sign === '=') {
        return value === filterValue;
    } else if (sign === '>') {
        return value > filterValue;
    } else if (sign === '<') {
        return value < filterValue;
    } else {
        return false;
    }
}

function fixNumericFilter(filter) {

    if (!utils.isDefined(filter)) return '';
    if (filter.length === 0) return '';

    //TODO: add negative values support
    const validPattern = /^(>|<|=)(\d+\.\d+|\d+)$/;
    const isValid = filter.match(validPattern);
    if (isValid) {
        return filter;
    } else {
        const sign = filter.charAt(0);
        const hasSign = sign === '>' && sign === '<' && sign === '=';

        if (hasSign && filter.length === 1) {
            return '';
        } else {

            if (hasSign) {
                const number = filter.slice(1);
                if (utils.isNumber(number)) {
                    return filter;
                } else {
                    return '';
                }
            } else {
                if (utils.isNumber(filter)) {
                    return '=' + filter;
                } else {
                    return '';
                }
            }

        }
    }
}

function fixDbVersion(ver) {
    if (ver.length === 1) {
        return `${ver}.0.0`;
    } else if (ver.length === 3) {
        return `${ver}.0`;
    } else {
        return ver;
    }
}



function filterDevices(devices, rawFilters) {

    if (!utils.isDefined(rawFilters)) return devices;

    rawFilters = rawFilters.replace(/ /g, '');
    const filters = rawFilters.split(',');

    if (filters.length === 0) return devices;

    devices = utils.cloneArray(devices);

    for (let i = 0; i < filters.length; i++) {
        let d = devices.length;
        const fKey = filters[i].split(':')[0];
        const fValue = filters[i].split(':')[1];
        while (d--) {

            const device = devices[d];

            if (boolFieldsMap.hasOwnProperty(fKey)) {
                const devKey = boolFieldsMap[fKey];
                const filterValue = fValue === 'true';

                if (device[devKey] !== filterValue) {
                    devices.splice(d, 1);
                }
            } else if (stringFieldsMap.hasOwnProperty(fKey)) {
                const devKey = stringFieldsMap[fKey];

                const devValue = device[devKey].toLowerCase().replace(/ /g, '');
                const queryValue = fValue.toLowerCase();

                if(devValue.indexOf(queryValue) === -1 && queryValue.indexOf(devValue) === -1){
                    devices.splice(d, 1);
                }

            } else if (numericFieldsMap.hasOwnProperty(fKey)) {
                const devKey = numericFieldsMap[fKey];

                if (!isNumericFilterMatch(device[devKey], fValue)) {
                    devices.splice(d, 1);
                }

            } else if (fKey === 'os' && isValidOsFilter(fValue) && !isOsMatch(device.osVersion, fValue)) {
                devices.splice(d, 1);
            }
        }
    }

    return devices;
}