<commit_before>/*
 * Copyright 2014 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 ONOS GUI -- Key Handler Service - Unit Tests

 @author Simon Hunt
 */
describe('factory: fw/lib/keys.js', function() {
    var ks, fs, d3Elem, elem, last,
        mockLog;

    beforeEach(module('onosApp'));

    // create mock log to verify warning was logged
    beforeEach(module(function($provide) {
        mockLog = {
            warn: function (msg) {
                mockLog._last.warn = msg;
            },
            _last: {},
            _check: function (which) {
                // destructive read
                var m = mockLog._last[which];
                mockLog._last[which] = null;
                return m;
            }
        };
        // tell angular to provide our mock, when '$log' service is requested
        $provide.value('$log', mockLog);
    }));

    beforeEach(inject(function (KeyService, FnService) {
        ks = KeyService;
        fs = FnService;
        d3Elem = d3.select('body').append('p').attr('id', 'ptest');
        elem = d3Elem.node();
        ks.installOn(d3Elem);
        last = {
            view: null,
            key: null,
            code: null,
            ev: null
        };
    }));

    afterEach(function () {
        d3.select('#ptest').remove();
    });

    it('should have injected stuff defined', function () {
        expect(ONOS).toBeDefined();
        expect(ks).toBeDefined();
        expect(fs).toBeDefined();
    });

    // NOTE: kinda messy, but it seems to get the job done.
    function jsKeyDown(element, code) {
        var ev = document.createEvent('KeyboardEvent');

        // Chromium Hack
        if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
            Object.defineProperty(ev, 'keyCode', {
                get: function () { return this.keyCodeVal; }
            });
            Object.defineProperty(ev, 'which', {
                get: function () { return this.keyCodeVal; }
            });
        }

        if (ev.initKeyboardEvent) {
            ev.initKeyboardEvent('keydown', true, true, document.defaultView,
                                false, false, false, false, code, code);
        } else {
            ev.initKeyEvent('keydown', true, true, document.defaultView,
                            false, false, false, false, code, 0);
        }

        ev.keyCodeVal = code;

        if (ev.keyCode !== code) {
            console.warn("keyCode mismatch " + ev.keyCode +
                        "(" + ev.which + ") -> "+ code);
        }
        element.dispatchEvent(ev);
    }

    // === Theme related tests
    it('should start in light theme', function () {
        expect(ks.theme()).toEqual('light');
    });
    it('should toggle to dark theme', function () {
        jsKeyDown(elem, 84); // 'T'
        expect(ks.theme()).toEqual('dark');
    });

    // === Key binding related tests
    it('should start with default key bindings', function () {
        var state = ks.keyBindings(),
            gk = state.globalKeys,
            mk = state.maskedKeys,
            vk = state.viewKeys,
            vf = state.viewFunction;

        expect(gk.length).toEqual(4);
        ['backSlash', 'slash', 'esc', 'T'].forEach(function (k) {
            expect(fs.contains(gk, k)).toBeTruthy();
        });

        expect(mk.length).toEqual(3);
        ['backSlash', 'slash', 'T'].forEach(function (k) {
            expect(fs.contains(mk, k)).toBeTruthy();
        });

        expect(vk.length).toEqual(0);
        expect(vf).toBeFalsy();
    });

    function bindTestKeys(withDescs) {
        var keys = ['A', '1', 'F5', 'equals'],
            kb = {};

        function cb(view, key, code, ev) {
            last.view = view;
            last.key = key;
            last.code = code;
            last.ev = ev;
        }

        function bind(k) {
            return withDescs ? [cb, 'desc for key ' + k] : cb;
        }

        keys.forEach(function (k) {
            kb[k] = bind(k);
        });

        ks.keyBindings(kb);
    }

    function verifyCall(key, code) {
        // TODO: update expectation, when view tokens are implemented
        expect(last.view).toEqual('NotYetAViewToken');
        last.view = null;

        expect(last.key).toEqual(key);
        last.key = null;

        expect(last.code).toEqual(code);
        last.code = null;

        expect(last.ev).toBeTruthy();
        last.ev = null;
    }

    function verifyNoCall() {
        expect(last.view).toBeNull();
        expect(last.key).toBeNull();
        expect(last.code).toBeNull();
        expect(last.ev).toBeNull();
    }

    function verifyTestKeys() {
        jsKeyDown(elem, 65); // 'A'
        verifyCall('A', 65);
        jsKeyDown(elem, 66); // 'B'
        verifyNoCall();

        jsKeyDown(elem, 49); // '1'
        verifyCall('1', 49);
        jsKeyDown(elem, 50); // '2'
        verifyNoCall();

        jsKeyDown(elem, 116); // 'F5'
        verifyCall('F5', 116);
        jsKeyDown(elem, 117); // 'F6'
        verifyNoCall();

        jsKeyDown(elem, 187); // 'equals'
        verifyCall('equals', 187);
        jsKeyDown(elem, 189); // 'dash'
        verifyNoCall();

        var vk = ks.keyBindings().viewKeys;

        expect(vk.length).toEqual(4);
        ['A', '1', 'F5', 'equals'].forEach(function (k) {
            expect(fs.contains(vk, k)).toBeTruthy();
        });

        expect(ks.keyBindings().viewFunction).toBeFalsy();
    }

    it('should allow specific key bindings', function () {
        bindTestKeys();
        verifyTestKeys();
    });

    it('should allow specific key bindings with descriptions', function () {
        bindTestKeys(true);
        verifyTestKeys();
    });

    it('should warn about masked keys', function () {
        var k = {'space': cb, 'T': cb},
            count = 0;
        function cb() { count++; }

        ks.keyBindings(k);

        expect(mockLog._check('warn'))
            .toEqual('setKeyBindings(): Key "T" is reserved');

        // the 'T' key should NOT invoke our callback
        expect(count).toEqual(0);
        jsKeyDown(elem, 84); // 'T'
        expect(count).toEqual(0);

        // but the 'space' key SHOULD invoke our callback
        jsKeyDown(elem, 32); // 'space'
        expect(count).toEqual(1);
    });

    // === Gesture notes related tests
    it('should start with no notes', function () {
        expect(ks.gestureNotes()).toEqual([]);
    });

    it('should allow us to add nodes', function () {
        var notes = [
            ['one', 'something about one'],
            ['two', 'description of two']
        ];
        ks.gestureNotes(notes);

        expect(ks.gestureNotes()).toEqual(notes);
    });

    it('should ignore non-arrays', function () {
        ks.gestureNotes({foo:4});
        expect(ks.gestureNotes()).toEqual([]);
    });

    // Consider adding test to ensure array contains 2-tuples of strings
});
<commit_msg>GUI -- refactored key service test to spy on $log service, instead of implementing our own mock.<commit_after>/*
 * Copyright 2014 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 ONOS GUI -- Key Handler Service - Unit Tests

 @author Simon Hunt
 */
describe('factory: fw/lib/keys.js', function() {
    var ks, fs, $log,
        d3Elem, elem, last;

    beforeEach(module('onosApp'));

    beforeEach(inject(function (KeyService, FnService, _$log_) {
        $log = _$log_;
        ks = KeyService;
        fs = FnService;
        d3Elem = d3.select('body').append('p').attr('id', 'ptest');
        elem = d3Elem.node();
        ks.installOn(d3Elem);
        last = {
            view: null,
            key: null,
            code: null,
            ev: null
        };
    }));

    afterEach(function () {
        d3.select('#ptest').remove();
    });

    it('should have injected stuff defined', function () {
        expect(ONOS).toBeDefined();
        expect(ks).toBeDefined();
        expect(fs).toBeDefined();
    });

    // NOTE: kinda messy, but it seems to get the job done.
    function jsKeyDown(element, code) {
        var ev = document.createEvent('KeyboardEvent');

        // Chromium Hack
        if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
            Object.defineProperty(ev, 'keyCode', {
                get: function () { return this.keyCodeVal; }
            });
            Object.defineProperty(ev, 'which', {
                get: function () { return this.keyCodeVal; }
            });
        }

        if (ev.initKeyboardEvent) {
            ev.initKeyboardEvent('keydown', true, true, document.defaultView,
                                false, false, false, false, code, code);
        } else {
            ev.initKeyEvent('keydown', true, true, document.defaultView,
                            false, false, false, false, code, 0);
        }

        ev.keyCodeVal = code;

        if (ev.keyCode !== code) {
            console.warn("keyCode mismatch " + ev.keyCode +
                        "(" + ev.which + ") -> "+ code);
        }
        element.dispatchEvent(ev);
    }

    // === Theme related tests
    it('should start in light theme', function () {
        expect(ks.theme()).toEqual('light');
    });
    it('should toggle to dark theme', function () {
        jsKeyDown(elem, 84); // 'T'
        expect(ks.theme()).toEqual('dark');
    });

    // === Key binding related tests
    it('should start with default key bindings', function () {
        var state = ks.keyBindings(),
            gk = state.globalKeys,
            mk = state.maskedKeys,
            vk = state.viewKeys,
            vf = state.viewFunction;

        expect(gk.length).toEqual(4);
        ['backSlash', 'slash', 'esc', 'T'].forEach(function (k) {
            expect(fs.contains(gk, k)).toBeTruthy();
        });

        expect(mk.length).toEqual(3);
        ['backSlash', 'slash', 'T'].forEach(function (k) {
            expect(fs.contains(mk, k)).toBeTruthy();
        });

        expect(vk.length).toEqual(0);
        expect(vf).toBeFalsy();
    });

    function bindTestKeys(withDescs) {
        var keys = ['A', '1', 'F5', 'equals'],
            kb = {};

        function cb(view, key, code, ev) {
            last.view = view;
            last.key = key;
            last.code = code;
            last.ev = ev;
        }

        function bind(k) {
            return withDescs ? [cb, 'desc for key ' + k] : cb;
        }

        keys.forEach(function (k) {
            kb[k] = bind(k);
        });

        ks.keyBindings(kb);
    }

    function verifyCall(key, code) {
        // TODO: update expectation, when view tokens are implemented
        expect(last.view).toEqual('NotYetAViewToken');
        last.view = null;

        expect(last.key).toEqual(key);
        last.key = null;

        expect(last.code).toEqual(code);
        last.code = null;

        expect(last.ev).toBeTruthy();
        last.ev = null;
    }

    function verifyNoCall() {
        expect(last.view).toBeNull();
        expect(last.key).toBeNull();
        expect(last.code).toBeNull();
        expect(last.ev).toBeNull();
    }

    function verifyTestKeys() {
        jsKeyDown(elem, 65); // 'A'
        verifyCall('A', 65);
        jsKeyDown(elem, 66); // 'B'
        verifyNoCall();

        jsKeyDown(elem, 49); // '1'
        verifyCall('1', 49);
        jsKeyDown(elem, 50); // '2'
        verifyNoCall();

        jsKeyDown(elem, 116); // 'F5'
        verifyCall('F5', 116);
        jsKeyDown(elem, 117); // 'F6'
        verifyNoCall();

        jsKeyDown(elem, 187); // 'equals'
        verifyCall('equals', 187);
        jsKeyDown(elem, 189); // 'dash'
        verifyNoCall();

        var vk = ks.keyBindings().viewKeys;

        expect(vk.length).toEqual(4);
        ['A', '1', 'F5', 'equals'].forEach(function (k) {
            expect(fs.contains(vk, k)).toBeTruthy();
        });

        expect(ks.keyBindings().viewFunction).toBeFalsy();
    }

    it('should allow specific key bindings', function () {
        bindTestKeys();
        verifyTestKeys();
    });

    it('should allow specific key bindings with descriptions', function () {
        bindTestKeys(true);
        verifyTestKeys();
    });

    it('should warn about masked keys', function () {
        var k = {'space': cb, 'T': cb},
            count = 0;

        function cb() { count++; }

        spyOn($log, 'warn');

        ks.keyBindings(k);

        expect($log.warn).toHaveBeenCalledWith('setKeyBindings(): Key "T" is reserved');

        // the 'T' key should NOT invoke our callback
        expect(count).toEqual(0);
        jsKeyDown(elem, 84); // 'T'
        expect(count).toEqual(0);

        // but the 'space' key SHOULD invoke our callback
        jsKeyDown(elem, 32); // 'space'
        expect(count).toEqual(1);
    });

    // === Gesture notes related tests
    it('should start with no notes', function () {
        expect(ks.gestureNotes()).toEqual([]);
    });

    it('should allow us to add nodes', function () {
        var notes = [
            ['one', 'something about one'],
            ['two', 'description of two']
        ];
        ks.gestureNotes(notes);

        expect(ks.gestureNotes()).toEqual(notes);
    });

    it('should ignore non-arrays', function () {
        ks.gestureNotes({foo:4});
        expect(ks.gestureNotes()).toEqual([]);
    });

    // Consider adding test to ensure array contains 2-tuples of strings
});
<|endoftext|>


<commit_before>const Subiex = require('../bot.js')

Subiex.registerCommand('dm', 'moderator', (message, bot) => {
    let isDM = message.channel.type === 1
    console.log("it is a dm message")
    let myChannel = message.mentions.channels.array()[0]
    let deleteMessage = message.guild.member(bot.user).hasPermission('MANAGE_MESSAGES')
    if (myChannel === undefined) {
        if (deleteMessage) message.delete()
        return ('Please mention a #channel so I know where to speak!')
    }

    let msg = message.content.replace(myChannel.id, '').replace('<#>', '')
    let channel = message.guild.channels.find('name', myChannel.name)

    let channel = message.guild.channels.find('name', myChannel.name)

    // if (myMention !== undefined) {
    //     msg = msg.replace(myMention.id, '').replace('<@>', '')
    //     msg = msg.replace('<@!>', '') // If user has a nickname
    // } else { myMention = '' }

    // if (deleteMessage) message.delete()
    // if (msg === '') return "The message can't be empty!"

    // channel.send(myMention + msg)
    searchUser(message, message.content)
}, ['pm', 'direct'], 'Make the bot speak to a given channel', '[to channel] <to member> [message]')

function searchUser(message) {
    let textInDQuotes = extractFirstText(message.content).trim()
    let name = message.content.replace('"' + textInDQuotes + '"', '').trim()

    var receiver_id = "";
    if (message.mentions.members.size != 0) {
        receiver_id = args[0].replace("<@", "");
        receiver_id = receiver_id.replace(">", "");
        receiver_id = receiver_id.replace("!", ""); // if user has username
    } else {
        for (var entry of message.guild.members.entries()) {
            if (entry[1].user.bot) { continue; }
            if (entry[1].nickname != null && entry[1].nickname.toLowerCase().includes(name.toLowerCase())) {
                receiver_id = entry[0];

                return receiver_id;
                break;
            }
            if (entry[1].user.tag.toLowerCase().includes(name.toLowerCase())) {
                receiver_id = entry[0];

                return receiver_id;
                break;
            }
        }
    }
}

function extractFirstText(str) {
    const matches = str.match(/"(.*?)"/);
    return matches ?
        matches[1] :
        str;
}<commit_msg>working on new command [dm.js]<commit_after>const Subiex = require('../bot.js')

Subiex.registerCommand('dm', 'moderator', (message, bot) => {
    let isDM = message.channel.type === 1
    console.log("it is a dm message")
    // let myChannel = message.mentions.channels.array()[0]
    // let deleteMessage = message.guild.member(bot.user).hasPermission('MANAGE_MESSAGES')
    // if (myChannel === undefined) {
        // if (deleteMessage) message.delete()
        // return ('Please mention a #channel so I know where to speak!')
    // }

    // let msg = message.content.replace(myChannel.id, '').replace('<#>', '')
    // let channel = message.guild.channels.find('name', myChannel.name)

    // let channel = message.guild.channels.find('name', myChannel.name)

    // if (myMention !== undefined) {
    //     msg = msg.replace(myMention.id, '').replace('<@>', '')
    //     msg = msg.replace('<@!>', '') // If user has a nickname
    // } else { myMention = '' }

    // if (deleteMessage) message.delete()
    // if (msg === '') return "The message can't be empty!"

    // channel.send(myMention + msg)
    searchUser(message, message.content)
}, ['pm', 'direct'], 'Make the bot speak to a given channel', '[to channel] <to member> [message]')

function searchUser(message) {
    let textInDQuotes = extractFirstText(message.content).trim()
    let name = message.content.replace('"' + textInDQuotes + '"', '').trim()

    var receiver_id = "";
    if (message.mentions.members.size != 0) {
        receiver_id = args[0].replace("<@", "");
        receiver_id = receiver_id.replace(">", "");
        receiver_id = receiver_id.replace("!", ""); // if user has username
    } else {
        for (var entry of message.guild.members.entries()) {
            if (entry[1].user.bot) { continue; }
            if (entry[1].nickname != null && entry[1].nickname.toLowerCase().includes(name.toLowerCase())) {
                receiver_id = entry[0];

                return receiver_id;
                break;
            }
            if (entry[1].user.tag.toLowerCase().includes(name.toLowerCase())) {
                receiver_id = entry[0];

                return receiver_id;
                break;
            }
        }
    }
}

function extractFirstText(str) {
    const matches = str.match(/"(.*?)"/);
    return matches ?
        matches[1] :
        str;
}<|endoftext|>


<commit_before>var Bluemold = require( "./../lib/" ).Bluemold;
var a = require( "assert" );

var tpl1 = "
${a}
",
    tpl2 = "
{{= a}}
",
    tpl3 = "
${$data.a}
",
    tpl4 = "
${$item.data.a}
",
    tpl5 = "
${$item.someFunction()}
",
    tpl6 = "{{html a}}",
    tpl9 = "{{if a == 1}}
${a}
{{/if}}",
    tpl11 = "{{if a == 1}}
${a}
{{else}}2{{/if}}",
    tpl12 = "{{if a == 1}}
${a}
{{else a==2 }}2{{else}}3{{/if}}";

// "template" method

function equals(actual,expected,message){
  describe(message, function(){
    it("should work", function(){
      expect(actual).toEqual(expected);
    });
  });
}

function pending(actual,expected,message){
  describe(message, function(){
    it("may eventually work", function(){
      //expect(actual).toEqual(expected);
    });
  });
}

equals( Bluemold(tpl2, {a:1}), "
1
", "use simple data object, using {{= }} in the template " );
pending( Bluemold(tpl1, [{a:1}]), "
1
", "use an array with one object element" );
pending( Bluemold(tpl2, [{a:1}]), "
1
", "use an array with one object element, using {{= }} in the template" );
pending( Bluemold(tpl1, [{a:1},{a:2}]), "
1

2
", "use an array with 2 objects" );
equals( Bluemold(tpl1, {a: function(){return 1;}}), "
1
", "use function as a value" );
// equals( Bluemold(tpl1,{a:'
2
'}), "
<div id="123">2</div>
", "escaping per default" );

// local variables
equals( Bluemold(tpl3, {a:1}), "
1
", "test access to $data" );
pending( Bluemold(tpl4, {a:1}), "
1
", "test access to $item" );
pending( Bluemold(tpl5, null, {someFunction: function() {return 1;}}), "
1
", "test access to $item" );

// ${html}
equals( Bluemold(tpl6,{a:'
2
'}), '
2
', 'output html without escaping');

// ${if}
equals( Bluemold(tpl9,{a:1}), "
1
", "test 'if' when true" );
equals( Bluemold(tpl9,{a:2}), "", "test 'if' when false" );

// ${else}
equals( Bluemold(tpl11,{a:1}), "
1
", "test else when true" );
equals( Bluemold(tpl11,{a:2}), "2", "test else when false" );
equals( Bluemold(tpl12,{a:2}), "2", "test else =2" );
equals( Bluemold(tpl12,{a:3}), "3", "test else =3" );

// {{each}}
equals(
    Bluemold(
        "{{each(index, value) names}}
${index}.${value}
{{/each}}",
        {names: ["A", "B"]}
    ),
    "
0.A

1.B
", "test 'each', use index and value, explizitely mapping them "
);
equals(
    Bluemold(
        "{{each names}}
${$index}.${$value}
{{/each}}",
        {names: ["A", "B"]}
    ),
    "
0.A

1.B
", "test 'each', use index and name with auto mapping"
);
equals(
    Bluemold(
        "{{each getData()}}
${$value}
{{/each}}",
        {
            getData: function(){
                return [1,2,3];
            }
        }
    ),
    "
1

2

3
", "test 'each', using templates variables"
);
equals(
    Bluemold(
        "{{each data }}
${$value}
{{/each}}",
        {
            data: {1:1, 2:2, 3:3}
        }
    ),
    "
1

2

3
",
    "iterate over json in each loop"
);

// {{tmpl}}
pending(
    Bluemold(
        "{{tmpl(data) extTpl}}",
        {
            extTpl: "
${a}
",
            data: {a:123456}
        }
    ),
    "
123456
",
    "include template {{tmpl}}"
);

/*
// {{wrap}}

var tpl1 =
    '{{wrap "#tableWrapper"}}\

\
            First content\

\

\
            And more content...\

\
    {{/wrap}}';

var tpl2 =
    '

\

\
            {{each $item.html("div")}}\
                \
                    {{html $value}}\
                	\
            {{/each}}\

\

';

jte.template( "#tableWrapper", tpl2 );
console.log(Bluemold(tpl1));
*/

// {{!}}
equals( Bluemold("
{{! its a comment}}
", {a:1}), "

", "comments work" );
<commit_msg>removed old test file<commit_after><|endoftext|>


<commit_before>// Copyright 2014 CloudFounders NV
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*global define, window */
define([
    'jquery', 'durandal/app', 'plugins/dialog', 'knockout',
    'ovs/shared', 'ovs/generic', 'ovs/refresher', 'ovs/api',
    '../containers/vmachine', '../containers/vpool', '../wizards/rollback/index', '../wizards/snapshot/index'
], function($, app, dialog, ko, shared, generic, Refresher, api, VMachine, VPool, RollbackWizard, SnapshotWizard) {
    "use strict";
    return function() {
        var self = this;

        // System
        self.shared      = shared;
        self.guard       = { authenticated: true };
        self.refresher   = new Refresher();
        self.widgets     = [];
        self.updateSort  = false;
        self.sortTimeout = undefined;

        // Data
        self.vMachineHeaders = [
            { key: 'name',         value: $.t('ovs:generic.name'),       width: 150       },
            { key: 'vpool',        value: $.t('ovs:generic.vpool'),      width: 150       },
            { key: 'vsa',          value: $.t('ovs:generic.vsa'),        width: 150       },
            { key: undefined,      value: $.t('ovs:generic.vdisks'),     width: 60        },
            { key: 'storedData',   value: $.t('ovs:generic.storeddata'), width: 110       },
            { key: 'cacheRatio',   value: $.t('ovs:generic.cache'),      width: 100       },
            { key: 'iops',         value: $.t('ovs:generic.iops'),       width: 55        },
            { key: 'readSpeed',    value: $.t('ovs:generic.read'),       width: 100       },
            { key: 'writeSpeed',   value: $.t('ovs:generic.write'),      width: 100       },
            { key: 'failoverMode', value: $.t('ovs:generic.focstatus'),  width: undefined },
            { key: undefined,      value: $.t('ovs:generic.actions'),    width: 100       }
        ];
        self.vMachines = ko.observableArray([]);
        self.vPoolCache = {};
        self.vsaCache = {};
        self.vMachinesInitialLoad = ko.observable(true);

        // Variables
        self.loadVMachinesHandle = undefined;

        // Functions
        self.fetchVMachines = function(full) {
            full = full || false;
            return $.Deferred(function(deferred) {
                if (generic.xhrCompleted(self.loadVMachinesHandle)) {
                    var query = {
                            query: {
                                type: 'AND',
                                items: [['is_internal', 'EQUALS', false],
                                        ['is_vtemplate', 'EQUALS', false],
                                        ['status', 'NOT_EQUALS', 'CREATED']]
                            }
                        }, filter = {};
                    if (full) {
                        filter.full = true;
                    }
                    self.loadVMachinesHandle = api.post('vmachines/filter', query, filter)
                        .done(function(data) {
                            var i, guids = [], vmdata = {};
                            for (i = 0; i < data.length; i += 1) {
                                guids.push(data[i].guid);
                                vmdata[data[i].guid] = data[i];
                            }
                            generic.crossFiller(
                                guids, self.vMachines,
                                function(guid) {
                                    var vm = new VMachine(guid);
                                    if (full) {
                                        vm.fillData(vmdata[guid]);
                                    }
                                    return vm;
                                }, 'guid'
                            );
                            self.vMachinesInitialLoad(false);
                            deferred.resolve();
                        })
                        .fail(deferred.reject);
                } else {
                    deferred.reject();
                }
            }).promise();
        };
        self.loadVMachine = function(vm, reduced) {
            reduced = reduced || false;
            return $.Deferred(function(deferred) {
                var calls = [vm.load(reduced)];
                if (!reduced) {
                    calls.push(vm.fetchVSAGuids());
                    calls.push(vm.fetchVPoolGuids());
                }
                $.when.apply($, calls)
                    .done(function() {
                        // Merge in the VSAs
                        generic.crossFiller(
                            vm.vSAGuids, vm.vsas,
                            function(guid) {
                                if (!self.vsaCache.hasOwnProperty(guid)) {
                                    var vm = new VMachine(guid);
                                    vm.load();
                                    self.vsaCache[guid] = vm;
                                }
                                return self.vsaCache[guid];
                            }, 'guid'
                        );
                        // Merge in the vPools
                        generic.crossFiller(
                            vm.vPoolGuids, vm.vpools,
                            function(guid) {
                                if (!self.vPoolCache.hasOwnProperty(guid)) {
                                    var vp = new VPool(guid);
                                    vp.load();
                                    self.vPoolCache[guid] = vp;
                                }
                                return self.vPoolCache[guid];
                            }, 'guid'
                        );
                        // (Re)sort vMachines
                        if (self.updateSort) {
                            self.sort();
                        }
                    })
                    .always(deferred.resolve);
            }).promise();
        };
        self.sort = function() {
            if (self.sortTimeout) {
                window.clearTimeout(self.sortTimeout);
            }
            self.sortTimeout = window.setTimeout(function() { generic.advancedSort(self.vMachines, ['name', 'guid']); }, 250);
        };
        self.rollback = function(guid) {
            var i, vms = self.vMachines(), vm;
            for (i = 0; i < vms.length; i += 1) {
                if (vms[i].guid() === guid) {
                    vm = vms[i];
                }
            }
            if (vm !== undefined && !vm.isRunning()) {
                dialog.show(new RollbackWizard({
                    modal: true,
                    type: 'vmachine',
                    guid: guid
                }));
            }
        };
        self.snapshot = function(guid) {
            dialog.show(new SnapshotWizard({
                modal: true,
                machineguid: guid
            }));
        };
        self.setAsTemplate = function(guid) {
            var i, vms = self.vMachines(), vm;
            for (i = 0; i < vms.length; i += 1) {
                if (vms[i].guid() === guid) {
                    vm = vms[i];
                }
            }
            if (vm !== undefined && !vm.isRunning()) {
                app.showMessage(
                        $.t('ovs:vmachines.setastemplate.warning'),
                        $.t('ovs:vmachines.setastemplate.title', { what: vm.name() }),
                        [$.t('ovs:vmachines.setastemplate.no'), $.t('ovs:vmachines.setastemplate.yes')]
                    )
                    .done(function(answer) {
                        if (answer === $.t('ovs:vmachines.setastemplate.yes')) {
                            generic.alertInfo(
                                $.t('ovs:vmachines.setastemplate.marked'),
                                $.t('ovs:vmachines.setastemplate.markedmsg', { what: vm.name() })
                            );
                            api.post('vmachines/' + vm.guid() + '/set_as_template')
                                .then(self.shared.tasks.wait)
                                .done(function() {
                                    self.vMachines.destroy(vm);
                                    generic.alertSuccess(
                                        $.t('ovs:vmachines.setastemplate.done'),
                                        $.t('ovs:vmachines.setastemplate.donemsg', { what: vm.name() })
                                    );
                                })
                                .fail(function(error) {
                                    generic.alertError(
                                        $.t('ovs:generic.error'),
                                        $.t('ovs:generic.messages.errorwhile', {
                                            context: 'error',
                                            what: $.t('ovs:vmachines.setastemplate.errormsg', { what: vm.name() }),
                                            error: error
                                        })
                                    );
                                });
                        }
                    });
            }
        };

        // Durandal
        self.activate = function() {
            self.refresher.init(self.fetchVMachines, 5000);
            self.shared.footerData(self.vMachines);

            self.fetchVMachines(true)
                .always(function() {
                    self.sort();
                    self.updateSort = true;
                    self.refresher.start();
                });
        };
        self.deactivate = function() {
            var i;
            for (i = 0; i < self.widgets.length; i += 2) {
                self.widgets[i].deactivate();
            }
            self.refresher.stop();
            self.shared.footerData(ko.observable());
        };
    };
});
<commit_msg>Small layout tweak preventing line break on read- and writespeeds<commit_after>// Copyright 2014 CloudFounders NV
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*global define, window */
define([
    'jquery', 'durandal/app', 'plugins/dialog', 'knockout',
    'ovs/shared', 'ovs/generic', 'ovs/refresher', 'ovs/api',
    '../containers/vmachine', '../containers/vpool', '../wizards/rollback/index', '../wizards/snapshot/index'
], function($, app, dialog, ko, shared, generic, Refresher, api, VMachine, VPool, RollbackWizard, SnapshotWizard) {
    "use strict";
    return function() {
        var self = this;

        // System
        self.shared      = shared;
        self.guard       = { authenticated: true };
        self.refresher   = new Refresher();
        self.widgets     = [];
        self.updateSort  = false;
        self.sortTimeout = undefined;

        // Data
        self.vMachineHeaders = [
            { key: 'name',         value: $.t('ovs:generic.name'),       width: 150       },
            { key: 'vpool',        value: $.t('ovs:generic.vpool'),      width: 150       },
            { key: 'vsa',          value: $.t('ovs:generic.vsa'),        width: 100       },
            { key: undefined,      value: $.t('ovs:generic.vdisks'),     width: 60        },
            { key: 'storedData',   value: $.t('ovs:generic.storeddata'), width: 110       },
            { key: 'cacheRatio',   value: $.t('ovs:generic.cache'),      width: 100       },
            { key: 'iops',         value: $.t('ovs:generic.iops'),       width: 55        },
            { key: 'readSpeed',    value: $.t('ovs:generic.read'),       width: 120       },
            { key: 'writeSpeed',   value: $.t('ovs:generic.write'),      width: 120       },
            { key: 'failoverMode', value: $.t('ovs:generic.focstatus'),  width: undefined },
            { key: undefined,      value: $.t('ovs:generic.actions'),    width: 100       }
        ];
        self.vMachines = ko.observableArray([]);
        self.vPoolCache = {};
        self.vsaCache = {};
        self.vMachinesInitialLoad = ko.observable(true);

        // Variables
        self.loadVMachinesHandle = undefined;

        // Functions
        self.fetchVMachines = function(full) {
            full = full || false;
            return $.Deferred(function(deferred) {
                if (generic.xhrCompleted(self.loadVMachinesHandle)) {
                    var query = {
                            query: {
                                type: 'AND',
                                items: [['is_internal', 'EQUALS', false],
                                        ['is_vtemplate', 'EQUALS', false],
                                        ['status', 'NOT_EQUALS', 'CREATED']]
                            }
                        }, filter = {};
                    if (full) {
                        filter.full = true;
                    }
                    self.loadVMachinesHandle = api.post('vmachines/filter', query, filter)
                        .done(function(data) {
                            var i, guids = [], vmdata = {};
                            for (i = 0; i < data.length; i += 1) {
                                guids.push(data[i].guid);
                                vmdata[data[i].guid] = data[i];
                            }
                            generic.crossFiller(
                                guids, self.vMachines,
                                function(guid) {
                                    var vm = new VMachine(guid);
                                    if (full) {
                                        vm.fillData(vmdata[guid]);
                                    }
                                    return vm;
                                }, 'guid'
                            );
                            self.vMachinesInitialLoad(false);
                            deferred.resolve();
                        })
                        .fail(deferred.reject);
                } else {
                    deferred.reject();
                }
            }).promise();
        };
        self.loadVMachine = function(vm, reduced) {
            reduced = reduced || false;
            return $.Deferred(function(deferred) {
                var calls = [vm.load(reduced)];
                if (!reduced) {
                    calls.push(vm.fetchVSAGuids());
                    calls.push(vm.fetchVPoolGuids());
                }
                $.when.apply($, calls)
                    .done(function() {
                        // Merge in the VSAs
                        generic.crossFiller(
                            vm.vSAGuids, vm.vsas,
                            function(guid) {
                                if (!self.vsaCache.hasOwnProperty(guid)) {
                                    var vm = new VMachine(guid);
                                    vm.load();
                                    self.vsaCache[guid] = vm;
                                }
                                return self.vsaCache[guid];
                            }, 'guid'
                        );
                        // Merge in the vPools
                        generic.crossFiller(
                            vm.vPoolGuids, vm.vpools,
                            function(guid) {
                                if (!self.vPoolCache.hasOwnProperty(guid)) {
                                    var vp = new VPool(guid);
                                    vp.load();
                                    self.vPoolCache[guid] = vp;
                                }
                                return self.vPoolCache[guid];
                            }, 'guid'
                        );
                        // (Re)sort vMachines
                        if (self.updateSort) {
                            self.sort();
                        }
                    })
                    .always(deferred.resolve);
            }).promise();
        };
        self.sort = function() {
            if (self.sortTimeout) {
                window.clearTimeout(self.sortTimeout);
            }
            self.sortTimeout = window.setTimeout(function() { generic.advancedSort(self.vMachines, ['name', 'guid']); }, 250);
        };
        self.rollback = function(guid) {
            var i, vms = self.vMachines(), vm;
            for (i = 0; i < vms.length; i += 1) {
                if (vms[i].guid() === guid) {
                    vm = vms[i];
                }
            }
            if (vm !== undefined && !vm.isRunning()) {
                dialog.show(new RollbackWizard({
                    modal: true,
                    type: 'vmachine',
                    guid: guid
                }));
            }
        };
        self.snapshot = function(guid) {
            dialog.show(new SnapshotWizard({
                modal: true,
                machineguid: guid
            }));
        };
        self.setAsTemplate = function(guid) {
            var i, vms = self.vMachines(), vm;
            for (i = 0; i < vms.length; i += 1) {
                if (vms[i].guid() === guid) {
                    vm = vms[i];
                }
            }
            if (vm !== undefined && !vm.isRunning()) {
                app.showMessage(
                        $.t('ovs:vmachines.setastemplate.warning'),
                        $.t('ovs:vmachines.setastemplate.title', { what: vm.name() }),
                        [$.t('ovs:vmachines.setastemplate.no'), $.t('ovs:vmachines.setastemplate.yes')]
                    )
                    .done(function(answer) {
                        if (answer === $.t('ovs:vmachines.setastemplate.yes')) {
                            generic.alertInfo(
                                $.t('ovs:vmachines.setastemplate.marked'),
                                $.t('ovs:vmachines.setastemplate.markedmsg', { what: vm.name() })
                            );
                            api.post('vmachines/' + vm.guid() + '/set_as_template')
                                .then(self.shared.tasks.wait)
                                .done(function() {
                                    self.vMachines.destroy(vm);
                                    generic.alertSuccess(
                                        $.t('ovs:vmachines.setastemplate.done'),
                                        $.t('ovs:vmachines.setastemplate.donemsg', { what: vm.name() })
                                    );
                                })
                                .fail(function(error) {
                                    generic.alertError(
                                        $.t('ovs:generic.error'),
                                        $.t('ovs:generic.messages.errorwhile', {
                                            context: 'error',
                                            what: $.t('ovs:vmachines.setastemplate.errormsg', { what: vm.name() }),
                                            error: error
                                        })
                                    );
                                });
                        }
                    });
            }
        };

        // Durandal
        self.activate = function() {
            self.refresher.init(self.fetchVMachines, 5000);
            self.shared.footerData(self.vMachines);

            self.fetchVMachines(true)
                .always(function() {
                    self.sort();
                    self.updateSort = true;
                    self.refresher.start();
                });
        };
        self.deactivate = function() {
            var i;
            for (i = 0; i < self.widgets.length; i += 2) {
                self.widgets[i].deactivate();
            }
            self.refresher.stop();
            self.shared.footerData(ko.observable());
        };
    };
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
 */

define([
    'underscore',
    'contrail-model',
    'config/infra/bgp/ui/js/models/bgpPeersModel'
], function (_, ContrailModel, BGPPeersModel) {
    var self;
    var bgpCfgModel = ContrailModel.extend({
        defaultConfig: {
            'name': null,
            'display_name' : null,
            'fq_name' : null,
            'parent_type' : 'routing-instance',
            'parent_name' : '__default__',
            'bgp_router_parameters' : {
                'vendor' : null,
                'port' : 179,
                'address' : null,
                'identifier' : null,
                'hold_time' : 90,
                'autonomous_system' : null,
                'address_families' : {
                    'family' : []
                },
                'auth_data' : null
            },
            'bgp_router_refs' : [],
            'physical_router_back_refs' : [],
            'user_created_role' : 'bgp_router',
            'user_created_autonomous_system' : null,
            'user_created_address_family' :
                'inet-vpn,inet6-vpn,route-target,e-vpn',
            'user_created_auth_key_type' : 'none',
            'user_created_auth_key' : null,
            'user_created_physical_router' : 'none',
            'user_created_vendor' : null,
            'user_created_address': null,
            'user_created_identifier': null,
            'addressFamilyData' : ctwc.BGP_ADDRESS_FAMILY_DATA,
            'isAutoMeshEnabled' : null
        },
        formatModelConfig : function(modelConfig) {
            self = this;
            // populate bgp router parameters
            var bgpParams = modelConfig['bgp_router_parameters'];
            if(bgpParams['vendor'] != null) {
                modelConfig['user_created_vendor'] = bgpParams['vendor'];
            }
            if(bgpParams['address'] != null) {
                modelConfig['user_created_address'] = bgpParams['address'];
            }
            if(bgpParams['identifier'] != null) {
                modelConfig['user_created_identifier'] = bgpParams['identifier'];
            }
            if(bgpParams['autonomous_system'] != null) {
                modelConfig['user_created_autonomous_system'] =
                    bgpParams['autonomous_system'];
            }
            if(bgpParams['auth_data'] != null) {
                var authData = bgpParams['auth_data'];
                modelConfig['user_created_auth_key_type'] =
                    authData.key_type != null ? authData.key_type : 'none';
                modelConfig['user_created_auth_key'] =
                    authData.key_items != null &&
                    authData.key_items.length > 0 ?
                    authData.key_items[0].key : '';
            }
            if(bgpParams['address_families']['family'].length > 0) {
                modelConfig['user_created_address_family'] =
                    bgpParams['address_families']['family'];
            } else{
                //it is required to send default family list for bgp router type
                bgpParams['address_families']['family'] =
                   ['inet-vpn','inet6-vpn','route-target','e-vpn'];
            }

            //populate user_created_physical_router
            if(modelConfig['physical_router_back_refs'] != null &&
                modelConfig['physical_router_back_refs'].length > 0) {
                modelConfig['user_created_physical_router'] =
                    modelConfig['physical_router_back_refs'][0].uuid;
            }

            //populate available peers
            var selectedPeers = ifNull(modelConfig['bgp_router_refs'],[]),
                peerModels = [], peerModel,
                peerCollectionModel;
            var availablePeers = window.bgp != null &&
                window.bgp.availablePeers != null ?
                window.bgp.availablePeers : [];
            if(availablePeers.length > 0) {
                for(var i = 0; i < availablePeers.length; i++) {
                    var isSelected = false;
                    var currentPeer = availablePeers[i];
                    var authData = null;
                    if(selectedPeers.length > 0) {
                        for(var j = 0; j < selectedPeers.length; j++) {
                            var selectedPeer = selectedPeers[j];
                            if(currentPeer.name === selectedPeer.to[4]) {
                                isSelected = true;
                                authData = getValueByJsonPath(selectedPeer,
                                'attr;session;0;attributes;0;auth_data', null);
                                break;
                            }
                        }
                    }
                    peerModel = new BGPPeersModel({
                        isPeerSelected : isSelected,
                        peerName : currentPeer.name,
                        disabled : true,
                        auth_data : authData,
                        peerASN :
                            currentPeer.bgp_router_parameters.autonomous_system
                    });
                    peerModel.__kb.view_model.model().on('change:user_created_auth_key_type',
                        function(model, newValue){
                             var currPeer = self.getCurrentPeer(
                                 this.attributes.peerName);
                            if(newValue === 'none') {
                                currPeer.user_created_auth_key('');
                                currPeer.disableAuthKey(true);
                            } else {
                                var authKey = '';
                                if(currPeer.auth_data() != null) {
                                    var authData = currPeer.auth_data();
                                    authKey = authData.key_items != null &&
                                        authData.key_items.length > 0 ?
                                        authData.key_items[0].key : '';
                                }
                                currPeer.user_created_auth_key(authKey);
                                currPeer.disableAuthKey(false);
                            }
                        }
                    );
                    peerModels.push(peerModel)
                }
            };
            peerCollectionModel = new Backbone.Collection(peerModels);
            modelConfig['peers'] = peerCollectionModel;
            return modelConfig;
        },
        getCurrentPeer: function(name){
            var model;
            var peers = this.model().attributes['peers'].toJSON();
            for(var i = 0; i < peers.length; i++) {
                if(peers[i].peerName() === name) {
                    model = peers[i];
                    break;
                }
            }
            return model;
        },
        getPeers : function(attr) {
            var peerCollection = attr.peers.toJSON(),
                peerArray = [];
            for(var i = 0; i < peerCollection.length; i++) {
                if(peerCollection[i].isPeerSelected()) {
                    var peer = peerCollection[i];
                    var authData = null;
                    if(peer.user_created_auth_key_type() != 'none') {
                        authData = {
                            key_type : peer.user_created_auth_key_type(),
                            key_items : [{
                                key_id : 0,
                                key : peer.user_created_auth_key()
                            }]
                       };
                    }
                    peerArray.push({
                        peerName : peer.peerName(),
                        authData : authData
                    });
                }
            }
            return peerArray;
        },
        configBGPRouter: function (callbackObj, ajaxMethod) {
            var ajaxConfig = {}, returnFlag = false;
            var postBGPData = {'bgp-router':{}};
            var postData = { 'content' : {}};
            var peers = [];
            var self  = this;
            if (self.model().isValid(true, "configureValidations")) {
                var attr = this.model().attributes;
                var newBGPRouterCfgData = $.extend(true, {}, attr);

                if(!newBGPRouterCfgData.isAutoMeshEnabled ||
                    newBGPRouterCfgData.user_created_role !==
                    ctwl.CONTROL_NODE_TYPE) {
                    var selectdata = self.getPeers(newBGPRouterCfgData);
                    for (var i = 0; i < selectdata.length; i++) {
                        for (var j = 0; j < self.bgpData.length; j++) {
                            if (self.bgpData[j].name == selectdata[i].peerName) {
                                var attr = {};
                                attr.session = [];
                                attr.session.push({
                                    uuid: null,
                                    attributes: [
                                        {
                                            auth_data : selectdata[i].authData
                                        }
                                    ]
                                })
                                peers.push(
                                    {
                                        "uuid":self.bgpData[j].uuid,
                                        "href":self.bgpData[j].href,
                                        "_id_params":self.bgpData[j]._id_params,
                                        "to":["default-domain", "default-project" ,
                                            "ip-fabric", "__default__", selectdata[i].peerName],
                                        "attr" : attr
                                    }
                                );
                                break;
                            }
                        }
                    }

                }
                //set physical router post data
                postData['content']['prouter-params'] = {
                    newProuter :
                        newBGPRouterCfgData.user_created_physical_router
                };
                var holdTime =
                    newBGPRouterCfgData.bgp_router_parameters.hold_time;
                if(holdTime != null && holdTime.toString().trim() != '') {
                    newBGPRouterCfgData.bgp_router_parameters.hold_time =
                        parseInt(holdTime.toString().trim());
                }

                var port = newBGPRouterCfgData.bgp_router_parameters.port;
                if(port != null && port.toString().trim() != '') {
                    newBGPRouterCfgData.bgp_router_parameters.port =
                        parseInt(port.toString().trim());
                }

                //handling auth data
                if(newBGPRouterCfgData.user_created_auth_key_type != 'none') {
                    newBGPRouterCfgData.bgp_router_parameters.auth_data = {
                        key_type : newBGPRouterCfgData.user_created_auth_key_type,
                        key_items : [{
                            key_id : 0,
                            key : newBGPRouterCfgData.user_created_auth_key
                        }]
                    };
                } else {
                   newBGPRouterCfgData.bgp_router_parameters.auth_data = null;
                }

                delete newBGPRouterCfgData.errors;
                delete newBGPRouterCfgData.locks;
                delete newBGPRouterCfgData.cgrid;
                delete newBGPRouterCfgData.id_perms;
                delete newBGPRouterCfgData.bgp_router_refs;
                delete newBGPRouterCfgData.physical_router_back_refs;
                delete newBGPRouterCfgData.user_created_role;
                delete newBGPRouterCfgData.user_created_address;
                delete newBGPRouterCfgData.user_created_identifier;
                delete newBGPRouterCfgData.user_created_address_family;
                delete newBGPRouterCfgData.user_created_auth_key_type;
                delete newBGPRouterCfgData.user_created_auth_key;
                delete newBGPRouterCfgData.user_created_physical_router;
                delete newBGPRouterCfgData.user_created_vendor;
                delete newBGPRouterCfgData.addressFamilyData;
                delete newBGPRouterCfgData.isAutoMeshEnabled;
                delete newBGPRouterCfgData.peers;
                delete newBGPRouterCfgData.elementConfigMap;

                postBGPData['bgp-router'] = newBGPRouterCfgData;
                if(peers.length > 0) {
                    postBGPData['bgp-router']['bgp_router_refs'] = peers
                }
                postData['content']['bgp-router'] = postBGPData['bgp-router'];

                ajaxConfig.type  = ajaxMethod;
                ajaxConfig.data  = JSON.stringify(postData);
                ajaxConfig.url   = ajaxMethod == 'PUT' ?
                                   '/api/admin/bgp-router/' +
                                   newBGPRouterCfgData['uuid'] :
                                   '/api/admin/bgp-router';

                contrail.ajaxHandler(ajaxConfig, function () {
                    if (contrail.checkIfFunction(callbackObj.init)) {
                        callbackObj.init();
                    }
                }, function (response) {
                    if (contrail.checkIfFunction(callbackObj.success)) {
                        callbackObj.success();
                    }
                    returnFlag = true;
                }, function (error) {
                    if (contrail.checkIfFunction(callbackObj.error)) {
                        callbackObj.error(error);
                    }
                    returnFlag = false;
                });
            } else {
                if (contrail.checkIfFunction(callbackObj.error)) {
                    callbackObj.error(this.getFormErrorText(ctwl.BGP_PREFIX_ID));
                }
            }

            return returnFlag;
        },
        deleteBGPRouters : function(checkedRows, callbackObj) {
            var ajaxConfig = {}, that = this;
            var uuidList = [];

            $.each(checkedRows, function (checkedRowsKey, checkedRowsValue) {
                uuidList.push(checkedRowsValue.uuid);
            });

            ajaxConfig.type = "POST";
            ajaxConfig.data = JSON.stringify([{'type': 'bgp-router',
                                              'deleteIDs': uuidList}]);

            ajaxConfig.url = '/api/tenants/config/delete';
            contrail.ajaxHandler(ajaxConfig, function () {
                if (contrail.checkIfFunction(callbackObj.init)) {
                    callbackObj.init();
                }
            }, function (response) {
                if (contrail.checkIfFunction(callbackObj.success)) {
                    callbackObj.success();
                }
            }, function (error) {
                if (contrail.checkIfFunction(callbackObj.error)) {
                    callbackObj.error(error);
                }
            });
        },
        validations: {
            configureValidations: {
                'name': {
                    required: true,
                    msg: 'Hostname is required'
                },
                'user_created_autonomous_system' : function(value, attr, finalObj){
                     var asn = parseInt(value);
                     if (asn < 1 || asn > 65534 || isNaN(asn)) {
                         return "Enter valid BGP ASN number between 1-65534";
                     }
                },
                'user_created_identifier' : function(value, attr, finalObj){
                    if (!isValidIP(value) || value.trim().indexOf("/") != -1) {
                        return "Enter a valid BGP router ID in the format xxx.xxx.xxx.xxx";
                    }
                },
                'user_created_address' : function(value, attr, finalObj){
                    if (!isValidIP(value) || value.trim().indexOf("/") != -1) {
                        return "Enter a valid BGP router address in the format xxx.xxx.xxx.xxx";
                    }
                },
                'user_created_auth_key' : function(value, attr, finalObj){
                    if (finalObj['user_created_auth_key_type'] != 'none'
                        && (value == null || value.trim() == '')) {
                        return "Enter a valid Authentication key";
                    }
                },
                'bgp_router_parameters.port' :  function(value, attr, finalObj){
                     var port = parseInt(value);
                    if (port <= 0 || port > 9999 || isNaN(port)) {
                        return "Enter valid BGP port number between 1-9999";
                    }
                },
                'bgp_router_parameters.hold_time' :  function(value, attr, finalObj){
                    if(value != "") {
                        var holdTime = parseInt(value);
                        if (holdTime < 1 || holdTime > 65535 || isNaN(holdTime)) {
                            return "Enter valid  hold time between 1-65535" ;
                        }
                    }
                },
                'user_created_vendor' : function(value, attr, finalObj){
                    if (finalObj.user_created_role !== ctwl.CONTROL_NODE_TYPE){
                        if(value === null || value.trim() === '') {
                            return "Enter valid vendor name or SKU such as 'Juniper' or 'MX-40'";
                        } else if(value.trim().toLowerCase() === "contrail"){
                            return "Vendor name cannot be 'contrail'.\
                                Enter valid vendor name or SKU such as 'Juniper' or 'MX-40'";
                        }
                    }
                }
            }
        },
    });
    return bgpCfgModel;
});
<commit_msg>Deleted 'user_created_autonomous_system' from request payload.<commit_after>/*
 * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
 */

define([
    'underscore',
    'contrail-model',
    'config/infra/bgp/ui/js/models/bgpPeersModel'
], function (_, ContrailModel, BGPPeersModel) {
    var self;
    var bgpCfgModel = ContrailModel.extend({
        defaultConfig: {
            'name': null,
            'display_name' : null,
            'fq_name' : null,
            'parent_type' : 'routing-instance',
            'parent_name' : '__default__',
            'bgp_router_parameters' : {
                'vendor' : null,
                'port' : 179,
                'address' : null,
                'identifier' : null,
                'hold_time' : 90,
                'autonomous_system' : null,
                'address_families' : {
                    'family' : []
                },
                'auth_data' : null
            },
            'bgp_router_refs' : [],
            'physical_router_back_refs' : [],
            'user_created_role' : 'bgp_router',
            'user_created_autonomous_system' : null,
            'user_created_address_family' :
                'inet-vpn,inet6-vpn,route-target,e-vpn',
            'user_created_auth_key_type' : 'none',
            'user_created_auth_key' : null,
            'user_created_physical_router' : 'none',
            'user_created_vendor' : null,
            'user_created_address': null,
            'user_created_identifier': null,
            'addressFamilyData' : ctwc.BGP_ADDRESS_FAMILY_DATA,
            'isAutoMeshEnabled' : null
        },
        formatModelConfig : function(modelConfig) {
            self = this;
            // populate bgp router parameters
            var bgpParams = modelConfig['bgp_router_parameters'];
            if(bgpParams['vendor'] != null) {
                modelConfig['user_created_vendor'] = bgpParams['vendor'];
            }
            if(bgpParams['address'] != null) {
                modelConfig['user_created_address'] = bgpParams['address'];
            }
            if(bgpParams['identifier'] != null) {
                modelConfig['user_created_identifier'] = bgpParams['identifier'];
            }
            if(bgpParams['autonomous_system'] != null) {
                modelConfig['user_created_autonomous_system'] =
                    bgpParams['autonomous_system'];
            }
            if(bgpParams['auth_data'] != null) {
                var authData = bgpParams['auth_data'];
                modelConfig['user_created_auth_key_type'] =
                    authData.key_type != null ? authData.key_type : 'none';
                modelConfig['user_created_auth_key'] =
                    authData.key_items != null &&
                    authData.key_items.length > 0 ?
                    authData.key_items[0].key : '';
            }
            if(bgpParams['address_families']['family'].length > 0) {
                modelConfig['user_created_address_family'] =
                    bgpParams['address_families']['family'];
            } else{
                //it is required to send default family list for bgp router type
                bgpParams['address_families']['family'] =
                   ['inet-vpn','inet6-vpn','route-target','e-vpn'];
            }

            //populate user_created_physical_router
            if(modelConfig['physical_router_back_refs'] != null &&
                modelConfig['physical_router_back_refs'].length > 0) {
                modelConfig['user_created_physical_router'] =
                    modelConfig['physical_router_back_refs'][0].uuid;
            }

            //populate available peers
            var selectedPeers = ifNull(modelConfig['bgp_router_refs'],[]),
                peerModels = [], peerModel,
                peerCollectionModel;
            var availablePeers = window.bgp != null &&
                window.bgp.availablePeers != null ?
                window.bgp.availablePeers : [];
            if(availablePeers.length > 0) {
                for(var i = 0; i < availablePeers.length; i++) {
                    var isSelected = false;
                    var currentPeer = availablePeers[i];
                    var authData = null;
                    if(selectedPeers.length > 0) {
                        for(var j = 0; j < selectedPeers.length; j++) {
                            var selectedPeer = selectedPeers[j];
                            if(currentPeer.name === selectedPeer.to[4]) {
                                isSelected = true;
                                authData = getValueByJsonPath(selectedPeer,
                                'attr;session;0;attributes;0;auth_data', null);
                                break;
                            }
                        }
                    }
                    peerModel = new BGPPeersModel({
                        isPeerSelected : isSelected,
                        peerName : currentPeer.name,
                        disabled : true,
                        auth_data : authData,
                        peerASN :
                            currentPeer.bgp_router_parameters.autonomous_system
                    });
                    peerModel.__kb.view_model.model().on('change:user_created_auth_key_type',
                        function(model, newValue){
                             var currPeer = self.getCurrentPeer(
                                 this.attributes.peerName);
                            if(newValue === 'none') {
                                currPeer.user_created_auth_key('');
                                currPeer.disableAuthKey(true);
                            } else {
                                var authKey = '';
                                if(currPeer.auth_data() != null) {
                                    var authData = currPeer.auth_data();
                                    authKey = authData.key_items != null &&
                                        authData.key_items.length > 0 ?
                                        authData.key_items[0].key : '';
                                }
                                currPeer.user_created_auth_key(authKey);
                                currPeer.disableAuthKey(false);
                            }
                        }
                    );
                    peerModels.push(peerModel)
                }
            };
            peerCollectionModel = new Backbone.Collection(peerModels);
            modelConfig['peers'] = peerCollectionModel;
            return modelConfig;
        },
        getCurrentPeer: function(name){
            var model;
            var peers = this.model().attributes['peers'].toJSON();
            for(var i = 0; i < peers.length; i++) {
                if(peers[i].peerName() === name) {
                    model = peers[i];
                    break;
                }
            }
            return model;
        },
        getPeers : function(attr) {
            var peerCollection = attr.peers.toJSON(),
                peerArray = [];
            for(var i = 0; i < peerCollection.length; i++) {
                if(peerCollection[i].isPeerSelected()) {
                    var peer = peerCollection[i];
                    var authData = null;
                    if(peer.user_created_auth_key_type() != 'none') {
                        authData = {
                            key_type : peer.user_created_auth_key_type(),
                            key_items : [{
                                key_id : 0,
                                key : peer.user_created_auth_key()
                            }]
                       };
                    }
                    peerArray.push({
                        peerName : peer.peerName(),
                        authData : authData
                    });
                }
            }
            return peerArray;
        },
        configBGPRouter: function (callbackObj, ajaxMethod) {
            var ajaxConfig = {}, returnFlag = false;
            var postBGPData = {'bgp-router':{}};
            var postData = { 'content' : {}};
            var peers = [];
            var self  = this;
            if (self.model().isValid(true, "configureValidations")) {
                var attr = this.model().attributes;
                var newBGPRouterCfgData = $.extend(true, {}, attr);

                if(!newBGPRouterCfgData.isAutoMeshEnabled ||
                    newBGPRouterCfgData.user_created_role !==
                    ctwl.CONTROL_NODE_TYPE) {
                    var selectdata = self.getPeers(newBGPRouterCfgData);
                    for (var i = 0; i < selectdata.length; i++) {
                        for (var j = 0; j < self.bgpData.length; j++) {
                            if (self.bgpData[j].name == selectdata[i].peerName) {
                                var attr = {};
                                attr.session = [];
                                attr.session.push({
                                    uuid: null,
                                    attributes: [
                                        {
                                            auth_data : selectdata[i].authData
                                        }
                                    ]
                                })
                                peers.push(
                                    {
                                        "uuid":self.bgpData[j].uuid,
                                        "href":self.bgpData[j].href,
                                        "_id_params":self.bgpData[j]._id_params,
                                        "to":["default-domain", "default-project" ,
                                            "ip-fabric", "__default__", selectdata[i].peerName],
                                        "attr" : attr
                                    }
                                );
                                break;
                            }
                        }
                    }

                }
                //set physical router post data
                postData['content']['prouter-params'] = {
                    newProuter :
                        newBGPRouterCfgData.user_created_physical_router
                };
                var holdTime =
                    newBGPRouterCfgData.bgp_router_parameters.hold_time;
                if(holdTime != null && holdTime.toString().trim() != '') {
                    newBGPRouterCfgData.bgp_router_parameters.hold_time =
                        parseInt(holdTime.toString().trim());
                }

                var port = newBGPRouterCfgData.bgp_router_parameters.port;
                if(port != null && port.toString().trim() != '') {
                    newBGPRouterCfgData.bgp_router_parameters.port =
                        parseInt(port.toString().trim());
                }

                //handling auth data
                if(newBGPRouterCfgData.user_created_auth_key_type != 'none') {
                    newBGPRouterCfgData.bgp_router_parameters.auth_data = {
                        key_type : newBGPRouterCfgData.user_created_auth_key_type,
                        key_items : [{
                            key_id : 0,
                            key : newBGPRouterCfgData.user_created_auth_key
                        }]
                    };
                } else {
                   newBGPRouterCfgData.bgp_router_parameters.auth_data = null;
                }

                delete newBGPRouterCfgData.errors;
                delete newBGPRouterCfgData.locks;
                delete newBGPRouterCfgData.cgrid;
                delete newBGPRouterCfgData.id_perms;
                delete newBGPRouterCfgData.bgp_router_refs;
                delete newBGPRouterCfgData.physical_router_back_refs;
                delete newBGPRouterCfgData.user_created_role;
                delete newBGPRouterCfgData.user_created_address;
                delete newBGPRouterCfgData.user_created_identifier;
                delete newBGPRouterCfgData.user_created_autonomous_system;
                delete newBGPRouterCfgData.user_created_address_family;
                delete newBGPRouterCfgData.user_created_auth_key_type;
                delete newBGPRouterCfgData.user_created_auth_key;
                delete newBGPRouterCfgData.user_created_physical_router;
                delete newBGPRouterCfgData.user_created_vendor;
                delete newBGPRouterCfgData.addressFamilyData;
                delete newBGPRouterCfgData.isAutoMeshEnabled;
                delete newBGPRouterCfgData.peers;
                delete newBGPRouterCfgData.elementConfigMap;

                postBGPData['bgp-router'] = newBGPRouterCfgData;
                if(peers.length > 0) {
                    postBGPData['bgp-router']['bgp_router_refs'] = peers
                }
                postData['content']['bgp-router'] = postBGPData['bgp-router'];

                ajaxConfig.type  = ajaxMethod;
                ajaxConfig.data  = JSON.stringify(postData);
                ajaxConfig.url   = ajaxMethod == 'PUT' ?
                                   '/api/admin/bgp-router/' +
                                   newBGPRouterCfgData['uuid'] :
                                   '/api/admin/bgp-router';

                contrail.ajaxHandler(ajaxConfig, function () {
                    if (contrail.checkIfFunction(callbackObj.init)) {
                        callbackObj.init();
                    }
                }, function (response) {
                    if (contrail.checkIfFunction(callbackObj.success)) {
                        callbackObj.success();
                    }
                    returnFlag = true;
                }, function (error) {
                    if (contrail.checkIfFunction(callbackObj.error)) {
                        callbackObj.error(error);
                    }
                    returnFlag = false;
                });
            } else {
                if (contrail.checkIfFunction(callbackObj.error)) {
                    callbackObj.error(this.getFormErrorText(ctwl.BGP_PREFIX_ID));
                }
            }

            return returnFlag;
        },
        deleteBGPRouters : function(checkedRows, callbackObj) {
            var ajaxConfig = {}, that = this;
            var uuidList = [];

            $.each(checkedRows, function (checkedRowsKey, checkedRowsValue) {
                uuidList.push(checkedRowsValue.uuid);
            });

            ajaxConfig.type = "POST";
            ajaxConfig.data = JSON.stringify([{'type': 'bgp-router',
                                              'deleteIDs': uuidList}]);

            ajaxConfig.url = '/api/tenants/config/delete';
            contrail.ajaxHandler(ajaxConfig, function () {
                if (contrail.checkIfFunction(callbackObj.init)) {
                    callbackObj.init();
                }
            }, function (response) {
                if (contrail.checkIfFunction(callbackObj.success)) {
                    callbackObj.success();
                }
            }, function (error) {
                if (contrail.checkIfFunction(callbackObj.error)) {
                    callbackObj.error(error);
                }
            });
        },
        validations: {
            configureValidations: {
                'name': {
                    required: true,
                    msg: 'Hostname is required'
                },
                'user_created_autonomous_system' : function(value, attr, finalObj){
                     var asn = parseInt(value);
                     if (asn < 1 || asn > 65534 || isNaN(asn)) {
                         return "Enter valid BGP ASN number between 1-65534";
                     }
                },
                'user_created_identifier' : function(value, attr, finalObj){
                    if (!isValidIP(value) || value.trim().indexOf("/") != -1) {
                        return "Enter a valid BGP router ID in the format xxx.xxx.xxx.xxx";
                    }
                },
                'user_created_address' : function(value, attr, finalObj){
                    if (!isValidIP(value) || value.trim().indexOf("/") != -1) {
                        return "Enter a valid BGP router address in the format xxx.xxx.xxx.xxx";
                    }
                },
                'user_created_auth_key' : function(value, attr, finalObj){
                    if (finalObj['user_created_auth_key_type'] != 'none'
                        && (value == null || value.trim() == '')) {
                        return "Enter a valid Authentication key";
                    }
                },
                'bgp_router_parameters.port' :  function(value, attr, finalObj){
                     var port = parseInt(value);
                    if (port <= 0 || port > 9999 || isNaN(port)) {
                        return "Enter valid BGP port number between 1-9999";
                    }
                },
                'bgp_router_parameters.hold_time' :  function(value, attr, finalObj){
                    if(value != "") {
                        var holdTime = parseInt(value);
                        if (holdTime < 1 || holdTime > 65535 || isNaN(holdTime)) {
                            return "Enter valid  hold time between 1-65535" ;
                        }
                    }
                },
                'user_created_vendor' : function(value, attr, finalObj){
                    if (finalObj.user_created_role !== ctwl.CONTROL_NODE_TYPE){
                        if(value === null || value.trim() === '') {
                            return "Enter valid vendor name or SKU such as 'Juniper' or 'MX-40'";
                        } else if(value.trim().toLowerCase() === "contrail"){
                            return "Vendor name cannot be 'contrail'.\
                                Enter valid vendor name or SKU such as 'Juniper' or 'MX-40'";
                        }
                    }
                }
            }
        },
    });
    return bgpCfgModel;
});
<|endoftext|>


<commit_before>/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const admin = require('firebase-admin');
const functions = require('firebase-functions');
// Paths for wipeout and takeout.
// All instances of `UID` in the JSON are replaced by the user's uid at runtime.
const userPrivacyPaths = require('./user_privacy.json');

admin.initializeApp(functions.config().firebase);

const db = admin.database();
const firestore = admin.firestore();
const storage = admin.storage();
const FieldValue = admin.firestore.FieldValue;

// App-specific default bucket for storage. Used to upload takeout json and in
// sample json of wipeout and takeout paths.
const appBucketName = 'wipeout-takeout.appspot.com';

// Wipeout
//
// The wipeout function removes personal data from the RealTime Database,
// Storage, and Firestore. It waits for all deletions to complete, and then
// returns a success message.
//
// Triggered by a user deleting their account.
exports.wipeout = functions.auth.user().onDelete((event) => {
  const uid = event.data.uid;

  const databasePromise = databaseWipeout(uid);
  const storagePromise = storageWipeout(uid);
  const firestorePromise = firestoreWipeout(uid);

  return Promise.all([databasePromise, firestorePromise, storagePromise])
      .then(() => console.log(`Successfully removed data for user #${uid}.`)
  );
});

// Delete data from all specified paths from the Realtime Database. To add or
// remove a path, edit the `database[wipeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `wipeout` function.
//
// Returns a list of Promises
const databaseWipeout = (uid) => {
  const paths = userPrivacyPaths.database.wipeout;
  let promises = [];

  for (let i = 0; i < paths.length; i++) {
    let path = replaceUID(paths[i], uid);
    promises.push(db.ref(path).remove().catch((error) => {
      // Avoid execution interuption.
      console.error('Error deleting data at path: ', path, error);
    }));
  }

  return Promise.all(promises).then(() => takeout);
};

// Wipeout all specified files from the Realtime Database. To add or remove a
// path, edit the `storage[wipeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `wipeout` function.
//
// Returns a list of Promises
const storageWipeout = (uid) => {
  const paths = userPrivacyPaths.storage.wipeout;
  let promises = [];

  for (let i = 0; i < paths.length; i++) {
    let bucketName = replaceUID(paths[i][0], uid);
    let path = replaceUID(paths[i][1], uid);
    let bucket = storage.bucket(bucketName);
    let file = bucket.file(path);
    promises.push(file.delete().catch((error) => {
      console.error('Error deleting file: ', path, error);
    }));
  };

  return Promise.all(promises).then(() => takeout);
};

// Wipeout all specified paths from the Firestore Database. To add or remove a
// path, edit the `firestore[wipeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `wipeout` function.
//
// Returns a list of Promises
const firestoreWipeout = (uid) => {
  const paths = userPrivacyPaths.firestore.wipeout;
  let promises = [];

  for (let i = 0; i < paths.length; i++) {
    let entry = paths[i];
    let entryCollection = replaceUID(entry.collection, uid);
    let entryDoc = replaceUID(entry.doc, uid);
    let docToDelete = firestore.collection(entryCollection).doc(entryDoc);
    if ('field' in entry) {
      entryField = replaceUID(entry.field, uid);
      promises.push(docToDelete.update({
        entryField: FieldValue.delete(),
      }).catch((error) => {
        console.error('Error deleting field: ', error);
      }));
    } else if (docToDelete) {
      promises.push(docToDelete.delete().catch((error) => {
        console.error('Error deleting document: ', error);
      }));
    };
  };

  return Promise.all(promises).then(() => uid);
};

// Takeout
//
// The `takeout` function reads and copys data from the RealTime Database,
// Storage, and Firestore. It waits to complete reads for all three, and then
// uploads a JSON file of the takeout data to storage and returns a success
// message.
//
// Because the resulting file will contain personal information, it's important
// to use Firebase Security Rules to make these files readable only by the user.
// See the `storage.rules` file for an example.
//
// Triggered by an http request.
exports.takeout = functions.https.onRequest((req, res) => {
  const body = JSON.parse(req.body);
  const uid = body.uid;
  let takeout = {};

  const databasePromise = databaseTakeout(uid).then((databaseData) => {
    takeout.database = databaseData;
  });
  const firestorePromise = firestoreTakeout(uid).then((firestoreData) => {
    takeout.firestore = firestoreData;
  });
  const storagePromise = storageTakeout(uid).then((storageReferences) => {
    takeout.storage = storageReferences;
  });

  return Promise.all([databasePromise, firestorePromise, storagePromise])
      .then(() => {
        console.log(`Success! Completed takeout for user ${uid}.`);
        return uploadToStorage(uid, takeout);
      }).then(() => res.json({takeoutComplete: true}));
});

// Read and copy the specified paths from the RealTime Database. To add or
// remove a path, edit the `database[takeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `takeout` function.
//
// Returns a Promise.
const databaseTakeout = (uid) => {
  const paths = userPrivacyPaths.database.takeout;
  let promises = [];
  let takeout = {};

  for (let i = 0; i < paths.length; i++) {
    let path = replaceUID(paths[i], uid);
    promises.push( db.ref(path).once('value').then((snapshot) => {
      read = snapshot.val();
      if (read !== null) {
          takeout[snapshot.key] = read;
        }
      }).catch((err) => {
        console.error('Error encountered during database takeout: ', err);
      })
    );
  };

  return Promise.all(promises).then(() => takeout);
};

// Read and copy the specified paths from the Firestore Database. To add or
// remove a path, edit the `firestore[takeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `takeout` function.
//
// Returns a Promise.
const firestoreTakeout = (uid) => {
  const paths = userPrivacyPaths.firestore.takeout;
  let promises = [];
  let takeout = {};

  for (let i = 0; i < paths.length; i++) {
    let entry = paths[i];
    let entryCollection = entry.collection;
    let entryDoc = replaceUID(entry.doc, uid);
    let takeoutRef = firestore.collection(entryCollection).doc(entryDoc);
    let path = `${entryCollection}/${entryDoc}`;
    promises.push(
      takeoutRef.get().then((doc) => {
        if (doc.exists) {
          read = doc.data();
          if ('field' in entry) {
            let entryField = replaceUID(entry.field, uid);
            read = read.field(entryField);
          }
          takeout[path] = read;
        }
      }).catch((err) => {
        console.error('Error encountered during firestore takeout: ', err);
      }).then(new Promise((resolve, reject) => {
        resolve(path);
      }))
    );
  };
  return Promise.all(promises).then(() => takeout);
};

// In the case of Storage, a read-only copy of each file is created, accessible
// only to the user, and a list of copied files is added to the final JSON. It's
// essential that the Firebase Security Rules for Storage restrict access of the
// copied files to the given user.
//
// This implementation works is designed for accounts on the free tier. To use
// multiple buckets, specify a desination bucket arg to the `copy` method.
//
// To add or remove a path, edit the `database[takeout]` array in
// `user_privacy.json`.
//
// This function is called by the top-level `takeout` function.
//
// Returns a Promise.
const storageTakeout = (uid) => {
  const paths = userPrivacyPaths.storage.takeout;
  let promises = [];
  let takeout = {};

  for (let i = 0; i < paths.length; i++) {
    let entry = paths[i];
    let entryBucket = replaceUID(entry[0], uid);
    let path = replaceUID(entry[1], uid);
    let sourceBucket = storage.bucket(entryBucket);
    let sourceFile = sourceBucket.file(path);

    let destinationPath = `takeout/${uid}/${path}`;

    let copyPromise = sourceFile.copy(destinationPath);
    // Make copyPromise succeed even if it fails:
    copyPromise = copyPromise.catch((err) =>
      console.log('There is an error copying the promise, but keep going.')
    );
    // Add the copy task to the array of Promises
    promises.push(copyPromise);
    takeout[`${entryBucket}/${path}`] = `${appBucketName}/${destinationPath}`;
  }
  return Promise.all(promises).then(() => takeout);
};

// Upload json to Storage, under a filename of the user's uid. This is the final
// result of the takeout function, and because this file will contain personal
// information, it's important to use Firebase Security Rules to make these
// files readable only by the user with the same uid.
//
// Called by the top-level takeout function.
const uploadToStorage = (uid, takeout) => {
  const json = JSON.stringify(takeout);
  const bucket = storage.bucket(appBucketName);
  const file = bucket.file(`takeout/${uid}/takeout.json`);

  return file.save(json);
};

const replaceUID = (str, uid) => {
  return str.replace(/UID_VARIABLE/g, uid);
};
<commit_msg>Caught mistakes<commit_after>/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const admin = require('firebase-admin');
const functions = require('firebase-functions');
// Paths for wipeout and takeout.
// All instances of `UID` in the JSON are replaced by the user's uid at runtime.
const userPrivacyPaths = require('./user_privacy.json');

admin.initializeApp(functions.config().firebase);

const db = admin.database();
const firestore = admin.firestore();
const storage = admin.storage();
const FieldValue = admin.firestore.FieldValue;

// App-specific default bucket for storage. Used to upload takeout json and in
// sample json of wipeout and takeout paths.
const appBucketName = 'wipeout-takeout.appspot.com';

// Wipeout
//
// The wipeout function removes personal data from the RealTime Database,
// Storage, and Firestore. It waits for all deletions to complete, and then
// returns a success message.
//
// Triggered by a user deleting their account.
exports.wipeout = functions.auth.user().onDelete((event) => {
  const uid = event.data.uid;

  const databasePromise = databaseWipeout(uid);
  const storagePromise = storageWipeout(uid);
  const firestorePromise = firestoreWipeout(uid);

  return Promise.all([databasePromise, firestorePromise, storagePromise])
      .then(() => console.log(`Successfully removed data for user #${uid}.`)
  );
});

// Delete data from all specified paths from the Realtime Database. To add or
// remove a path, edit the `database[wipeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `wipeout` function.
//
// Returns a list of Promises
const databaseWipeout = (uid) => {
  const paths = userPrivacyPaths.database.wipeout;
  let promises = [];

  for (let i = 0; i < paths.length; i++) {
    let path = replaceUID(paths[i], uid);
    promises.push(db.ref(path).remove().catch((error) => {
      // Avoid execution interuption.
      console.error('Error deleting data at path: ', path, error);
    }));
  }

  return Promise.all(promises).then(() => uid);
};

// Wipeout all specified files from the Realtime Database. To add or remove a
// path, edit the `storage[wipeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `wipeout` function.
//
// Returns a list of Promises
const storageWipeout = (uid) => {
  const paths = userPrivacyPaths.storage.wipeout;
  let promises = [];

  for (let i = 0; i < paths.length; i++) {
    let bucketName = replaceUID(paths[i][0], uid);
    let path = replaceUID(paths[i][1], uid);
    let bucket = storage.bucket(bucketName);
    let file = bucket.file(path);
    promises.push(file.delete().catch((error) => {
      console.error('Error deleting file: ', path, error);
    }));
  };

  return Promise.all(promises).then(() => uid);
};

// Wipeout all specified paths from the Firestore Database. To add or remove a
// path, edit the `firestore[wipeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `wipeout` function.
//
// Returns a list of Promises
const firestoreWipeout = (uid) => {
  const paths = userPrivacyPaths.firestore.wipeout;
  let promises = [];

  for (let i = 0; i < paths.length; i++) {
    let entry = paths[i];
    let entryCollection = replaceUID(entry.collection, uid);
    let entryDoc = replaceUID(entry.doc, uid);
    let docToDelete = firestore.collection(entryCollection).doc(entryDoc);
    if ('field' in entry) {
      entryField = replaceUID(entry.field, uid);
      promises.push(docToDelete.update({
        entryField: FieldValue.delete(),
      }).catch((error) => {
        console.error('Error deleting field: ', error);
      }));
    } else if (docToDelete) {
      promises.push(docToDelete.delete().catch((error) => {
        console.error('Error deleting document: ', error);
      }));
    };
  };

  return Promise.all(promises).then(() => uid);
};

// Takeout
//
// The `takeout` function reads and copys data from the RealTime Database,
// Storage, and Firestore. It waits to complete reads for all three, and then
// uploads a JSON file of the takeout data to storage and returns a success
// message.
//
// Because the resulting file will contain personal information, it's important
// to use Firebase Security Rules to make these files readable only by the user.
// See the `storage.rules` file for an example.
//
// Triggered by an http request.
exports.takeout = functions.https.onRequest((req, res) => {
  const body = JSON.parse(req.body);
  const uid = body.uid;
  let takeout = {};

  const databasePromise = databaseTakeout(uid).then((databaseData) => {
    takeout.database = databaseData;
  });
  const firestorePromise = firestoreTakeout(uid).then((firestoreData) => {
    takeout.firestore = firestoreData;
  });
  const storagePromise = storageTakeout(uid).then((storageReferences) => {
    takeout.storage = storageReferences;
  });

  return Promise.all([databasePromise, firestorePromise, storagePromise])
      .then(() => {
        console.log(`Success! Completed takeout for user ${uid}.`);
        return uploadToStorage(uid, takeout);
      }).then(() => res.json({takeoutComplete: true}));
});

// Read and copy the specified paths from the RealTime Database. To add or
// remove a path, edit the `database[takeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `takeout` function.
//
// Returns a Promise.
const databaseTakeout = (uid) => {
  const paths = userPrivacyPaths.database.takeout;
  let promises = [];
  let takeout = {};

  for (let i = 0; i < paths.length; i++) {
    let path = replaceUID(paths[i], uid);
    promises.push( db.ref(path).once('value').then((snapshot) => {
      read = snapshot.val();
      if (read !== null) {
          takeout[snapshot.key] = read;
        }
      }).catch((err) => {
        console.error('Error encountered during database takeout: ', err);
      })
    );
  };

  return Promise.all(promises).then(() => takeout);
};

// Read and copy the specified paths from the Firestore Database. To add or
// remove a path, edit the `firestore[takeout]` array in `user_privacy.json`.
//
// This function is called by the top-level `takeout` function.
//
// Returns a Promise.
const firestoreTakeout = (uid) => {
  const paths = userPrivacyPaths.firestore.takeout;
  let promises = [];
  let takeout = {};

  for (let i = 0; i < paths.length; i++) {
    let entry = paths[i];
    let entryCollection = entry.collection;
    let entryDoc = replaceUID(entry.doc, uid);
    let takeoutRef = firestore.collection(entryCollection).doc(entryDoc);
    let path = `${entryCollection}/${entryDoc}`;
    promises.push(
      takeoutRef.get().then((doc) => {
        if (doc.exists) {
          read = doc.data();
          if ('field' in entry) {
            let entryField = replaceUID(entry.field, uid);
            path = `${path}/${entryField}`;
            read = read[entryField];
          }
          takeout[path] = read;
        }
      }).catch((err) => {
        console.error('Error encountered during firestore takeout: ', err);
      }).then(new Promise((resolve, reject) => {
        resolve(path);
      }))
    );
  };
  return Promise.all(promises).then(() => takeout);
};

// In the case of Storage, a read-only copy of each file is created, accessible
// only to the user, and a list of copied files is added to the final JSON. It's
// essential that the Firebase Security Rules for Storage restrict access of the
// copied files to the given user.
//
// This implementation works is designed for accounts on the free tier. To use
// multiple buckets, specify a desination bucket arg to the `copy` method.
//
// To add or remove a path, edit the `database[takeout]` array in
// `user_privacy.json`.
//
// This function is called by the top-level `takeout` function.
//
// Returns a Promise.
const storageTakeout = (uid) => {
  const paths = userPrivacyPaths.storage.takeout;
  let promises = [];
  let takeout = {};

  for (let i = 0; i < paths.length; i++) {
    let entry = paths[i];
    let entryBucket = replaceUID(entry[0], uid);
    let path = replaceUID(entry[1], uid);
    let sourceBucket = storage.bucket(entryBucket);
    let sourceFile = sourceBucket.file(path);

    let destinationPath = `takeout/${uid}/${path}`;

    let copyPromise = sourceFile.copy(destinationPath);
    // Make copyPromise succeed even if it fails:
    copyPromise = copyPromise.catch((err) =>
      console.log('There is an error copying the promise, but keep going.')
    );
    // Add the copy task to the array of Promises
    promises.push(copyPromise);
    takeout[`${entryBucket}/${path}`] = `${appBucketName}/${destinationPath}`;
  }
  return Promise.all(promises).then(() => takeout);
};

// Upload json to Storage, under a filename of the user's uid. This is the final
// result of the takeout function, and because this file will contain personal
// information, it's important to use Firebase Security Rules to make these
// files readable only by the user with the same uid.
//
// Called by the top-level takeout function.
const uploadToStorage = (uid, takeout) => {
  const json = JSON.stringify(takeout);
  const bucket = storage.bucket(appBucketName);
  const file = bucket.file(`takeout/${uid}/takeout.json`);

  return file.save(json);
};

const replaceUID = (str, uid) => {
  return str.replace(/UID_VARIABLE/g, uid);
};
<|endoftext|>