<commit_before>/*
 *  LittleBitsBridge.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-03-22
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  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.
 */

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var bunyan = iotdb.bunyan;

var littlebits = require('littlebits-cloud-http');

var logger = bunyan.createLogger({
    name: 'homestar-littlebits',
    module: 'LittleBitsBridge',
});

/**
 *  EXEMPLAR and INSTANCE
 *

 *  No subclassing needed! The following functions are
 *  injected _after_ this is created, and before .discover and .connect
 *

 *
discovered - tell IOTDB that we're talking to a new Thing
 *
pulled - got new data
 *

 */
var LittleBitsBridge = function (initd, native) {
    var self = this;

    self.initd = _.defaults(initd, {
        access_token: null,
        id: null,
        name: null,
    });
    self.native = native;

    if (self.native) {
        self.connected = {};
    }
};

/* --- lifecycle --- */

/**
 *  EXEMPLAR.
 *  Discover LittleBits Socket
 *

 *
look for Things (using self.bridge data to initialize)
 *
find / create a native that does the talking
 *
create an LittleBitsBridge(native)
 *
call self.discovered(bridge) with it
 */
LittleBitsBridge.prototype.discover = function () {
    var self = this;

    var api = self._api();
    if (!api) {
        logger.error({
            method: "discover",
        }, "LittleBits is not configured correctly");
        return;
    }

    api.devices(function(error, devices) {
        for (var di in devices) {
            var device = devices[di];
            if (self.initd.id && (device.id !== self.initd.id)) {
                continue;
            } else if (self.initd.name && (device.label !== self.initd.name)) {
                continue;
            }

            var native = api.defaults({
                device_id: device.id,
            });

            var initd = _.defaults({
                id: device.id,
                name: device.label,
            }, self.initd);

            self.discovered(new LittleBitsBridge(initd, native));
        };
    });
};

/**
 *  INSTANCE
 *  This is called when this Thing is ready to be used
 */
LittleBitsBridge.prototype.connect = function (connectd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self.connectd = _.defaults(connectd, {
        subscribes: [],
        data_in: function (paramd) {
            paramd.cookd = paramd.rawd;
        },
        data_out: function (paramd) {
            paramd.rawd = paramd.cookd;
        },
    });

    self._setup_events();
};

LittleBitsBridge.prototype._setup_events = function () {
    var self = this;

    for (var si in self.connectd.subscribes) {
        self._setup_event(self.connectd.subscribes[si]);
    }
};

LittleBitsBridge.prototype._setup_event = function (subscribe_id) {
    var self = this;

    self.native.subscribe({
        subscriber_id: self.initd.id,
        publisher_id: self.initd.id,
        publisher_events: [
            "amplitude",
            "amplitude:delta:sustain",
            "amplitude:delta:ignite",
            "amplitude:delta:release",
            "amplitude:delta:nap",
            "amplitude:level:active",
            "amplitude:level:idle",
        ]
    }, function() {
        console.log("HERE:EVENT.ACTIVE", arguments);
    });

};

LittleBitsBridge.prototype._forget = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "_forget"
    }, "called");

    self.native = null;
    self.pulled();
};

/**
 *  INSTANCE and EXEMPLAR (during shutdown).
 *  This is called when the Bridge is no longer needed.
 */
LittleBitsBridge.prototype.disconnect = function () {
    var self = this;
    if (!self.native || !self.native) {
        return;
    }

    self._forget();
};

/* --- data --- */

/**
 *  INSTANCE.
 *  Send data to whatever you're taking to.
 */
LittleBitsBridge.prototype.push = function (pushd) {
    var self = this;
    if (!self.native) {
        return;
    }

    var paramd = {
        cookd: pushd,
        rawd: {},
    };
    self.connectd.data_out(paramd);

    logger.info({
        method: "push",
        unique_id: self.unique_id,
        cookd: paramd.cookd,
        rawd: paramd.rawd,
    }, "pushed");

    if (paramd.rawd.percent !== undefined) {
        self.native.output({
            percent: paramd.rawd.percent,
            duration_ms: -1,
        }, function() {
            console.log("HERE:RESULT", arguments);
        });
    } else if (paramd.rawd.color) {
        /*

        self.native.light({
            color: "yellow",
            mode: "blink",
        }, function() {
        });
        */
    }

    /*
    if (pushed.mode) {
    }

    if (pushed.duration) {
    }

    if (pushed.percent) {
    }

    percent :: Float | >= 0, <= 100

    color :: String | "green" "yellow" "red" "blue" "purple" "white" "cyan" "clownbarf"
    mode :: String | "blink" "hold"
    duration_ms :: Integer | >= 0
    device_id :: String
    */
};

/**
 *  INSTANCE.
 *  Pull data from whatever we're talking to. You don't
 *  have to implement this if it doesn't make sense
 */
LittleBitsBridge.prototype.pull = function () {
    var self = this;
    if (!self.native) {
        return;
    }
};

/* --- state --- */

/**
 *  INSTANCE.
 *  Return the metadata - compact form can be used.
 *  Does not have to work when not reachable
 *

 *  Really really useful things are:
 *

 *
iot:thing required - a unique ID
 *
iot:device suggested if linking multiple things together
 *
schema:name
 *
iot:number
 *
schema:manufacturer
 *
schema:model
 */
LittleBitsBridge.prototype.meta = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    return {
        "iot:thing": _.id.thing_urn.unique("LittleBits", self.initd.id),
        "schema:name": self.initd.name || "LittleBits",
        "schema:manufacturer": "http://littlebits.cc/",
        "schema:model": "http://littlebits.cc/cloud",
    };
};

/**
 *  INSTANCE.
 *  Return True if this is reachable. You
 *  do not need to worry about connect / disconnect /
 *  shutdown states, they will be always checked first.
 */
LittleBitsBridge.prototype.reachable = function () {
    return this.native !== null;
};

/**
 *  INSTANCE.
 *  Configure an express web page to configure this Bridge.
 *  Return the name of the Bridge, which may be
 *  listed and displayed to the user.
 */
LittleBitsBridge.prototype.configure = function (app) {};

/* --- injected: THIS CODE WILL BE REMOVED AT RUNTIME, DO NOT MODIFY  --- */
LittleBitsBridge.prototype.discovered = function (bridge) {
    throw new Error("LittleBitsBridge.discovered not implemented");
};

LittleBitsBridge.prototype.pulled = function (pulld) {
    throw new Error("LittleBitsBridge.pulled not implemented");
};

/* --- internals -- */
var __api;

LittleBitsBridge.prototype._api = function () {
    var self = this;

    /* special case */
    if (self.initd.access_token) {
        return littlebits.defaults({
            access_token: self.initd.access_token,
        });
    }

    /* normal case */
    if (!__api) {
        var access_token = iotdb.keystore().get("/bridges/LittleBitsBridge/account/access_token");
        if (!access_token) {
            logger.error({
                method: "_api",
                cause: "set /bridges/LittleBitsBridge/account/access_token",
            }, "LittleBits is not configured correctly");
            return;
        }

        __api = littlebits.defaults({
            access_token: access_token,
        });
    }

    return __api;
}

/*
 *  API
 */
exports.Bridge = LittleBitsBridge;
<commit_msg>missing items<commit_after>/*
 *  LittleBitsBridge.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-03-22
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  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.
 */

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var bunyan = iotdb.bunyan;

var littlebits = require('littlebits-cloud-http');

var logger = bunyan.createLogger({
    name: 'homestar-littlebits',
    module: 'LittleBitsBridge',
});

/**
 *  EXEMPLAR and INSTANCE
 *

 *  No subclassing needed! The following functions are
 *  injected _after_ this is created, and before .discover and .connect
 *

 *
discovered - tell IOTDB that we're talking to a new Thing
 *
pulled - got new data
 *

 */
var LittleBitsBridge = function (initd, native) {
    var self = this;

    self.initd = _.defaults(initd, {
        access_token: null,
        id: null,
        name: null,
    });
    self.native = native;

    if (self.native) {
        self.connected = {};
    }
};

/* --- lifecycle --- */

/**
 *  EXEMPLAR.
 *  Discover LittleBits Socket
 *

 *
look for Things (using self.bridge data to initialize)
 *
find / create a native that does the talking
 *
create an LittleBitsBridge(native)
 *
call self.discovered(bridge) with it
 */
LittleBitsBridge.prototype.discover = function () {
    var self = this;

    var api = self._api();
    if (!api) {
        logger.error({
            method: "discover",
        }, "LittleBits is not configured correctly");
        return;
    }

    api.devices(function(error, devices) {
        for (var di in devices) {
            var device = devices[di];
            if (self.initd.id && (device.id !== self.initd.id)) {
                continue;
            } else if (self.initd.name && (device.label !== self.initd.name)) {
                continue;
            }

            var native = api.defaults({
                device_id: device.id,
            });

            var initd = _.defaults({
                id: device.id,
                name: device.label,
            }, self.initd);

            self.discovered(new LittleBitsBridge(initd, native));
        };
    });
};

/**
 *  INSTANCE
 *  This is called when this Thing is ready to be used
 */
LittleBitsBridge.prototype.connect = function (connectd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self.connectd = _.defaults(connectd, {
        subscribes: [],
        data_in: function (paramd) {
            paramd.cookd = paramd.rawd;
        },
        data_out: function (paramd) {
            paramd.rawd = paramd.cookd;
        },
    });

    self._setup_events();
};

LittleBitsBridge.prototype._setup_events = function () {
    var self = this;

    for (var si in self.connectd.subscribes) {
        self._setup_event(self.connectd.subscribes[si]);
    }
};

LittleBitsBridge.prototype._setup_event = function (subscribe_id) {
    var self = this;

    self.native.subscribe({
        subscriber_id: self.initd.id,
        publisher_id: self.initd.id,
        publisher_events: [
            "amplitude",
            "amplitude:delta:sustain",
            "amplitude:delta:ignite",
            "amplitude:delta:release",
            "amplitude:delta:nap",
            "amplitude:level:active",
            "amplitude:level:idle",
        ]
    }, function() {
        console.log("HERE:EVENT.ACTIVE", arguments);
    });

};

LittleBitsBridge.prototype._forget = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "_forget"
    }, "called");

    self.native = null;
    self.pulled();
};

/**
 *  INSTANCE and EXEMPLAR (during shutdown).
 *  This is called when the Bridge is no longer needed.
 */
LittleBitsBridge.prototype.disconnect = function () {
    var self = this;
    if (!self.native || !self.native) {
        return;
    }

    self._forget();
};

/* --- data --- */

/**
 *  INSTANCE.
 *  Send data to whatever you're taking to.
 */
LittleBitsBridge.prototype.push = function (pushd) {
    var self = this;
    if (!self.native) {
        return;
    }

    var paramd = {
        cookd: pushd,
        rawd: {},
    };
    self.connectd.data_out(paramd);

    logger.info({
        method: "push",
        unique_id: self.unique_id,
        cookd: paramd.cookd,
        rawd: paramd.rawd,
    }, "pushed");

    if (paramd.rawd.percent !== undefined) {
        self.native.output({
            percent: paramd.rawd.percent,
            duration_ms: -1,
        }, function() {
            // console.log("HERE:RESULT", arguments);
        });
    } else if (paramd.rawd.color) {
        /*

        self.native.light({
            color: "yellow",
            mode: "blink",
        }, function() {
        });
        */
    }

    /*
    if (pushed.mode) {
    }

    if (pushed.duration) {
    }

    if (pushed.percent) {
    }

    percent :: Float | >= 0, <= 100

    color :: String | "green" "yellow" "red" "blue" "purple" "white" "cyan" "clownbarf"
    mode :: String | "blink" "hold"
    duration_ms :: Integer | >= 0
    device_id :: String
    */
};

/**
 *  INSTANCE.
 *  Pull data from whatever we're talking to. You don't
 *  have to implement this if it doesn't make sense
 */
LittleBitsBridge.prototype.pull = function () {
    var self = this;
    if (!self.native) {
        return;
    }
};

/* --- state --- */

/**
 *  INSTANCE.
 *  Return the metadata - compact form can be used.
 *  Does not have to work when not reachable
 *

 *  Really really useful things are:
 *

 *
iot:thing required - a unique ID
 *
iot:device suggested if linking multiple things together
 *
schema:name
 *
iot:number
 *
schema:manufacturer
 *
schema:model
 */
LittleBitsBridge.prototype.meta = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    return {
        "iot:thing": _.id.thing_urn.unique("LittleBits", self.initd.id),
        "schema:name": self.initd.name || "LittleBits",
        "schema:manufacturer": "http://littlebits.cc/",
        "schema:model": "http://littlebits.cc/cloud",
    };
};

/**
 *  INSTANCE.
 *  Return True if this is reachable. You
 *  do not need to worry about connect / disconnect /
 *  shutdown states, they will be always checked first.
 */
LittleBitsBridge.prototype.reachable = function () {
    if (this.native === null) {
        return false;
    }

    return this.native.is_connected;
};

/**
 *  INSTANCE.
 *  Configure an express web page to configure this Bridge.
 *  Return the name of the Bridge, which may be
 *  listed and displayed to the user.
 */
LittleBitsBridge.prototype.configure = function (app) {};

/* --- injected: THIS CODE WILL BE REMOVED AT RUNTIME, DO NOT MODIFY  --- */
LittleBitsBridge.prototype.discovered = function (bridge) {
    throw new Error("LittleBitsBridge.discovered not implemented");
};

LittleBitsBridge.prototype.pulled = function (pulld) {
    throw new Error("LittleBitsBridge.pulled not implemented");
};

/* --- internals -- */
var __api;

LittleBitsBridge.prototype._api = function () {
    var self = this;

    /* special case */
    if (self.initd.access_token) {
        return littlebits.defaults({
            access_token: self.initd.access_token,
        });
    }

    /* normal case */
    if (!__api) {
        var access_token = iotdb.keystore().get("/bridges/LittleBitsBridge/account/access_token");
        if (!access_token) {
            logger.error({
                method: "_api",
                cause: "set /bridges/LittleBitsBridge/account/access_token",
            }, "LittleBits is not configured correctly");
            return;
        }

        __api = littlebits.defaults({
            access_token: access_token,
        });
    }

    return __api;
}

/*
 *  API
 */
exports.Bridge = LittleBitsBridge;
<|endoftext|>


<commit_before>;(function($){

    $.widget('editliveWidgets.textField', $.editliveWidgets.charField, {
        _type: 'text',
        placeholdertag: 'div',
        options: {},
        _create: function() {
            var $self = this;
            if (!$self.options.width) {
                // Restric native textarea resizing to vertical only
                $self.element.css('min-width', $self.element.parent().width() - 17)
                             .css('max-width', $self.element.parent().width() - 17);
            }
            if (!$self.options.width) {
                $self.element.css('min-height', $self.element.height(200));
            }
            $.editliveWidgets.charField.prototype._create.apply(this, arguments);
        },

        set_placeholder_value: function(display) {
            if (this.placeholder) {
                var val = display || this.get_display_value() || this.options.emptyvalue;
                this.placeholder.html(val);
            }
        },

        _get_width: function() {
            return this.placeholder.parent().parent().width();
        },

        _bind_kb_blur_events: function(el) {
            var $self = this;
            (el || $self.element).bind('keyup.editlive', function(e){
                // Same as the parent's _bind_kb_blur_events except that
                // it does not blur on "enter" since it's a textarea. To
                // achieve the same result you must use shift+enter.
                if (e.keyCode == 13 && e.shiftKey) { // enter
                    $self.blur();
                    e.preventDefault(); // otherwise a \n will be inserted
                }
                if (e.keyCode == 27) $self.blur(true); // escape (no save)
            });
        }
    });

})(jQuery);
<commit_msg>Fixed small issue with text widget<commit_after>;(function($){

    $.widget('editliveWidgets.textField', $.editliveWidgets.charField, {
        _type: 'text',
        placeholdertag: 'div',
        options: {wrapclass: ''},
        _create: function() {
            var $self = this;
            if (!$self.options.width) {
                // Restric native textarea resizing to vertical only
                $self.element.css('min-width', $self.element.parent().width() - 17)
                             .css('max-width', $self.element.parent().width() - 17);
            }
            if (!$self.options.width) {
                $self.element.css('min-height', $self.element.height(200));
            }
            $.editliveWidgets.charField.prototype._create.apply(this, arguments);
        },

        set_placeholder_value: function(display) {
            if (this.placeholder) {
                var val = display || this.get_display_value() || this.options.emptyvalue;
                this.placeholder.html(val);
            }
        },

        _get_width: function() {
            return this.placeholder.parent().parent().width();
        },

        _bind_kb_blur_events: function(el) {
            var $self = this;
            (el || $self.element).bind('keyup.editlive', function(e){
                // Same as the parent's _bind_kb_blur_events except that
                // it does not blur on "enter" since it's a textarea. To
                // achieve the same result you must use shift+enter.
                if (e.keyCode == 13 && e.shiftKey) { // enter
                    $self.blur();
                    e.preventDefault(); // otherwise a \n will be inserted
                }
                if (e.keyCode == 27) $self.blur(true); // escape (no save)
            });
        }
    });

})(jQuery);
<|endoftext|>


<commit_before>const jsdom = require('jsdom');
const assert = require('assert');
const { JSDOM } = jsdom;

// jsdom instance
let dom;

// read test page
 JSDOM.fromURL(
    'http://127.0.0.1:8080/test/ui/camessage-test-case.html',
    {
      runScripts: "dangerously",
      resources: "usable"
    }
  ).then(jsdom => {
  	dom = jsdom;
  	// check the loading flag
	let checkLoaded = setInterval(function(){
		console.count('check');
		//console.log(jsdom.window.document.getElementById('isLoad').checked);
		if(jsdom.window.document.getElementById('isLoad').checked){
			clearInterval(checkLoaded);

			console.log(jsdom.window);
			// run test cases if page is ready.
			run();
		}
	},100);
  }).catch(function(error) {
    console.log(error);
  })

//
describe('Ca Message Component', function () {

	// case1: initialize
	it('Initialize', function () {
		const case1 = dom.window.document.getElementById('case1');
		assert.equal(case1.textContent,'Hello World');

	});

	// case 2: change text
	it('Change Text', function () {
		const case2 = dom.window.document.getElementById('case2');
		assert.equal(case2.innerHTML,'Change Text');
	});

	// case 3: change style
	it('Change Style', function () {
		console.log();
		const case3 = dom.window.document.getElementById('case3');
		assert.equal(case3.innerHTML,'case3');
		assert.equal(case3.style.color,'rgb(9, 2, 35)');
		assert.equal(case3.style.fontStyle,'2rem');
		assert.equal(case3.style.backgroundColor,'rgb(193, 13, 13)');
	});
});<commit_msg>fix the typo<commit_after>const jsdom = require('jsdom');
const assert = require('assert');
const { JSDOM } = jsdom;

// jsdom instance
let dom;

// read test page
 JSDOM.fromURL(
    'http://127.0.0.1:8080/test/ui/camessage-test-cases.html',
    {
      runScripts: "dangerously",
      resources: "usable"
    }
  ).then(jsdom => {
  	dom = jsdom;
  	// check the loading flag
	let checkLoaded = setInterval(function(){
		console.count('check');
		//console.log(jsdom.window.document.getElementById('isLoad').checked);
		if(jsdom.window.document.getElementById('isLoad').checked){
			clearInterval(checkLoaded);

			console.log(jsdom.window);
			// run test cases if page is ready.
			run();
		}
	},100);
  }).catch(function(error) {
    console.log(error);
  })

//
describe('Ca Message Component', function () {

	// case1: initialize
	it('Initialize', function () {
		const case1 = dom.window.document.getElementById('case1');
		assert.equal(case1.textContent,'Hello World');

	});

	// case 2: change text
	it('Change Text', function () {
		const case2 = dom.window.document.getElementById('case2');
		assert.equal(case2.innerHTML,'Change Text');
	});

	// case 3: change style
	it('Change Style', function () {
		console.log();
		const case3 = dom.window.document.getElementById('case3');
		assert.equal(case3.innerHTML,'case3');
		assert.equal(case3.style.color,'rgb(9, 2, 35)');
		assert.equal(case3.style.fontStyle,'2rem');
		assert.equal(case3.style.backgroundColor,'rgb(193, 13, 13)');
	});
});<|endoftext|>


<commit_before>const test = require('tape')
require('rewire-global')

const createCsvFile = require('../../messages/createCsvFile')
const azureStorage = createCsvFile.__get__('azureStorage')
azureStorage.cloudStoreTextToFile = () => Promise.resolve()
azureStorage.cloudgetFile = () => Promise.resolve({name: 'a cloud file name'})

test('should only create the header when message has no members', t => {
  t.plan(1)
  const message = {
    _desc: {
      userType: 'students'
    },
    member: []
  }

  createCsvFile(message, 'SF1626VT171', '/tmp/', 'dev-lms-csv').then(result => {
    // TODO: should this really return the name from azure?
    t.deepEqual(result, {csvContent: 'course_id,user_id,role,status\n', name: '/tmp/a cloud file name'})
  })
})

test('should create the header and one more line when message has one member', t => {
  t.plan(1)

  const sisCourseCode = 'SF1626VT171'

  const message = {
    _desc: {
      userType: 'students'
    },
    member: ['abc123']
  }

  createCsvFile(message, sisCourseCode, '/tmp/', 'dev-lms-csv')
  .then(({csvContent}) => {
    // TODO: should this really return the name from azure?
    const expectedCsvContent = `course_id,user_id,role,status
${sisCourseCode},abc123,students,active
`
    t.deepEqual(csvContent, expectedCsvContent)
  })
})

test('should create the file with one line per sisCourseCode when sisCourseCode is an array', t => {
  t.plan(1)

  const message = {
    _desc: {
      userType: 'students'
    },
    member: ['abc123']
  }

  createCsvFile(message, ['SF1626VT171', 'SF1626VT172'], '/tmp/', 'dev-lms-csv').then(({csvContent}) => {
      // TODO: should this really return the name from azure?
    const expectedCsvContent = `course_id,user_id,role,status
SF1626VT171,abc123,students,active
SF1626VT172,abc123,students,active
`
    t.deepEqual(csvContent, expectedCsvContent)
  })
})
<commit_msg>fixed unit tests<commit_after>const test = require('tape')
require('rewire-global')

const createCsvFile = require('../../messages/createCsvFile')
const azureStorage = createCsvFile.__get__('azureStorage')
azureStorage.cloudStoreTextToFile = () => Promise.resolve()
azureStorage.cloudgetFile = () => Promise.resolve({name: 'a cloud file name'})

test('should only create the header when message has no members', t => {
  t.plan(1)
  const message = {
    _desc: {
      userType: 'students'
    },
    member: []
  }

  createCsvFile(message, 'SF1626VT171', '/tmp/', 'dev-lms-csv').then(result => {
    // TODO: should this really return the name from azure?
    t.deepEqual(result, {csvContent: 'section_id,user_id,role,status\n', name: '/tmp/a cloud file name'})
  })
})

test('should create the header and one more line when message has one member', t => {
  t.plan(1)

  const sisCourseCode = 'SF1626VT171'

  const message = {
    _desc: {
      userType: 'students'
    },
    member: ['abc123']
  }

  createCsvFile(message, sisCourseCode, '/tmp/', 'dev-lms-csv')
  .then(({csvContent}) => {
    // TODO: should this really return the name from azure?
    const expectedCsvContent = `section_id,user_id,role,status
${sisCourseCode},abc123,students,active
`
    t.deepEqual(csvContent, expectedCsvContent)
  })
})

test('should create the file with one line per sisCourseCode when sisCourseCode is an array', t => {
  t.plan(1)

  const message = {
    _desc: {
      userType: 'students'
    },
    member: ['abc123']
  }

  createCsvFile(message, ['SF1626VT171', 'SF1626VT172'], '/tmp/', 'dev-lms-csv').then(({csvContent}) => {
      // TODO: should this really return the name from azure?
    const expectedCsvContent = `section_id,user_id,role,status
SF1626VT171,abc123,students,active
SF1626VT172,abc123,students,active
`
    t.deepEqual(csvContent, expectedCsvContent)
  })
})
<|endoftext|>


<commit_before>// import $ from 'jquery';
// import { expect } from 'chai';
import { describe, it } from 'mocha';
// import { View } from 'backbone';
import UserPage from '../../../js/views/userPage/UserPage';

describe('the user page', () => {
  describe('has a select tab method', () => {
    it('which defaults to Store if no tab is set in options when the view is created', () => {
      const userPage = new UserPage();
      console.log(userPage.currentTabView);
      console.log(userPage.currentTabView instanceof userPage.Store);
    });
     /*
    it('which defaults the tab to Store if an invalid targ parameter is passed in', () => {
      const userPage = new UserPage();
      let errorThrown = false;

      try {
        statusBar.pushMessage();
      } catch (e) {
        errorThrown = true;
      }

      try {
        statusBar.pushMessage(true);
      } catch (e) {
        errorThrown = true;
      }

      try {
        statusBar.pushMessage(93);
      } catch (e) {
        errorThrown = true;
      }

      try {
        statusBar.pushMessage(null);
      } catch (e) {
        errorThrown = true;
      }

      try {
        statusBar.pushMessage(undefined);
      } catch (e) {
        errorThrown = true;
      }

      expect(errorThrown).to.equal(true);
    });

    it('which throws an error if you pass in a type, but not one of the available ones', () => {
      const statusBar = new StatusBar();
      let errorThrown = false;

      try {
        statusBar.pushMessage({
          msg: 'The status is moo',
          type: 'dreadful',
        });
      } catch (e) {
        errorThrown = true;
      }

      try {
        statusBar.pushMessage({
          msg: 'The status is moo',
          type: 'saucy',
        });
      } catch (e) {
        errorThrown = true;
      }

      try {
        statusBar.pushMessage({
          msg: 'The status is moo',
          type: 'loopy',
        });
      } catch (e) {
        errorThrown = true;
      }

      expect(errorThrown).to.equal(true);
    });

    const msgTypes = new StatusMessage().getMessageTypes();

    if (msgTypes.length) {
      it('does not throw an error if you pass in a type that is one of the available ones', () => {
        const statusBar = new StatusBar();
        let errorThrown = false;

        try {
          msgTypes.forEach((type) => {
            statusBar.pushMessage({
              msg: 'The status is moo',
              type,
            });
          });
        } catch (e) {
          errorThrown = true;
        }

        expect(errorThrown).to.equal(false);
      });
    }

    it('which throws an error if you pass in a duration, but not as a number', () => {
      const statusBar = new StatusBar();
      let errorThrown = false;

      try {
        statusBar.pushMessage({
          msg: 'The status is moo',
          duration: 'dreadful',
        });
      } catch (e) {
        errorThrown = true;
      }

      try {
        statusBar.pushMessage({
          msg: 'The status is moo',
          duration: true,
        });
      } catch (e) {
        errorThrown = true;
      }

      try {
        statusBar.pushMessage({
          msg: 'The status is moo',
          duration: '5678',
        });
      } catch (e) {
        errorThrown = true;
      }

      expect(errorThrown).to.equal(true);
    });

    it('does not throw an error if you pass in a duration as a number', () => {
      const statusBar = new StatusBar();
      let errorThrown = false;

      try {
        statusBar.pushMessage({
          msg: 'The status is moo',
          duration: 5678,
        });
      } catch (e) {
        errorThrown = true;
      }

      expect(errorThrown).to.equal(false);
    });

    it('throws an error if you pass in a View that is not a descendant of the StatusMessage view',
      () => {
        const statusBar = new StatusBar();
        let errorThrown = false;

        try {
          statusBar.pushMessage({
            msg: 'The status is moo',
            View,
          });
        } catch (e) {
          errorThrown = true;
        }

        expect(errorThrown).to.equal(true);
      });

    it('doesn\'t throw an error if you pass in a View that is a descendant of the StatusMessage' +
      ' view',
      () => {
        const statusBar = new StatusBar();
        let errorThrown = false;

        class MyStatusMsg extends StatusMessageVw {}

        try {
          statusBar.pushMessage({
            msg: 'The status is moo',
            View: MyStatusMsg,
          });
        } catch (e) {
          errorThrown = true;
        }

        expect(errorThrown).to.equal(false);
      });

    it('which results in a new status message being added to the DOM', () => {
      const statusBar = new StatusBar();
      $('#statusBar').html(statusBar.render().el);

      statusBar.pushMessage('check the facts, son');
      statusBar.pushMessage({
        msg: 'green eggs and ham, i am',
      });

      expect($('#statusBar .statusMessage').length).to.equal(2);
    });

    it('which results in a new status message being added to the DOM with the given text', () => {
      const statusBar = new StatusBar();
      $('#statusBar').html(statusBar.render().el);

      statusBar.pushMessage('check the facts, son');
      statusBar.pushMessage({
        msg: 'green eggs and ham, i am',
      });

      expect(
        $('#statusBar .statusMessage').eq(1)
          .text()
          .trim()
      ).to.equal('check the facts, son');

      expect(
        $('#statusBar .statusMessage').eq(0)
          .text()
          .trim()
      ).to.equal('green eggs and ham, i am');
    });

    it('which returns an object with a method to update the text of the status message', () => {
      const statusBar = new StatusBar();
      $('#statusBar').html(statusBar.render().el);

      const statusMessage = statusBar.pushMessage('check the facts, son');

      expect(
        $('#statusBar .statusMessage').eq(0)
          .text()
          .trim()
      ).to.equal('check the facts, son');

      statusMessage.update('feel good yo');

      expect(
        $('#statusBar .statusMessage').eq(0)
          .text()
          .trim()
      ).to.equal('feel good yo');

      statusMessage.update({ msg: 'send a salomi to your boy in the army' });

      expect(
        $('#statusBar .statusMessage').eq(0)
          .text()
          .trim()
      ).to.equal('send a salomi to your boy in the army');
    });
    */
  });
});
<commit_msg>Removing DOM tests for userPage, since jsDOM is not working on Windows and committing to have Travis run the test is too cumbersome.<commit_after><|endoftext|>


<commit_before>#!/usr/bin/env node

import fs from 'fs'
import path from 'path'
import client from 'cheerio-httpcli'
import program from 'commander'

program
    .parse(process.argv);

const contests = program.args;
if( !contests.length )
{
    console.error('contests required');
    process.exit(1);
}

function get_url( contest, path )
{
    return 'http://' + contest + '.contest.atcoder.jp/' + path;
}

contests.forEach( contest => {
    fs.mkdir( contest, err => {
        client.fetch( get_url(contest, 'assignments'), ( err, $, res ) => {
            $('tbody tr').each( function( idx, el ) {
                const linkwrappers = $(el).find('.linkwrapper');
                const task_index = $(linkwrappers.get(0)).text();
                const task_name  = $(linkwrappers.get(1)).text();
                const task_path  = $(linkwrappers.get(1)).attr('href');
                const dir_name = task_index + '_' + task_name.replace(/\//g, '-').replace(/\s/g,'_');
                fs.mkdir( path.join( contest, dir_name ), err => {
                    const task_page_url = get_url(contest, task_path);
                    client.fetch( task_page_url, (err, $, res ) => {
                        $('section').each( function( idx, el ) {
                            const section_title   = $($(el).children().get(0)).text().trim();
                            const section_content = $($(el).children().get(1)).text().trim();

                            const input_match  = /入力例\s*(\d)/.exec( section_title );
                            const output_match = /出力例\s*(\d)/.exec( section_title );
                            const section_file_name = input_match  ? `in_${input_match[1]}.txt`:
                                                   output_match ? `out_${output_match[1]}.txt`:
                                                   null;
                            if( section_file_name )
                            {
                                fs.writeFile( path.join( contest, dir_name, section_file_name ), section_content, err => {
                                    if(err)
                                    {
                                        console.log( err );
                                    }
                                });
                            }
                        });
                    });
                });
            });
        });
    });
});
<commit_msg>change return code into system return code<commit_after>#!/usr/bin/env node

import fs from 'fs'
import path from 'path'
import client from 'cheerio-httpcli'
import program from 'commander'

const return_code = '\n';

program
    .parse(process.argv);

const contests = program.args;
if( !contests.length )
{
    console.error('contests required');
    process.exit(1);
}

function get_url( contest, path )
{
    return 'http://' + contest + '.contest.atcoder.jp/' + path;
}

contests.forEach( contest => {
    fs.mkdir( contest, err => {
        client.fetch( get_url(contest, 'assignments'), ( err, $, res ) => {
            $('tbody tr').each( function( idx, el ) {
                const linkwrappers = $(el).find('.linkwrapper');
                const task_index = $(linkwrappers.get(0)).text();
                const task_name  = $(linkwrappers.get(1)).text();
                const task_path  = $(linkwrappers.get(1)).attr('href');
                const dir_name = task_index + '_' + task_name.replace(/\//g, '-').replace(/\s/g,'_');
                fs.mkdir( path.join( contest, dir_name ), err => {
                    const task_page_url = get_url(contest, task_path);
                    client.fetch( task_page_url, (err, $, res ) => {
                        $('section').each( function( idx, el ) {
                            const section_title   = $($(el).children().get(0)).text()
                                                                              .trim();
                            const section_content = $($(el).children().get(1)).text()
                                                                              .trimLeft()
                                                                              .replace(/\r\n/g,'\n')
                                                                              .replace(/\n/g,return_code);

                            const input_match  = /入力例\s*(\d)/.exec( section_title );
                            const output_match = /出力例\s*(\d)/.exec( section_title );
                            const section_file_name = input_match  ? `in_${input_match[1]}.txt`:
                                                   output_match ? `out_${output_match[1]}.txt`:
                                                   null;
                            if( section_file_name )
                            {
                                fs.writeFile( path.join( contest, dir_name, section_file_name ), section_content, err => {
                                    if(err)
                                    {
                                        console.log( err );
                                    }
                                });
                            }
                        });
                    });
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>/*
 * This file needs to be renamed as app.js when we want to run unit tests
 * in order this to get loaded by the jxcore ready event.
 * This effectively acts as main entry point to the unit test app
 */

'use strict';

var platform = require('thali/NextGeneration/utils/platform');

if (typeof Mobile === 'undefined') {
  var mockPlatform = require('./lib/parsePlatformArg')();
  global.Mobile = require('./lib/wifiBasedNativeMock.js')(mockPlatform);
}

var config = require('./config.json');
var objectAssign = require('object-assign');
process.env = objectAssign(process.env, config.env);

var logger = require('./lib/testLogger')('UnitTest_app');
var testUtils = require('./lib/testUtils');
var ThaliMobile = require('thali/NextGeneration/thaliMobile');
var Promise = require('bluebird');

var utResult = false;

if (platform._isRealMobile) {
  Mobile('executeNativeTests').callNative(function (result) {
    logger.debug('Running unit tests');
    if (result) {
      if (!result.executed) {
        console.log('*Native tests were not executed*');

        utResult = false;
      } else {
        console.log('*Native tests were executed*');

        utResult = result.failed <= 0;
      }

      console.log('Total number of executed tests: ', result.total);
      console.log('Number of passed tests: ', result.passed);
      console.log('Number of failed tests: ', result.failed);
      console.log('Number of ignored tests: ', result.ignored);
      console.log('Total duration: ', result.duration);
    } else {
      console.log('*Native tests results are empty*');

      utResult = false;
    }
  });

  if (!utResult) {
    console.log('Failed to execute UT.');
    global.nativeUTFailed = true;

  }
} else {
  // We aren't on a device so we can't run those tests anyway
  utResult = true;
}

if (!utResult) {
  logger.debug('Failed to execute UT.');
  global.nativeUTFailed = true;
}
//
// if (platform.isIOS) {
//   // Disable node tests for iOS due to issue #1343
//   console.log('****TEST_LOGGER:[PROCESS_ON_EXIT_SUCCESS]****');
//   return;
// }

global.NETWORK_TYPE = ThaliMobile.networkTypes.NATIVE;

ThaliMobile.getNetworkStatus()
.then(function (networkStatus) {
  var promiseList = [];
  if (networkStatus.wifi === 'off') {
    promiseList.push(testUtils.toggleWifi(true));
  }
  if (networkStatus.bluetooth === 'off') {
    promiseList.push(testUtils.toggleBluetooth(true));
  }
  Promise.all(promiseList).then(function () {
    Mobile('GetDeviceName').callNative(function (name) {
      logger.debug('My device name is: %s', name);
      testUtils.setName(name);
      require('./runTests.js');
    });
  });
});

logger.debug('Unit Test app is loaded');
<commit_msg>Disable node test for iOS platform<commit_after>/*
 * This file needs to be renamed as app.js when we want to run unit tests
 * in order this to get loaded by the jxcore ready event.
 * This effectively acts as main entry point to the unit test app
 */

'use strict';

var platform = require('thali/NextGeneration/utils/platform');

if (typeof Mobile === 'undefined') {
  var mockPlatform = require('./lib/parsePlatformArg')();
  global.Mobile = require('./lib/wifiBasedNativeMock.js')(mockPlatform);
}

var config = require('./config.json');
var objectAssign = require('object-assign');
process.env = objectAssign(process.env, config.env);

var logger = require('./lib/testLogger')('UnitTest_app');
var testUtils = require('./lib/testUtils');
var ThaliMobile = require('thali/NextGeneration/thaliMobile');
var Promise = require('bluebird');

var utResult = false;

if (platform._isRealMobile) {
  Mobile('executeNativeTests').callNative(function (result) {
    logger.debug('Running unit tests');
    if (result) {
      if (!result.executed) {
        console.log('*Native tests were not executed*');

        utResult = false;
      } else {
        console.log('*Native tests were executed*');

        utResult = result.failed <= 0;
      }

      console.log('Total number of executed tests: ', result.total);
      console.log('Number of passed tests: ', result.passed);
      console.log('Number of failed tests: ', result.failed);
      console.log('Number of ignored tests: ', result.ignored);
      console.log('Total duration: ', result.duration);
    } else {
      console.log('*Native tests results are empty*');

      utResult = false;
    }
  });

  if (!utResult) {
    console.log('Failed to execute UT.');
    global.nativeUTFailed = true;

  }
} else {
  // We aren't on a device so we can't run those tests anyway
  utResult = true;
}

if (!utResult) {
  logger.debug('Failed to execute UT.');
  global.nativeUTFailed = true;
}

if (platform.isIOS) {
  // Disable node tests for iOS due to issue #1343
  console.log('****TEST_LOGGER:[PROCESS_ON_EXIT_SUCCESS]****');
  return;
}

global.NETWORK_TYPE = ThaliMobile.networkTypes.NATIVE;

ThaliMobile.getNetworkStatus()
.then(function (networkStatus) {
  var promiseList = [];
  if (networkStatus.wifi === 'off') {
    promiseList.push(testUtils.toggleWifi(true));
  }
  if (networkStatus.bluetooth === 'off') {
    promiseList.push(testUtils.toggleBluetooth(true));
  }
  Promise.all(promiseList).then(function () {
    Mobile('GetDeviceName').callNative(function (name) {
      logger.debug('My device name is: %s', name);
      testUtils.setName(name);
      require('./runTests.js');
    });
  });
});

logger.debug('Unit Test app is loaded');
<|endoftext|>


<commit_before>/*
 * This file needs to be renamed as app.js when we want to run unit tests
 * in order this to get loaded by the jxcore ready event.
 * This effectively acts as main entry point to the unit test app
 */

'use strict';

if (typeof Mobile === 'undefined') {
  global.Mobile = require('./lib/wifiBasedNativeMock.js')();
}

var testRunner = require('./runTests.js');
var testUtils = require('./lib/testUtils');
var ThaliMobile = require('thali/NextGeneration/thaliMobile');
var Promise = require('lie');
var utResult;

Mobile('ExecuteNativeTests').callNative(function (result) {
  utResult = true;
  if (result && result.executed) {
    console.log("Total number of executed tests: ", result.total);
    console.log("Number of passed tests: ", result.passed);
    console.log("Number of failed tests: ", result.failed);
    console.log("Number of ignored tests: ", result.ignored);
    console.log("Total duration: ", result.duration);
    if (result.failed > 0) {
      utResult = false;
    }
  }
});

if (!utResult) {
  console.log("Failed to execute UT.");
  console.log('****TEST_LOGGER:[PROCESS_ON_EXIT_FAILED]****');
  return;
}

// TODO finish testing here (the node part will be omitted)
console.log('****TEST_LOGGER:[PROCESS_ON_EXIT_SUCCESS]****');
return;

// Issue #914
var networkTypes = [];
if (process.platform === 'android') {
  global.Mobile = require('./lib/wifiBasedNativeMock.js')();
  networkTypes = [
    ThaliMobile.networkTypes.WIFI,
    ThaliMobile.networkTypes.NATIVE,
    ThaliMobile.networkTypes.BOTH
  ];
} else if (process.platform === 'ios') {
  global.Mobile = require('./lib/wifiBasedNativeMock.js')();
  networkTypes = [
    ThaliMobile.networkTypes.NATIVE,
    ThaliMobile.networkTypes.BOTH
  ];
}

ThaliMobile.getNetworkStatus()
.then(function (networkStatus) {
  var promiseList = [];
  if (networkStatus.wifi === 'off') {
    promiseList.push(testUtils.toggleWifi(true));
  }
  if (networkStatus.bluetooth === 'off') {
    promiseList.push(testUtils.toggleBluetooth(true));
  }
  Promise.all(promiseList)
  .then(function () {
    Mobile('GetDeviceName').callNative(function (name) {
      console.log('My device name is: %s', name);
      testUtils.setName(name);

      networkTypes.reduce(function (sequence, networkType) {
        return sequence
          .then(function () {
            console.log('Running for ' + networkType + ' network type');
            global.NETWORK_TYPE = networkType;
            return testRunner.run();
          });
      }, Promise.resolve());
    });
  });
});

console.log('Unit Test app is loaded');
<commit_msg>Added WiFi network type for iOS test runner<commit_after>/*
 * This file needs to be renamed as app.js when we want to run unit tests
 * in order this to get loaded by the jxcore ready event.
 * This effectively acts as main entry point to the unit test app
 */

'use strict';

if (typeof Mobile === 'undefined') {
  global.Mobile = require('./lib/wifiBasedNativeMock.js')();
}

var testRunner = require('./runTests.js');
var testUtils = require('./lib/testUtils');
var ThaliMobile = require('thali/NextGeneration/thaliMobile');
var Promise = require('lie');
var utResult;

Mobile('ExecuteNativeTests').callNative(function (result) {
  utResult = true;
  if (result && result.executed) {
    console.log("Total number of executed tests: ", result.total);
    console.log("Number of passed tests: ", result.passed);
    console.log("Number of failed tests: ", result.failed);
    console.log("Number of ignored tests: ", result.ignored);
    console.log("Total duration: ", result.duration);
    if (result.failed > 0) {
      utResult = false;
    }
  }
});

if (!utResult) {
  console.log("Failed to execute UT.");
  console.log('****TEST_LOGGER:[PROCESS_ON_EXIT_FAILED]****');
  return;
}

// TODO finish testing here (the node part will be omitted)
console.log('****TEST_LOGGER:[PROCESS_ON_EXIT_SUCCESS]****');
return;

// Issue #914
var networkTypes = [];
if (process.platform === 'android' || process.platform === 'ios') {
  global.Mobile = require('./lib/wifiBasedNativeMock.js')();
  networkTypes = [
    ThaliMobile.networkTypes.WIFI,
    ThaliMobile.networkTypes.NATIVE,
    ThaliMobile.networkTypes.BOTH
  ];
}

ThaliMobile.getNetworkStatus()
.then(function (networkStatus) {
  var promiseList = [];
  if (networkStatus.wifi === 'off') {
    promiseList.push(testUtils.toggleWifi(true));
  }
  if (networkStatus.bluetooth === 'off') {
    promiseList.push(testUtils.toggleBluetooth(true));
  }
  Promise.all(promiseList)
  .then(function () {
    Mobile('GetDeviceName').callNative(function (name) {
      console.log('My device name is: %s', name);
      testUtils.setName(name);

      networkTypes.reduce(function (sequence, networkType) {
        return sequence
          .then(function () {
            console.log('Running for ' + networkType + ' network type');
            global.NETWORK_TYPE = networkType;
            return testRunner.run();
          });
      }, Promise.resolve());
    });
  });
});

console.log('Unit Test app is loaded');
<|endoftext|>


<commit_before>const http = require("https");
const multer = require("multer");
const path = require("path");
const memoryStorage = multer.memoryStorage;
const storage = require("@google-cloud/storage");
const isAuthenticated = require("../api-helpers/authHelpers.js").isAuthenticated;
const Op = require("sequelize").Op;

module.exports = function(app) {
  const {db} = app.settings;

  app.get("/api/companies/", (req, res) => {
    let {days} = req.query;
    let daysAgo = new Date(1318781876406);
    const today = new Date();
    const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
    if (days && (/^\d+$/).test(days)) {
      days = parseInt(days, 10);
      daysAgo = new Date(today - new Date(oneDay * days));
      daysAgo.setHours(23, 59, 59);
    }

    db.Company.findAll({
      where: {
        createdAt: {
          [Op.lt]: today,
          [Op.gt]: daysAgo
        }
      },
      order: [["createdAt", "DESC"]],
      limit: 100,
      include: [db.Country, db.users]
    })
      .then(companies => res.json(companies))
      .catch(err => res.json(err));
  });

  app.get("/api/companies/byUser/:uid", (req, res) => {
    const {uid} = req.params;
    db.Company.findAll({
      where: {uid},
      include: [db.Country],
      order: [["createdAt", "DESC"]]
    })
    .then(companies => res.json(companies))
    .catch(err => res.json(err));
  });

  // Instantiate a storage client
  const googleCloudStorage = storage({
    projectId: process.env.GCLOUD_STORAGE_BUCKET,
    keyFilename: process.env.GCLOUD_KEY_FILE
  });

  // A bucket is a container for objects (files).
  const gcsBucket = googleCloudStorage.bucket("mm-company");

  // Multer is required to process file uploads and make them available via
  // req.files.
  const upload = multer({
    storage: memoryStorage(),
    limits: {
      fileSize: 5 * 1024 * 1024 // no larger than 5mb
    },
    fileFilter: (req, file, callback) => {
      if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
        return callback(new Error("Only image files are allowed!"));
      }
      return callback(null, true);
    }
  });

  app.get("/api/companies/:slug", (req, res) => {
    const {slug} = req.params;
    // const {id: uid} = req.user;
    // console.log("companyid:", id)
    // console.log("req.user:", req.user)

    if (slug === "new") {
      res.json({});
    }
    else if (slug.slice(0, 3) === "ca_") {
      const option = {
        hostname: "m.connectamericas.com",
        path: `/apirest/v6/company/${slug.slice(3, slug.length)}`,
        method: "GET",
        headers: {
          "Accept": "application/json",
          "content-type": "application/json",
          "clientToken": process.env.CA_CLIENT_TOKEN
        }
      };
      const request = response => {
        let result = "";
        // another chunk of data has been recieved, so append it to `str`
        response.on("data", chunk => {
          result += chunk;
        });
        // the whole response has been recieved, so we just print it out here
        response.on("end", () => {
          const err = result ? null : "Not found";
          const json = JSON.parse(result);
          // console.log(result);
          const company = {
            name: json.name,
            website: json.website,
            phone_number: json.phone_number,
            description: json.bussiness_objetives,
            address: json.address + json.address_line2 + json.city + json.country,
            Country: {id:json.country_id, name:json.country},
            profile_image: json.photo_url,
            ca_link: json.public_url,
            catalog: json.catalog
          };
          res.json(company);
        });
      };
      http.request(option, request).end();
    }
    else {
      db.Company.findOne({
        // where: {id, uid},
        where: {slug},
        include: [db.Country]
      }).then(company => {
        const err = company ? null : "Not found";
        res.json(company);
      })
        .catch(err => res.json(err));
    }
  });

  app.delete("/api/companies/:id/:imgType", isAuthenticated, (req, res) => {
    const {id, imgType} = req.params;
    const {file: filename} = req.query;
    db.Company.findOne({
      where: {id}
    }).then(company => {
      if (!company) {
        return res.json({error: "Company not found."});
      }
      if (company.uid !== req.user.id) {
        return res.json({error: "You do not have permission to edit this company."});
      }
      if (company[`${imgType}_image`].replace("https://storage.googleapis.com/mm-company/", "") !== filename) {
        return res.json({error: "You do not have permission to delete this image."});
      }
      const file = gcsBucket.file(filename);
      file.delete().then(() => {
        company.update({
          [`${imgType}_image`]: null
        }).then(() =>
          res.json({
            deleted: true,
            query: req.query
          })
        );
      })
      .catch(err => res.json({error: "File doesn't exist", resp: err}));
    })
    .catch(err => res.json(err));
  });

  /** POST /:id - Uploads new image to google storage and updates DB
  REQUIRED:
    - id (req.params.id)
    - file (req.file)
    - imgType (req.query.imgType)
    /api/companies/1/image?imgType=profile|cover
  */
  const imgUpload = upload.single("image");
  app.post("/api/companies/:id/:imgType", isAuthenticated, (req, res) => {
    const {id, imgType} = req.params;
    db.Company.findOne({
      where: {id}
    }).then(company => {
      if (!company) {
        return res.json({error: "Company not found."});
      }
      if (company.uid !== req.user.id) {
        return res.json({error: "You do not have permission to edit this company."});
      }
      imgUpload(req, res, err => {
        if (err) return res.json({error: err});

        if (!req.file) {
          return res.json({error: "No file."});
        }

        // Create a new blob in the bucket and upload the file data.
        const fname = path.parse(req.file.originalname).name.replace(/\W+/g, "-").toLowerCase();
        const extension = path.parse(req.file.originalname).ext.toLowerCase();
        const fileName = `company/company${id}-${fname}${extension}`;
        const fileTest = gcsBucket.file(fileName);

        fileTest.exists().then(data => {
          const exists = data[0];
          // console.log("exists?", exists);
          // res.json({});

          const blob = gcsBucket.file(fileName);

          // Make sure to set the contentType metadata for the browser to be able
          // to render the image instead of downloading the file (default behavior)
          const blobStream = blob.createWriteStream({
            metadata: {
              contentType: req.file.mimetype
            }
          });

          blobStream.on("error", err => {
            console.log("blobStream error\n\n");
            console.log(err);
          });

          blobStream.on("finish", () => {
            // The public URL can be used to directly access the file via HTTP.
            const publicUrl = `https://storage.googleapis.com/${gcsBucket.name}/${blob.name}`;

            // Make the image public to the web (since we'll be displaying it in browser)
            blob.makePublic().then(() => {
              company.update({
                [`${imgType}_image`]: publicUrl
              }).then(() =>
                res.json({
                  msg: `Success! Image uploaded to ${publicUrl}`,
                  file: publicUrl
                })
              );
            });
          });

          blobStream.end(req.file.buffer);
        });

      });
    })
    .catch(err => res.json(err));
  });

  /** POST / - Create a new entity */
  app.post("/api/companies", isAuthenticated, (req, res) => {
    const {id: uid} = req.user;
    const {body: company} = req;
    company.uid = uid;
    db.Company.create(company).then(company => {
      res.json(company);
    }).catch(error => {
      res.status(500).json({
        error,
        message: "Error in creating company."
      });
    });
  });

  /** GET /:id - Return a given entity */

  /** PUT /:id - Updates a given entity */
  app.put("/api/companies/:id", isAuthenticated, (req, res) => {
    const {id} = req.params;
    db.Company.update(
      req.body,
      {where: {id, uid: req.user.id}, individualHooks: true}
    ).then(company => res.json(company))
      .catch(err => res.json({error: "Unable to edit this company.", errorResp: err}));
  });

  /** DELETE /:id - Deletes a given entity
      WARNING: when deleting a company should also:
        - ensure user has the proper permissions
        - delete any trades associated with this company
  */
  app.delete("/api/companies/:id", isAuthenticated, (req, res) => {
    const {id} = req.params;
    db.Company.findOne({
      where: {id}
    }).then(company => {
      if (!company) {
        return res.json({error: "Company not found."});
      }
      if (company.uid !== req.user.id) {
        return res.json({error: "You do not have permission to delete this company."});
      }
      return company.destroy().then(() =>
        res.json({
          deleted: true,
          query: req.query
        })
      )
      .catch(err => res.json({error: "Unable to delete company.", resp: err}));
    })
    .catch(err => res.json(err));
  });
};
<commit_msg>add activated company filter to company slug endpoint<commit_after>const http = require("https");
const multer = require("multer");
const path = require("path");
const memoryStorage = multer.memoryStorage;
const storage = require("@google-cloud/storage");
const isAuthenticated = require("../api-helpers/authHelpers.js").isAuthenticated;
const Op = require("sequelize").Op;

module.exports = function(app) {
  const {db} = app.settings;

  app.get("/api/companies/", (req, res) => {
    let {days} = req.query;
    let daysAgo = new Date(1318781876406);
    const today = new Date();
    const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
    if (days && (/^\d+$/).test(days)) {
      days = parseInt(days, 10);
      daysAgo = new Date(today - new Date(oneDay * days));
      daysAgo.setHours(23, 59, 59);
    }

    db.Company.findAll({
      where: {
        createdAt: {
          [Op.lt]: today,
          [Op.gt]: daysAgo
        }
      },
      order: [["createdAt", "DESC"]],
      limit: 100,
      include: [db.Country, db.users]
    })
      .then(companies => res.json(companies))
      .catch(err => res.json(err));
  });

  app.get("/api/companies/byUser/:uid", (req, res) => {
    const {uid} = req.params;
    db.Company.findAll({
      where: {uid},
      include: [db.Country],
      order: [["createdAt", "DESC"]]
    })
    .then(companies => res.json(companies))
    .catch(err => res.json(err));
  });

  // Instantiate a storage client
  const googleCloudStorage = storage({
    projectId: process.env.GCLOUD_STORAGE_BUCKET,
    keyFilename: process.env.GCLOUD_KEY_FILE
  });

  // A bucket is a container for objects (files).
  const gcsBucket = googleCloudStorage.bucket("mm-company");

  // Multer is required to process file uploads and make them available via
  // req.files.
  const upload = multer({
    storage: memoryStorage(),
    limits: {
      fileSize: 5 * 1024 * 1024 // no larger than 5mb
    },
    fileFilter: (req, file, callback) => {
      if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
        return callback(new Error("Only image files are allowed!"));
      }
      return callback(null, true);
    }
  });

  app.get("/api/companies/:slug", async (req, res) => {
    const {slug} = req.params;
    // const {id: uid} = req.user;
    // console.log("companyid:", id)
    // console.log("req.user:", req.user)

    if (slug === "new") {
      res.json({});
    }
    else if (slug.slice(0, 3) === "ca_") {
      const option = {
        hostname: "m.connectamericas.com",
        path: `/apirest/v6/company/${slug.slice(3, slug.length)}`,
        method: "GET",
        headers: {
          "Accept": "application/json",
          "content-type": "application/json",
          "clientToken": process.env.CA_CLIENT_TOKEN
        }
      };
      const request = response => {
        let result = "";
        // another chunk of data has been recieved, so append it to `str`
        response.on("data", chunk => {
          result += chunk;
        });
        // the whole response has been recieved, so we just print it out here
        response.on("end", () => {
          const err = result ? null : "Not found";
          const json = JSON.parse(result);
          // console.log(result);
          const company = {
            name: json.name,
            website: json.website,
            phone_number: json.phone_number,
            description: json.bussiness_objetives,
            address: json.address + json.address_line2 + json.city + json.country,
            Country: {id:json.country_id, name:json.country},
            profile_image: json.photo_url,
            ca_link: json.public_url,
            catalog: json.catalog
          };
          res.json(company);
        });
      };
      http.request(option, request).end();
    }
    else {
      try {
        const company = await db.Company.findOne({
          // where: {id, uid},
          where: {slug},
          include: [db.Country]
        });
        const user = await db.users.findOne({where:{id: company.uid}});
        const result = user.activated ? company : "Not found";
        res.json(result);
      } catch (error) {
        res.json(error);
      }
    }
  });

  app.delete("/api/companies/:id/:imgType", isAuthenticated, (req, res) => {
    const {id, imgType} = req.params;
    const {file: filename} = req.query;
    db.Company.findOne({
      where: {id}
    }).then(company => {
      if (!company) {
        return res.json({error: "Company not found."});
      }
      if (company.uid !== req.user.id) {
        return res.json({error: "You do not have permission to edit this company."});
      }
      if (company[`${imgType}_image`].replace("https://storage.googleapis.com/mm-company/", "") !== filename) {
        return res.json({error: "You do not have permission to delete this image."});
      }
      const file = gcsBucket.file(filename);
      file.delete().then(() => {
        company.update({
          [`${imgType}_image`]: null
        }).then(() =>
          res.json({
            deleted: true,
            query: req.query
          })
        );
      })
      .catch(err => res.json({error: "File doesn't exist", resp: err}));
    })
    .catch(err => res.json(err));
  });

  /** POST /:id - Uploads new image to google storage and updates DB
  REQUIRED:
    - id (req.params.id)
    - file (req.file)
    - imgType (req.query.imgType)
    /api/companies/1/image?imgType=profile|cover
  */
  const imgUpload = upload.single("image");
  app.post("/api/companies/:id/:imgType", isAuthenticated, (req, res) => {
    const {id, imgType} = req.params;
    db.Company.findOne({
      where: {id}
    }).then(company => {
      if (!company) {
        return res.json({error: "Company not found."});
      }
      if (company.uid !== req.user.id) {
        return res.json({error: "You do not have permission to edit this company."});
      }
      imgUpload(req, res, err => {
        if (err) return res.json({error: err});

        if (!req.file) {
          return res.json({error: "No file."});
        }

        // Create a new blob in the bucket and upload the file data.
        const fname = path.parse(req.file.originalname).name.replace(/\W+/g, "-").toLowerCase();
        const extension = path.parse(req.file.originalname).ext.toLowerCase();
        const fileName = `company/company${id}-${fname}${extension}`;
        const fileTest = gcsBucket.file(fileName);

        fileTest.exists().then(data => {
          const exists = data[0];
          // console.log("exists?", exists);
          // res.json({});

          const blob = gcsBucket.file(fileName);

          // Make sure to set the contentType metadata for the browser to be able
          // to render the image instead of downloading the file (default behavior)
          const blobStream = blob.createWriteStream({
            metadata: {
              contentType: req.file.mimetype
            }
          });

          blobStream.on("error", err => {
            console.log("blobStream error\n\n");
            console.log(err);
          });

          blobStream.on("finish", () => {
            // The public URL can be used to directly access the file via HTTP.
            const publicUrl = `https://storage.googleapis.com/${gcsBucket.name}/${blob.name}`;

            // Make the image public to the web (since we'll be displaying it in browser)
            blob.makePublic().then(() => {
              company.update({
                [`${imgType}_image`]: publicUrl
              }).then(() =>
                res.json({
                  msg: `Success! Image uploaded to ${publicUrl}`,
                  file: publicUrl
                })
              );
            });
          });

          blobStream.end(req.file.buffer);
        });

      });
    })
    .catch(err => res.json(err));
  });

  /** POST / - Create a new entity */
  app.post("/api/companies", isAuthenticated, (req, res) => {
    const {id: uid} = req.user;
    const {body: company} = req;
    company.uid = uid;
    db.Company.create(company).then(company => {
      res.json(company);
    }).catch(error => {
      res.status(500).json({
        error,
        message: "Error in creating company."
      });
    });
  });

  /** GET /:id - Return a given entity */

  /** PUT /:id - Updates a given entity */
  app.put("/api/companies/:id", isAuthenticated, (req, res) => {
    const {id} = req.params;
    db.Company.update(
      req.body,
      {where: {id, uid: req.user.id}, individualHooks: true}
    ).then(company => res.json(company))
      .catch(err => res.json({error: "Unable to edit this company.", errorResp: err}));
  });

  /** DELETE /:id - Deletes a given entity
      WARNING: when deleting a company should also:
        - ensure user has the proper permissions
        - delete any trades associated with this company
  */
  app.delete("/api/companies/:id", isAuthenticated, (req, res) => {
    const {id} = req.params;
    db.Company.findOne({
      where: {id}
    }).then(company => {
      if (!company) {
        return res.json({error: "Company not found."});
      }
      if (company.uid !== req.user.id) {
        return res.json({error: "You do not have permission to delete this company."});
      }
      return company.destroy().then(() =>
        res.json({
          deleted: true,
          query: req.query
        })
      )
      .catch(err => res.json({error: "Unable to delete company.", resp: err}));
    })
    .catch(err => res.json(err));
  });
};
<|endoftext|>


<commit_before><commit_msg>debugging: when is pipe flushed ?<commit_after><|endoftext|>


<commit_before><commit_msg>also eagerload when `-h` passed<commit_after><|endoftext|>


<commit_before>/**
 * Sync directory watcher
 * @module servers/watcher
 */
const path = require('path');
const fs = require('fs');
const os = require('os');
const ini = require('ini');
const EventEmitter = require('events');
const WError = require('verror').WError;

/**
 * Server class
 */
class Watcher extends EventEmitter {
    /**
     * Create the service
     * @param {App} app                             Application
     * @param {object} config                       Configuration
     * @param {Logger} logger                       Logger service
     * @param {Cacher} cacher                       Cacher service
     * @param {Util} util                           Util service
     */
    constructor(app, config, logger, cacher, util) {
        super();

        this.updates = new Map();
        this.waiting = new Map();
        this.rootWatcher = null;
        this.updatesWatcher = null;

        this._name = null;
        this._app = app;
        this._config = config;
        this._logger = logger;
        this._cacher = cacher;
        this._util = util;
    }

    /**
     * Service name is 'servers.watcher'
     * @type {string}
     */
    static get provides() {
        return 'servers.watcher';
    }

    /**
     * Dependencies as constructor arguments
     * @type {string[]}
     */
    static get requires() {
        return [ 'app', 'config', 'logger', 'cacher', 'util' ];
    }

    /**
     * Update entry lifetime
     */
    static get updatesLifetime() {
        return 10 * 60 * 1000; // ms
    }

    /**
     * Clean updates directory interval
     */
    static get cleanUpdatesInterval() {
        return 10 * 1000; // ms
    }

    /**
     * Initialize the server
     * @param {string} name                     Config section name
     * @return {Promise}
     */
    init(name) {
        this._name = name;

        return Promise.resolve()
            .then(() => {
                let configPath = (os.platform() == 'freebsd' ? '/usr/local/etc/bhdir' : '/etc/bhdir');
                try {
                    fs.accessSync(path.join(configPath, 'bhdir.conf'), fs.constants.F_OK);
                } catch (error) {
                    throw new Error('Could not read bhdir.conf');
                }

                let bhdirConfig = ini.parse(fs.readFileSync(path.join(configPath, 'bhdir.conf'), 'utf8'));
                this._rootDir = bhdirConfig.directory && bhdirConfig.directory.root;
                if (!this._rootDir)
                    throw new Error('No root parameter in directory section of bhdir.conf');
            });
    }

    /**
     * Start the server
     * @param {string} name                     Config section name
     * @return {Promise}
     */
    start(name) {
        if (name !== this._name)
            return Promise.reject(new Error(`Server ${name} was not properly initialized`));

        return Array.from(this._app.get('modules')).reduce(
                (prev, [ curName, curModule ]) => {
                    return prev.then(() => {
                        if (!curModule.register)
                            return;

                        let result = curModule.register(name);
                        if (result === null || typeof result != 'object' || typeof result.then != 'function')
                            throw new Error(`Module '${curName}' register() did not return a Promise`);
                        return result;
                    });
                },
                Promise.resolve()
            )
            .then(() => {
                this._logger.debug('watcher', 'Starting the server');
                this._sessionId = this._util.getRandomString(8, {lower: true, upper: true, digits: true, special: false});

                try {
                    fs.accessSync(this._rootDir, fs.constants.F_OK);
                } catch (error) {
                    this._logger.error(`No access to ${this._rootDir}`);
                    process.exit(1);
                }

                this._logger.debug('watcher', `Watching ${this._rootDir}`);
                this.rootWatcher = fs.watch(this._rootDir, this.onChangeRoot.bind(this));
                if (!this.rootWatcher)
                    throw new Error('Could not install root watcher');

                this.rootWatcher.on('error', this.onErrorRoot.bind(this));

                this._watchUpdates();

                let updatesPath = path.join(this._rootDir, 'updates');
                let files = fs.readdirSync(updatesPath);
                for (let file of files) {
                    let update = fs.readFileSync(path.join(updatesPath, file), 'utf8');
                    try {
                        let json = JSON.parse(update);
                        if (!json.path)
                            throw new Error('No path');

                        json.timestamp = Date.now();
                        this.updates.set(file, json);
                    } catch (error) {
                        fs.unlinkSync(path.join(updatesPath, file));
                    }
                }

                this._cleanUpdatesTimer = setInterval(this.onCleanUpdates.bind(this), this.constructor.cleanUpdatesInterval);
            });
    }

    /**
     * Wait for variable change
     * @param {string} filename                     Variable path
     * @param {number} timeout                      Timeout in ms, 0 for no timeout
     * @return {Promise}
     */
    wait(filename, timeout) {
        let info = this.waiting.get(filename);
        if (!info) {
            info = {
                handlers: new Set(),
            };
            this.waiting.set(filename, info);
        }

        return new Promise((resolve) => {
            let cb = result => {
                this._logger.debug('watcher', `Wait on ${filename} timeout: ${result}`);
                resolve(result);
            };
            info.handlers.add(cb);
            if (timeout)
                setTimeout(() => { cb(true); }, timeout);
        });
    }

    /**
     * Wait for variable change
     * @param {string} filename                     Variable path
     * @return {Promise}
     */
    touch(filename) {
        return new Promise((resolve, reject) => {
            try {
                let json = {
                    path: filename,
                };
                let update = path.join(
                    this._rootDir,
                    'updates',
                    Date.now() + '.' + this._sessionId + '.json'
                );
                fs.writeFileSync(update, JSON.stringify(json) + '\n');
                resolve();
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * Notify about variable change
     * @param {string} filename                     Variable path
     */
    notify(filename) {
        let waiting = this.waiting.get(filename);
        if (!waiting)
            return;

        for (let cb of waiting.handlers)
            cb(false);
        this.waiting.delete(filename);
    }

    /**
     * Root directory changed
     * @param {string} eventType                        Either 'rename' or 'change'
     * @param {string} [filename]                       Name of the file
     */
    onChangeRoot(eventType, filename) {
        this._logger.debug('watcher', `Root event: ${eventType}, ${filename}`);
        this._watchUpdates();
    }

    /**
     * Root directory watcher error
     * @param {Error} error                             Error object
     */
    onErrorRoot(error) {
        this._logger.error(`Root directory error: ${error.message}`);
    }

    /**
     * Updates directory changed
     * @param {string} eventType                        Either 'rename' or 'change'
     * @param {string} [filename]                       Name of the file
     */
    onChangeUpdates(eventType, filename) {
        this._logger.debug('watcher', `Updates event: ${eventType}, ${filename}`);
        let updatesPath = path.join(this._rootDir, 'updates');
        try {
            let updates = [];
            let files = fs.readdirSync(updatesPath);
            for (let file of files) {
                if (this.updates.has(file))
                    continue;

                let update = fs.readFileSync(path.join(updatesPath, file), 'utf8');
                try {
                    let json = JSON.parse(update);
                    if (!json.path)
                        throw new Error('No path');

                    json.timestamp = Date.now();
                    this.updates.set(file, json);

                    let parts = file.split('.');
                    if (parts.length >= 3 && parts[1] != this._sessionId)
                       updates.push(json);
                } catch (error) {
                    fs.unlinkSync(path.join(updatesPath, file));
                }
            }

            for (let update of updates) {
                this._logger.debug('watcher', `Path updated: ${update.path}`);
                this.notify(update.path);
                this._cacher.unset(update.path)
                    .catch(error => {
                        this._logger.error(new WError(error, 'Watcher._watchUpdates(): unset'));
                    });
            }
        } catch (error) {
            this._logger.error(new WError(error, 'Watcher._watchUpdates()'));
        }
    }

    /**
     * Updates directory watcher error
     * @param {Error} error                             Error object
     */
    onErrorUpdates(error) {
        this._logger.error(`Updates directory error: ${error.message}`);
    }

    /**
     * Delete expired updates
     */
    onCleanUpdates() {
        let updatesPath = path.join(this._rootDir, 'updates');
        let expiration = Date.now() - this.constructor.updatesLifetime;
        for (let [ name, info ] of this.updates) {
            if (info.timestamp < expiration) {
                this._logger.debug('watcher', `Update expired: ${name}`);
                fs.unlinkSync(path.join(updatesPath, name));
                this.updates.delete(name);
            }
        }
    }
    /**
     * Create and watch updates directory
     */
    _watchUpdates() {
        let updates, updatesPath = path.join(this._rootDir, 'updates');
        try {
            fs.accessSync(updatesPath, fs.constants.F_OK);
            updates = true;
        } catch (error) {
            updates = false;
        }

        if (this.updatesWatcher) {
            if (!updates) {
                this.updatesWatcher.close();
                this.updatesWatcher = null;
            } else {
                return;
            }
        }

        try {
            if (!updates)
                fs.mkdirSync(updatesPath, 0o755);

            this._logger.debug('watcher', `Watching ${updatesPath}`);
            this.updatesWatcher = fs.watch(updatesPath, this.onChangeUpdates.bind(this));
            if (!this.updatesWatcher)
                throw new Error('Could not install updates watcher');

            this.updatesWatcher.on('error', this.onErrorUpdates.bind(this));
            this._logger.info('Watcher installed');
        } catch (error) {
            this._logger.error(new WError(error, 'Watcher._watchUpdates'));
        }
    }
}

module.exports = Watcher;
<commit_msg>Notify on file update<commit_after>/**
 * Sync directory watcher
 * @module servers/watcher
 */
const path = require('path');
const fs = require('fs');
const os = require('os');
const ini = require('ini');
const EventEmitter = require('events');
const WError = require('verror').WError;

/**
 * Server class
 */
class Watcher extends EventEmitter {
    /**
     * Create the service
     * @param {App} app                             Application
     * @param {object} config                       Configuration
     * @param {Logger} logger                       Logger service
     * @param {Cacher} cacher                       Cacher service
     * @param {Util} util                           Util service
     */
    constructor(app, config, logger, cacher, util) {
        super();

        this.updates = new Map();
        this.waiting = new Map();
        this.rootWatcher = null;
        this.updatesWatcher = null;

        this._name = null;
        this._app = app;
        this._config = config;
        this._logger = logger;
        this._cacher = cacher;
        this._util = util;
    }

    /**
     * Service name is 'servers.watcher'
     * @type {string}
     */
    static get provides() {
        return 'servers.watcher';
    }

    /**
     * Dependencies as constructor arguments
     * @type {string[]}
     */
    static get requires() {
        return [ 'app', 'config', 'logger', 'cacher', 'util' ];
    }

    /**
     * Update entry lifetime
     */
    static get updatesLifetime() {
        return 10 * 60 * 1000; // ms
    }

    /**
     * Clean updates directory interval
     */
    static get cleanUpdatesInterval() {
        return 10 * 1000; // ms
    }

    /**
     * Initialize the server
     * @param {string} name                     Config section name
     * @return {Promise}
     */
    init(name) {
        this._name = name;

        return Promise.resolve()
            .then(() => {
                let configPath = (os.platform() == 'freebsd' ? '/usr/local/etc/bhdir' : '/etc/bhdir');
                try {
                    fs.accessSync(path.join(configPath, 'bhdir.conf'), fs.constants.F_OK);
                } catch (error) {
                    throw new Error('Could not read bhdir.conf');
                }

                let bhdirConfig = ini.parse(fs.readFileSync(path.join(configPath, 'bhdir.conf'), 'utf8'));
                this._rootDir = bhdirConfig.directory && bhdirConfig.directory.root;
                if (!this._rootDir)
                    throw new Error('No root parameter in directory section of bhdir.conf');
            });
    }

    /**
     * Start the server
     * @param {string} name                     Config section name
     * @return {Promise}
     */
    start(name) {
        if (name !== this._name)
            return Promise.reject(new Error(`Server ${name} was not properly initialized`));

        return Array.from(this._app.get('modules')).reduce(
                (prev, [ curName, curModule ]) => {
                    return prev.then(() => {
                        if (!curModule.register)
                            return;

                        let result = curModule.register(name);
                        if (result === null || typeof result != 'object' || typeof result.then != 'function')
                            throw new Error(`Module '${curName}' register() did not return a Promise`);
                        return result;
                    });
                },
                Promise.resolve()
            )
            .then(() => {
                this._logger.debug('watcher', 'Starting the server');
                this._sessionId = this._util.getRandomString(8, {lower: true, upper: true, digits: true, special: false});

                try {
                    fs.accessSync(this._rootDir, fs.constants.F_OK);
                } catch (error) {
                    this._logger.error(`No access to ${this._rootDir}`);
                    process.exit(1);
                }

                this._logger.debug('watcher', `Watching ${this._rootDir}`);
                this.rootWatcher = fs.watch(this._rootDir, this.onChangeRoot.bind(this));
                if (!this.rootWatcher)
                    throw new Error('Could not install root watcher');

                this.rootWatcher.on('error', this.onErrorRoot.bind(this));

                this._watchUpdates();

                let updatesPath = path.join(this._rootDir, 'updates');
                let files = fs.readdirSync(updatesPath);
                for (let file of files) {
                    let update = fs.readFileSync(path.join(updatesPath, file), 'utf8');
                    try {
                        let json = JSON.parse(update);
                        if (!json.path)
                            throw new Error('No path');

                        json.timestamp = Date.now();
                        this.updates.set(file, json);
                    } catch (error) {
                        fs.unlinkSync(path.join(updatesPath, file));
                    }
                }

                this._cleanUpdatesTimer = setInterval(this.onCleanUpdates.bind(this), this.constructor.cleanUpdatesInterval);
            });
    }

    /**
     * Wait for variable change
     * @param {string} filename                     Variable path
     * @param {number} timeout                      Timeout in ms, 0 for no timeout
     * @return {Promise}
     */
    wait(filename, timeout) {
        let info = this.waiting.get(filename);
        if (!info) {
            info = {
                handlers: new Set(),
            };
            this.waiting.set(filename, info);
        }

        return new Promise((resolve) => {
            let cb = result => {
                this._logger.debug('watcher', `Wait on ${filename} timeout: ${result}`);
                resolve(result);
            };
            info.handlers.add(cb);
            if (timeout)
                setTimeout(() => { cb(true); }, timeout);
        });
    }

    /**
     * Wait for variable change
     * @param {string} filename                     Variable path
     * @return {Promise}
     */
    touch(filename) {
        return new Promise((resolve, reject) => {
            try {
                let json = {
                    path: filename,
                };
                let update = path.join(
                    this._rootDir,
                    'updates',
                    Date.now() + '.' + this._sessionId + '.json'
                );
                fs.writeFileSync(update, JSON.stringify(json) + '\n');
                resolve();
            } catch (error) {
                reject(error);
            }
        });
    }

    /**
     * Notify about variable change
     * @param {string} filename                     Variable path
     */
    notify(filename) {
        let waiting = this.waiting.get(filename);
        if (!waiting)
            return;

        for (let cb of waiting.handlers)
            cb(false);
        this.waiting.delete(filename);
    }

    /**
     * Root directory changed
     * @param {string} eventType                        Either 'rename' or 'change'
     * @param {string} [filename]                       Name of the file
     */
    onChangeRoot(eventType, filename) {
        this._logger.debug('watcher', `Root event: ${eventType}, ${filename}`);
        this._watchUpdates();
    }

    /**
     * Root directory watcher error
     * @param {Error} error                             Error object
     */
    onErrorRoot(error) {
        this._logger.error(`Root directory error: ${error.message}`);
    }

    /**
     * Updates directory changed
     * @param {string} eventType                        Either 'rename' or 'change'
     * @param {string} [filename]                       Name of the file
     */
    onChangeUpdates(eventType, filename) {
        this._logger.debug('watcher', `Updates event: ${eventType}, ${filename}`);
        let updatesPath = path.join(this._rootDir, 'updates');
        try {
            let updates = [];
            let files = fs.readdirSync(updatesPath);
            for (let file of files) {
                if (this.updates.has(file))
                    continue;

                let update = fs.readFileSync(path.join(updatesPath, file), 'utf8');
                try {
                    let json = JSON.parse(update);
                    if (!json.path)
                        throw new Error('No path');

                    json.timestamp = Date.now();
                    this.updates.set(file, json);

                    let parts = file.split('.');
                    if (parts.length >= 3 && parts[1] != this._sessionId)
                       updates.push(json);
                } catch (error) {
                    fs.unlinkSync(path.join(updatesPath, file));
                }
            }

            for (let update of updates) {
                this._logger.debug('watcher', `Path updated: ${update.path}`);
                this._cacher.unset(update.path)
                    .then(
                        () => {
                            this.notify(update.path);
                        },
                        error => {
                            this.notify(update.path);
                            this._logger.error(new WError(error, 'Watcher._watchUpdates(): unset'));
                        }
                    );
            }
        } catch (error) {
            this._logger.error(new WError(error, 'Watcher._watchUpdates()'));
        }
    }

    /**
     * Updates directory watcher error
     * @param {Error} error                             Error object
     */
    onErrorUpdates(error) {
        this._logger.error(`Updates directory error: ${error.message}`);
    }

    /**
     * Delete expired updates
     */
    onCleanUpdates() {
        let updatesPath = path.join(this._rootDir, 'updates');
        let expiration = Date.now() - this.constructor.updatesLifetime;
        for (let [ name, info ] of this.updates) {
            if (info.timestamp < expiration) {
                this._logger.debug('watcher', `Update expired: ${name}`);
                fs.unlinkSync(path.join(updatesPath, name));
                this.updates.delete(name);
            }
        }
    }
    /**
     * Create and watch updates directory
     */
    _watchUpdates() {
        let updates, updatesPath = path.join(this._rootDir, 'updates');
        try {
            fs.accessSync(updatesPath, fs.constants.F_OK);
            updates = true;
        } catch (error) {
            updates = false;
        }

        if (this.updatesWatcher) {
            if (!updates) {
                this.updatesWatcher.close();
                this.updatesWatcher = null;
            } else {
                return;
            }
        }

        try {
            if (!updates)
                fs.mkdirSync(updatesPath, 0o755);

            this._logger.debug('watcher', `Watching ${updatesPath}`);
            this.updatesWatcher = fs.watch(updatesPath, this.onChangeUpdates.bind(this));
            if (!this.updatesWatcher)
                throw new Error('Could not install updates watcher');

            this.updatesWatcher.on('error', this.onErrorUpdates.bind(this));
            this._logger.info('Watcher installed');
        } catch (error) {
            this._logger.error(new WError(error, 'Watcher._watchUpdates'));
        }
    }
}

module.exports = Watcher;
<|endoftext|>


<commit_before><commit_msg>debugging socket.io<commit_after><|endoftext|>


<commit_before>import Ember from "ember-metal/core";
import {
  meta,
  typeOf
} from "ember-metal/utils";
import { defineProperty as o_defineProperty, hasPropertyAccessors } from "ember-metal/platform";
import { MANDATORY_SETTER_FUNCTION, DEFAULT_GETTER_FUNCTION } from "ember-metal/properties";

var metaFor = meta; // utils.js

export function watchKey(obj, keyName, meta) {
  // can't watch length on Array - it is special...
  if (keyName === 'length' && typeOf(obj) === 'array') { return; }

  var m = meta || metaFor(obj), watching = m.watching;

  // activate watching first time
  if (!watching[keyName]) {
    watching[keyName] = 1;

    var desc = m.descs[keyName];
    if (desc && desc.willWatch) { desc.willWatch(obj, keyName); }

    if ('function' === typeof obj.willWatchProperty) {
      obj.willWatchProperty(keyName);
    }

    if (Ember.FEATURES.isEnabled('mandatory-setter')) {
      if (hasPropertyAccessors) {
        handleMandatorySetter(m, obj, keyName);
      }
    }
  } else {
    watching[keyName] = (watching[keyName] || 0) + 1;
  }
}

if (Ember.FEATURES.isEnabled('mandatory-setter')) {
  var handleMandatorySetter = function handleMandatorySetter(m, keyName, obj) {
    // this x in Y deopts, so keeping it in this function is better;
    if (keyName in obj) {
      m.values[keyName] = obj[keyName];
      o_defineProperty(obj, keyName, {
        configurable: true,
        enumerable: obj.propertyIsEnumerable(keyName),
        set: MANDATORY_SETTER_FUNCTION,
        get: DEFAULT_GETTER_FUNCTION(keyName)
      });
    }
  };
}

export function unwatchKey(obj, keyName, meta) {
  var m = meta || metaFor(obj), watching = m.watching;

  if (watching[keyName] === 1) {
    watching[keyName] = 0;

    var desc = m.descs[keyName];
    if (desc && desc.didUnwatch) { desc.didUnwatch(obj, keyName); }

    if ('function' === typeof obj.didUnwatchProperty) {
      obj.didUnwatchProperty(keyName);
    }

    if (Ember.FEATURES.isEnabled('mandatory-setter')) {
      if (hasPropertyAccessors && keyName in obj) {
        o_defineProperty(obj, keyName, {
          configurable: true,
          enumerable: obj.propertyIsEnumerable(keyName),
          set: function(val) {
            // redefine to set as enumerable
            o_defineProperty(obj, keyName, {
              configurable: true,
              writable: true,
              enumerable: true,
              value: val
            });
            delete m.values[keyName];
          },
          get: DEFAULT_GETTER_FUNCTION(keyName)
        });
      }
    }
  } else if (watching[keyName] > 1) {
    watching[keyName]--;
  }
}
<commit_msg>Fix argument order for handleMandatorySetter.<commit_after>import Ember from "ember-metal/core";
import {
  meta,
  typeOf
} from "ember-metal/utils";
import { defineProperty as o_defineProperty, hasPropertyAccessors } from "ember-metal/platform";
import { MANDATORY_SETTER_FUNCTION, DEFAULT_GETTER_FUNCTION } from "ember-metal/properties";

var metaFor = meta; // utils.js

export function watchKey(obj, keyName, meta) {
  // can't watch length on Array - it is special...
  if (keyName === 'length' && typeOf(obj) === 'array') { return; }

  var m = meta || metaFor(obj), watching = m.watching;

  // activate watching first time
  if (!watching[keyName]) {
    watching[keyName] = 1;

    var desc = m.descs[keyName];
    if (desc && desc.willWatch) { desc.willWatch(obj, keyName); }

    if ('function' === typeof obj.willWatchProperty) {
      obj.willWatchProperty(keyName);
    }

    if (Ember.FEATURES.isEnabled('mandatory-setter')) {
      if (hasPropertyAccessors) {
        handleMandatorySetter(m, obj, keyName);
      }
    }
  } else {
    watching[keyName] = (watching[keyName] || 0) + 1;
  }
}

if (Ember.FEATURES.isEnabled('mandatory-setter')) {
  var handleMandatorySetter = function handleMandatorySetter(m, obj, keyName) {
    // this x in Y deopts, so keeping it in this function is better;
    if (keyName in obj) {
      m.values[keyName] = obj[keyName];
      o_defineProperty(obj, keyName, {
        configurable: true,
        enumerable: obj.propertyIsEnumerable(keyName),
        set: MANDATORY_SETTER_FUNCTION,
        get: DEFAULT_GETTER_FUNCTION(keyName)
      });
    }
  };
}

export function unwatchKey(obj, keyName, meta) {
  var m = meta || metaFor(obj), watching = m.watching;

  if (watching[keyName] === 1) {
    watching[keyName] = 0;

    var desc = m.descs[keyName];
    if (desc && desc.didUnwatch) { desc.didUnwatch(obj, keyName); }

    if ('function' === typeof obj.didUnwatchProperty) {
      obj.didUnwatchProperty(keyName);
    }

    if (Ember.FEATURES.isEnabled('mandatory-setter')) {
      if (hasPropertyAccessors && keyName in obj) {
        o_defineProperty(obj, keyName, {
          configurable: true,
          enumerable: obj.propertyIsEnumerable(keyName),
          set: function(val) {
            // redefine to set as enumerable
            o_defineProperty(obj, keyName, {
              configurable: true,
              writable: true,
              enumerable: true,
              value: val
            });
            delete m.values[keyName];
          },
          get: DEFAULT_GETTER_FUNCTION(keyName)
        });
      }
    }
  } else if (watching[keyName] > 1) {
    watching[keyName]--;
  }
}
<|endoftext|>