Home Manual Reference Source Test Repository

src/bundles/deployment/DeploymentElement.js

'use strict';

import {
    OPERATION_ENUM
} from './OPERATION_ENUM';
import {
    OPTION_ENUM
} from './OPTION_ENUM';
import {
    TYPE_ENUM
} from './TYPE_ENUM';
import {
    TYPE_VALIDATORS_ENUM
} from './TYPE_VALIDATORS_ENUM';
import {
    MODE_VALIDATORS_ENUM
} from './MODE_VALIDATORS_ENUM';

import q from 'q';
import BaseProvision from '../../provision/BaseProvision';

/**
 * This is a base object that contains all you can do about Deployment Element.
 */
export default class DeploymentElement extends BaseProvision {
    constructor(context, ogapi, url, progressEvent) {
        super(ogapi, url + "/deploymentElements");
        this._progressEvent = progressEvent;

        this._resource = url + "/deploymentElements";
        this.validation = false;
        this._name = undefined;
        this._version = undefined;
        this._type = undefined;
        this._path = undefined;
        this._order = undefined;
        this._operation = undefined;
        this._option = undefined;
        this._fileName = undefined;
        this._downloadUrl = undefined;
        this._validators = undefined;
        this._oldName = undefined;
        this._oldVersion = undefined;
        this._oldPath = undefined;
    }

    /**
     * Set the name attribute
     * @param {string} name - required field
     * @return {DeploymentElement}
     */
    withName(name) {
        if (typeof name !== 'string' || name.length > 50)
            throw new Error({
                message: "OGAPI_STRING_PARAMETER_MAX_LENGTH_50",
                parameter: 'name'
            });
        this._name = name;
        return this;
    }

    /**
     * Set the version attribute
     * @param {string} version - required field
     * @return {DeploymentElement}
     */
    withVersion(version) {
        if (typeof version !== 'string' || version.length > 50)
            throw new Error({
                message: "OGAPI_STRING_PARAMETER_MAX_LENGTH_50",
                parameter: 'version'
            });
        this._version = version;
        return this;
    }

    /**
     * Set the type attribute
     * @param {string} type - required field
     * @return {DeploymentElement}
     */
    withType(type) {
        if (typeof type === "undefined" || typeof type !== 'string') {
            throw new Error({
                message: 'OGAPI_STRING_PARAMETER',
                parameter: 'type'
            });
        }
        let not_found = '';
        let found = TYPE_ENUM.find(function(action) {
            return action == this;
        }, type);
        if (typeof found === "undefined") {
            not_found = type;
        }

        if (not_found !== '') {
            throw new Error({
                message: "OGAPI_NOT_ALLOWED_PARAMETER",
                parameter: JSON.stringify(not_found),
                allowed: JSON.stringify(TYPE_ENUM)
            });

        }
        this._type = type;
        return this;
    }

    /**
     * Set the path attribute
     * @param {string} path - required field
     * @return {DeploymentElement}
     */
    withPath(path) {
        if (typeof path !== 'string')
            throw new Error({
                message: 'OGAPI_STRING_PARAMETER',
                parameter: 'path'
            });
        this._path = path;
        return this;
    }

    /**
     * Set the order attribute
     * @param {string} order - required field
     * @return {DeploymentElement}
     */
    withOrder(order) {
        /*if (typeof order !== 'string')
            throw new Error('Parameter order must be a string');*/
        this._order = order;
        return this;
    }

    /**
     * Set the operation attribute
     * @param {string} operation - required field
     * @return {DeploymentElement}
     */
    withOperation(operation) {
        if (typeof operation === "undefined" || typeof operation !== 'string') {
            throw new Error({
                message: "OGAPI_STRING_PARAMETER",
                parameter: "operation"
            });
        }

        let not_found = '';
        let found = OPERATION_ENUM.find(function(operation) {
            return operation == this;
        }, operation);

        if (typeof found === "undefined") {
            not_found = operation;
        }

        if (not_found !== '') {
            throw new Error("Parameter operation is not allowed. Parameter value <'" +
                JSON.stringify(not_found) + "'>, operation allowed <'" + JSON.stringify(OPERATION_ENUM) + "'>");
        }
        this._operation = operation;
        return this;
    }

    /**
     * Set the option attribute
     * @param {string} option 
     * @return {DeploymentElement}
     */
    withOption(option) {
        if (typeof option === "undefined" || typeof option !== 'string') {
            throw new Error({
                message: "OGAPI_STRING_PARAMETER",
                parameter: "option"
            });
        }

        let not_found = '';
        let found = OPTION_ENUM.find(function(option) {
            return option == this;
        }, option);
        if (typeof found === "undefined") {
            not_found = option;
        }

        if (not_found !== '') {
            throw new Error("Parameter option is not allowed. Parameter value <'" +
                JSON.stringify(not_found) + "'>, option allowed <'" + JSON.stringify(OPTION_ENUM) + "'>");
        }
        this._option = option;
        return this;
    }

    /**
     * Set the validators attribute
     * @param {Array} validators 
     * @return {DeploymentElement}
     */
    withValidators(validators) {
        let validator = {};
        let validatorsArray = [];

        if (typeof validators === "undefined" || validators.constructor !== Array) {
            throw new Error("Parameter validators must be typeof Array");
        }

        // Validar si los validators son correctos, solo se permite un firmware

        let trustedBootExists = false;
        for (var i = 0; i < validators.length; i++) {
            validator = this._checkValidator(validators[i]);

            if (validator.mode === 'TRUSTED_BOOT') {
                if (!trustedBootExists) {
                    trustedBootExists = true;
                } else {
                    throw new Error("OGAPI_422_ONE_TRUSTED_BOOT_ALLOWED_DEPLOY_ELEMENT");
                }
            }
            validatorsArray.push(validator);
        }
        this._validators = validatorsArray;


        return this;
    }

    _checkValidator(validator) {

        let validatorElement = {};

        if (validator.mode) {
            let not_found = '';
            let mode = validator.mode;

            if (typeof mode === "undefined" || typeof mode !== 'string') {
                throw new Error({
                    message: "OGAPI_STRING_PARAMETER",
                    parameter: "type"
                });
            }

            let foundMode = MODE_VALIDATORS_ENUM.find(function(action) {
                return action == this;
            }, mode);

            if (typeof foundMode === "undefined") {
                not_found = mode;
            }

            if (not_found !== '') {
                throw new Error("Parameter type is not allowed. Parameter value <'" +
                    JSON.stringify(not_found) + "'>, type allowed <'" + JSON.stringify(MODE_VALIDATORS_ENUM) + "'>");
            }

            // Se valida que TRUSTED_BOOT sea sólo para firmwares
            if (mode !== 'TRUSTED_BOOT' || (mode === 'TRUSTED_BOOT' && this._type === 'FIRMWARE')) {
                validatorElement.mode = mode;
            } else {
                throw new Error("TRUSTED_BOOT validator only allowed for FIRMWARE deployment element");
            }
        } else {
            // por defecto se pone el primero de la lista
            validatorElement.mode = MODE_VALIDATORS_ENUM[0];
        }


        // Type es obligatorio
        if (validator.type) {
            let not_found = '';
            let type = validator.type;
            if (typeof type === "undefined" || typeof type !== 'string') {
                throw new Error({
                    message: "OGAPI_STRING_PARAMETER",
                    parameter: "type"
                });
            }

            let found = TYPE_VALIDATORS_ENUM.find(function(action) {
                return action == this;
            }, type);

            if (typeof found === "undefined") {
                not_found = type;
            }

            if (not_found !== '') {
                throw new Error("Parameter type is not allowed. Parameter value <'" +
                    JSON.stringify(not_found) + "'>, type allowed <'" + JSON.stringify(TYPE_VALIDATORS_ENUM) + "'>");
            }

            validatorElement.type = type;
        } else {
            throw new Error("Parameter type is required");
        }

        // si el validador es el primero de la lista (PLATFORM)
        if (validatorElement.mode === MODE_VALIDATORS_ENUM[0]) {
            if (validator.value) {
                let value = validator.value;
                if (typeof value !== 'string')
                    throw new Error('Parameter value must be a string');

                validatorElement.value = value;
            } else {
                throw new Error("Parameter value is required when mode is " + MODE_VALIDATORS_ENUM[0]);
            }
        }


        return validatorElement;

    }

    /**
     * Set the downloadUrl attribute
     * @param {string} downloadUrl 
     * @return {DeploymentElement}
     */
    withDownloadUrl(downloadUrl) {
        if (typeof downloadUrl !== 'string')
            throw new Error('Parameter downloadUrl must be a string');
        this._downloadUrl = downloadUrl;
        return this;
    }

    /**
     * Set the fileName attribute
     * @param {string} fileName 
     * @return {DeploymentElement}
     */
    withFileName(fileName) {
        if (typeof fileName !== 'string')
            throw new Error('Parameter fileName must be a string');
        this._fileName = fileName;
        return this;
    }

    /**
     * Set the validation attribute
     * @param {string} validation 
     * @return {DeploymentElement}
     */
    withValidation(validation) {
        if (typeof validation !== 'boolean')
            throw new Error('Parameter validation must be a boolean');
        this.validation = validation;
        return this;
    }

    /**
     * Sets the old name attribute
     * @param {string} name 
     * @return {DeploymentElement}
     */
    withOldName(name) {
        if (typeof name !== 'string')
            throw new Error('Parameter old name must be a string');
        this._oldName = name;
        return this;
    }

    /**
     * Sets the old version attribute
     * @param {string} version 
     * @return {DeploymentElement}
     */
    withOldVersion(version) {
        if (typeof version !== 'string')
            throw new Error('Parameter old version must be a string');
        this._oldVersion = version;
        return this;
    }

    /**
     * Sets the old path attribute
     * @param {string} path 
     * @return {DeploymentElement}
     */
    withOldPath(path) {
        if (typeof path !== 'string')
            throw new Error('Parameter old path must be a string');
        this._oldPath = path;
        return this;
    }

    /**
     * Sets the file to upload
     * @param {object} rawFile 
     * @return {DeploymentElement}
     */
    withFile(rawFile) {
        this._rawFile = rawFile;
        return this;
    }

    /**
     * @return {String} This returns a json with the element for create a deployment element.
     * @private
     */
    _composeUrlCreate() {
        if (this._name === undefined || this._version === undefined ||
            this._name === '' || this._version === '')
            throw new Error('Method not allowed - You must to define the name and version');
        this._setUrlParameters({
            fileValidationRequired: this.validation
        });
        return this._resource;
    }

    _composeElement() {
        if (this._operation === 'UPGRADE') {
            if (this._name === undefined || this._version === undefined || this._type === undefined ||
                this._path === undefined || this._order === undefined || this._operation === undefined ||
                this._oldName === undefined || this._oldVersion === undefined || this._oldPath === undefined)
                throw new Error('Method not allowed - You must define the basic element [name, version, type, path, order, operation, oldName, oldVersion and oldPath ]');

        } else if (this._name === undefined || this._version === undefined || this._type === undefined ||
            this._path === undefined || this._order === undefined || this._operation === undefined || this._option === undefined)
            throw new Error('Method not allowed - You must define the basic element [name, version, type, path, order, option and operation]');
        var meta = {
            deploymentElement: {
                name: this._name || undefined,
                version: this._version || undefined,
                type: this._type || undefined,
                path: this._path || undefined,
                order: this._order || undefined,
                operation: this._operation || undefined,
                option: this._option || undefined,
                fileName: this._fileName || undefined,
                downloadUrl: this._downloadUrl || undefined,
                validators: this._validators || undefined,
                oldName: this._oldName || undefined,
                oldVersion: this._oldVersion || undefined,
                oldPath: this._oldPath || undefined
            }
        };
        return meta;
    }


    /**
     * The request will have a specific time out if it will be exceeded then the promise throw an exception
     * @param {number} ms - timeout in milliseconds    
     * @return {Bundles} 
     */
    withTimeout(ms) {
        if (typeof ms !== "number") throw new Error('Parameter ms must be a number');
        this._timeout = ms;
        return this;
    }

    _buildURL() {
        if (this._name === undefined || this._version === undefined)
            throw new Error('Parameters name, version must be defined');
        return this._resource + "/" + this._name + "/version/" + this._version;
    }


    /**
     * This invoke a request to OpenGate North API and the callback is managed by promises
     * This method create an element deploymentElement
     * @param {File} rawFile - this File is the deployment element
     * @property {function (result:object, statusCode:number)} then - When request it is OK
     * @property {function (error:string)} catch - When request it is NOK
     * @return {Promise}     
     */
    createWithFile(rawFile) {
        let form;
        if (typeof rawFile !== 'string') {
            form = new FormData();
            let blob = new Blob([JSON.stringify(this._composeElement())], {
                type: "application/octet-stream"
            });

            form.append('meta', blob);

            if (rawFile) {
                form.append('file', rawFile);
            }
        } else {
            form = {};
            form.meta = JSON.stringify(this._composeElement());

            if (rawFile) {
                form.file = rawFile;
            }
        }

        var petitionOpts = {};

        if (this._progressEvent != undefined) {
            petitionOpts = {
                'progress': this._progressEvent
            };
        }

        var defered = q.defer();
        var promise = defered.promise;

        this._ogapi.Napi.post_multipart(this._composeUrlCreate(), form, petitionOpts, this._timeout, this._getExtraHeaders(), this._getUrlParameters())
            .then((res) => {
                if (res.statusCode === 201) {
                    defered.resolve({
                        location: res.header.location,
                        statusCode: res.statusCode
                    });
                } else {
                    defered.reject({
                        "errors": [{
                            code: res.statusCode,
                            message: "OGAPI_FILE_NOT_CREATE"
                        }],
                        "statusCode": res.statusCode
                    });
                }
            })
            .catch((error) => {
                defered.reject(error);
            });

        return promise;
    }

    /**
     * This invoke a request to OpenGate North API and the callback is managed by promises
     * This method create an element deploymentElement with previously assignated file
     * @property {function (result:object, statusCode:number)} then - When request it is OK
     * @property {function (error:string)} catch - When request it is NOK
     * @return {Promise}     
     */
    deploy() {
        return this.createWithFile(this._rawFile);
    }

    /**
     * This method invalidates the update option
     * @throws {Allways} Deployment elements cannot be updated.
     */
    update() {
        throw new Error("OGAPI_DEPLOYMENT_ELEMENT_NOT_UPDATED");
    }
}