<commit_before>'use strict';

angular.module('arachne.visualizations.directives')
    .directive('con10tLineChart', ['$http', '$q', function ($http, $q) {
        return {
            restrict: 'E',
            scope: {
                letterDataPath: '@'
            },
            link: function (scope, element, attrs) {
                var dataQueries = [];

                dataQueries.push($http.get(scope.letterDataPath));

                scope.display = document.querySelector('#date-range-display-linechart');

                scope.selectionStartDate = null;
                scope.selectionEndDate = null;

                $q.all(dataQueries)
                    .then(function(responses) {
                        scope.processTsvData(
                            scope.parseTsvData(responses[0].data)
                        );
                        scope.initializeD3();
                        scope.updateState();
                    });

                scope.parseTsvData = function(data){
                    var parsedRows = [];
                    var lines = data.split('\n');

                    var headings = lines[0].split('\t');

                    var line_index = 1;
                    while (line_index < lines.length && lines[line_index].trim() !== '') {
                        var parsedLine = {};
                        var values = lines[line_index].split('\t');

                        var columnIndex = 0;

                        while (columnIndex < headings.length) {
                            parsedLine[headings[columnIndex]] = values[columnIndex];
                            columnIndex += 1;
                        }

                        parsedRows.push(parsedLine);
                        line_index += 1
                    }

                    return parsedRows
                };

                scope.processTsvData = function(tsvData) {
                    scope.data = [];
                    scope.binnedData = {};
                    scope.minDate = new Date('2018-01-01');
                    scope.maxDate = new Date('0000-01-01');

                    for(var i = 0; i < tsvData.length; i++){
                        var currentLetter = tsvData[i];

                        var fromDate = new Date(currentLetter['origin_date_from']);
                        var toDate = new Date(currentLetter['origin_date_to']);

                        if(fromDate.toString() === 'Invalid Date' || toDate.toString() === 'Invalid Date'){
                            continue;
                        }

                        if(fromDate.toISOString() === toDate.toISOString()) {
                            var binKey = fromDate.toISOString().substr(0,4);

                            if(new Date(binKey) < scope.minDate) scope.minDate = new Date(binKey);
                            if(new Date(binKey) > scope.maxDate) scope.maxDate = new Date(binKey);

                            if(binKey in scope.binnedData) {
                                scope.binnedData[binKey] += 1
                            } else {
                                scope.binnedData[binKey] = 1
                            }
                        } else {
                            var fromBinKey = fromDate.toISOString().substr(0,4);
                            var toBinKey = toDate.toISOString().substr(0,4);

                            if(new Date(fromBinKey) < scope.minDate) scope.minDate = new Date(fromBinKey);
                            if(new Date(toBinKey) > scope.maxDate) scope.maxDate = new Date(toBinKey);

                            if(fromBinKey in scope.binnedData) {
                                scope.binnedData[fromBinKey] += 1
                            } else {
                                scope.binnedData[fromBinKey] = 1
                            }

                            if(toBinKey in scope.binnedData) {
                                scope.binnedData[toBinKey] += 1
                            } else {
                                scope.binnedData[toBinKey] = 1
                            }
                        }
                    }

                    for(var binKey in scope.binnedData){
                        scope.data.push({
                            'date': new Date(binKey),
                            'count': scope.binnedData[binKey]
                        });
                    }

                    scope.data.sort(function(a, b) {
                        return a.date - b.date;
                    });

                    var getYearsInbetween = function (startYear, endYear) {
                        var result = [];
                        var currentYear = startYear + 1;

                        while(currentYear < endYear){
                            result.push(
                                {
                                    'date': new Date(currentYear, 1, 1),
                                    'count': 0
                                });
                            currentYear += 1;
                        }

                        return result;
                    };

                    for(var i = 0; i < scope.data.length - 1; i++) {

                        if(scope.data[i]['date'].getFullYear() + 1 !== scope.data[i + 1]['date'].getFullYear()){
                            var inbetween = getYearsInbetween(
                                scope.data[i]['date'].getFullYear(),
                                scope.data[i + 1]['date'].getFullYear()
                            );

                            for(var j = 0; j < inbetween.length; j++){
                                scope.data.splice(i + 1 + j, 0, inbetween[j])
                            }
                        }
                    }
                };

                scope.initializeD3 = function(){
                    var margin = {top: 20, right: 50, bottom: 30, left: 50},
                        width = 960 - margin.left - margin.right,
                        height = 200 - margin.top - margin.bottom;

                    var bisectDate = d3.bisector(function(d) { return d.date; }).left;

                    var x = d3.scaleTime()
                        .range([0, width]);

                    var y = d3.scaleLinear()
                        .range([height, 0]);

                    var xAxis = d3.axisBottom()
                        .scale(x);

                    var yAxis = d3.axisLeft()
                        .scale(y);

                    var line = d3.line()
                        .x(function(d) { return x(d.date); })
                        .y(function(d) { return y(d.count); });

                    scope.svg = d3.select("svg")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                        .append("g")
                        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

                    x.domain([scope.data[0].date, scope.data[scope.data.length - 1].date]);
                    y.domain(d3.extent(scope.data, function(d) { return d.count; }));

                    scope.svg.append("g")
                        .attr("class", "x axis")
                        .attr("transform", "translate(0," + height + ")")
                        .call(xAxis);

                    scope.svg.append("g")
                        .attr("class", "y axis")
                        .call(yAxis)
                        .append("text")
                        .attr("transform", "rotate(-90)")
                        .attr("y", 6)
                        .attr("dy", ".71em")
                        .style("text-anchor", "end")
                        .text("Price ($)");

                    scope.svg.append("path")
                        .datum(scope.data)
                        .attr("class", "line")
                        .attr("d", line);

                    var selection = scope.svg.append('rect')
                        .attr('x', 10)
                        .attr('y', 0)
                        .attr('width', 50)
                        .attr('height', height)
                        .attr('opacity', .0)
                        .style("fill", function(d) { return '#729AB4'; });

                    var focus = scope.svg.append("g")
                        .attr("class", "focus")
                        .style("display", "none");

                    focus.append("circle")
                        .attr("r", 4.5);

                    focus.append("text")
                        .attr("x", 9)
                        .attr("dy", ".35em");

                    scope.svg.append("rect")
                        .attr("class", "overlay")
                        .attr("width", width)
                        .attr("height", height)
                        .on("mouseover", function() { focus.style("display", null); })
                        .on("mouseout", function() { focus.style("display", "none"); })
                        .on("mousemove", mousemove);

                    function mousemove() {
                        var x0 = x.invert(d3.mouse(this)[0]),
                            i = bisectDate(scope.data, x0, 1),
                            d0 = scope.data[i - 1],
                            d1 = scope.data[i],
                            d = x0 - d0.date > d1.date - x0 ? d1 : d0;
                        focus.attr("transform", "translate(" + x(d.date) + "," + y(d.count) + ")");
                        focus.select("text").text(d.date.getFullYear() + '(' + d.count +')');
                    }

                    function dragStart() {
                        var mousePosition = d3.mouse(this);
                        var xPos = mousePosition[0];

                        if(xPos < 0) xPos = 0;
                        if(xPos > width) xPos = width;

                        scope.startPosition = xPos;

                        scope.selectionStartDate = null;
                        scope.selectionEndDate = null;

                        selection.attr('width', 0);
                        selection.attr("opacity", .5);
                        selection.attr('x', xPos);

                        scope.selectionStartDate = getDateForPosition(xPos);
                    }

                    function dragMove() {
                        var mousePosition = d3.mouse(this);
                        var xPos = mousePosition[0];

                        if(xPos < 0) xPos = 0;
                        if(xPos > width) xPos = width;

                        if(scope.startPosition < xPos) {
                            selection.attr('width', xPos - scope.startPosition)
                        } else {
                            selection.attr('x', xPos);
                            selection.attr('width', scope.startPosition - xPos)
                        }

                        scope.selectionEndDate = getDateForPosition(xPos);
                        scope.updateState()
                    }

                    function dragEnd() {
                    }

                    function getDateForPosition(xPos) {
                        var i = bisectDate(scope.data, x.invert(xPos), 1);
                        var d0 = scope.data[i - 1],
                            d1 = scope.data[i],
                            date = xPos - d0.date > d1.date - xPos ? d1 : d0;

                        return date;
                    }

                    var dragBehavior = d3.drag()
                        .on("drag", dragMove)
                        .on("start", dragStart)
                        .on("end", dragEnd);

                    scope.svg.call(dragBehavior);
                };

                scope.updateState = function () {

                    if(scope.selectionStartDate != null && scope.selectionEndDate != null){
                        scope.from = null;
                        scope.to = null;

                        if(scope.selectionStartDate['date'] < scope.selectionEndDate['date']){
                            scope.from = scope.selectionStartDate['date'];
                            scope.to = scope.selectionEndDate['date'];

                        } else if(scope.selectionStartDate['date'] > scope.selectionEndDate['date']){
                            scope.from = scope.selectionEndDate['date'];
                            scope.to = scope.selectionStartDate['date'];
                        } else {
                            scope.from = scope.to = scope.selectionEndDate['date'];
                        }

                        scope.display.innerHTML =
                            scope.from.toISOString()
                            + ' to '
                            + scope.to.toISOString();
                    }
                }
            }
        }
    }]);<commit_msg>Set line chart width to match its elements's width<commit_after>'use strict';

angular.module('arachne.visualizations.directives')
    .directive('con10tLineChart', ['$http', '$q', function ($http, $q) {
        return {
            restrict: 'A',
            scope: {
                letterDataPath: '@'
            },
            link: function (scope, element, attrs) {
                var dataQueries = [];

                dataQueries.push($http.get(scope.letterDataPath));

                scope.display = document.querySelector('#date-range-display-linechart');

                scope.selectionStartDate = null;
                scope.selectionEndDate = null;

                $q.all(dataQueries)
                    .then(function(responses) {
                        scope.processTsvData(
                            scope.parseTsvData(responses[0].data)
                        );
                        scope.initializeD3();
                        scope.updateState();
                    });

                scope.parseTsvData = function(data){
                    var parsedRows = [];
                    var lines = data.split('\n');

                    var headings = lines[0].split('\t');

                    var line_index = 1;
                    while (line_index < lines.length && lines[line_index].trim() !== '') {
                        var parsedLine = {};
                        var values = lines[line_index].split('\t');

                        var columnIndex = 0;

                        while (columnIndex < headings.length) {
                            parsedLine[headings[columnIndex]] = values[columnIndex];
                            columnIndex += 1;
                        }

                        parsedRows.push(parsedLine);
                        line_index += 1
                    }

                    return parsedRows
                };

                scope.processTsvData = function(tsvData) {
                    scope.data = [];
                    scope.binnedData = {};
                    scope.minDate = new Date('2018-01-01');
                    scope.maxDate = new Date('0000-01-01');

                    for(var i = 0; i < tsvData.length; i++){
                        var currentLetter = tsvData[i];

                        var fromDate = new Date(currentLetter['origin_date_from']);
                        var toDate = new Date(currentLetter['origin_date_to']);

                        if(fromDate.toString() === 'Invalid Date' || toDate.toString() === 'Invalid Date'){
                            continue;
                        }

                        if(fromDate.toISOString() === toDate.toISOString()) {
                            var binKey = fromDate.toISOString().substr(0,4);

                            if(new Date(binKey) < scope.minDate) scope.minDate = new Date(binKey);
                            if(new Date(binKey) > scope.maxDate) scope.maxDate = new Date(binKey);

                            if(binKey in scope.binnedData) {
                                scope.binnedData[binKey] += 1
                            } else {
                                scope.binnedData[binKey] = 1
                            }
                        } else {
                            var fromBinKey = fromDate.toISOString().substr(0,4);
                            var toBinKey = toDate.toISOString().substr(0,4);

                            if(new Date(fromBinKey) < scope.minDate) scope.minDate = new Date(fromBinKey);
                            if(new Date(toBinKey) > scope.maxDate) scope.maxDate = new Date(toBinKey);

                            if(fromBinKey in scope.binnedData) {
                                scope.binnedData[fromBinKey] += 1
                            } else {
                                scope.binnedData[fromBinKey] = 1
                            }

                            if(toBinKey in scope.binnedData) {
                                scope.binnedData[toBinKey] += 1
                            } else {
                                scope.binnedData[toBinKey] = 1
                            }
                        }
                    }

                    for(var binKey in scope.binnedData){
                        scope.data.push({
                            'date': new Date(binKey),
                            'count': scope.binnedData[binKey]
                        });
                    }

                    scope.data.sort(function(a, b) {
                        return a.date - b.date;
                    });

                    var getYearsInbetween = function (startYear, endYear) {
                        var result = [];
                        var currentYear = startYear + 1;

                        while(currentYear < endYear){
                            result.push(
                                {
                                    'date': new Date(currentYear, 1, 1),
                                    'count': 0
                                });
                            currentYear += 1;
                        }

                        return result;
                    };

                    for(var i = 0; i < scope.data.length - 1; i++) {

                        if(scope.data[i]['date'].getFullYear() + 1 !== scope.data[i + 1]['date'].getFullYear()){
                            var inbetween = getYearsInbetween(
                                scope.data[i]['date'].getFullYear(),
                                scope.data[i + 1]['date'].getFullYear()
                            );

                            for(var j = 0; j < inbetween.length; j++){
                                scope.data.splice(i + 1 + j, 0, inbetween[j])
                            }
                        }
                    }
                };

                scope.initializeD3 = function(){
                    var margin = {top: 20, right: 50, bottom: 30, left: 50},
                        width = element[0].scrollWidth - margin.left - margin.right,
                        height = 200 - margin.top - margin.bottom;

                    var bisectDate = d3.bisector(function(d) { return d.date; }).left;

                    var x = d3.scaleTime()
                        .range([0, width]);

                    var y = d3.scaleLinear()
                        .range([height, 0]);

                    var xAxis = d3.axisBottom()
                        .scale(x);

                    var yAxis = d3.axisLeft()
                        .scale(y);

                    var line = d3.line()
                        .x(function(d) { return x(d.date); })
                        .y(function(d) { return y(d.count); });

                    scope.svg = d3.select("svg")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                        .append("g")
                        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

                    x.domain([scope.data[0].date, scope.data[scope.data.length - 1].date]);
                    y.domain(d3.extent(scope.data, function(d) { return d.count; }));

                    scope.svg.append("g")
                        .attr("class", "x axis")
                        .attr("transform", "translate(0," + height + ")")
                        .call(xAxis);

                    scope.svg.append("g")
                        .attr("class", "y axis")
                        .call(yAxis)
                        .append("text")
                        .attr("transform", "rotate(-90)")
                        .attr("y", 6)
                        .attr("dy", ".71em")
                        .style("text-anchor", "end")
                        .text("Price ($)");

                    scope.svg.append("path")
                        .datum(scope.data)
                        .attr("class", "line")
                        .attr("d", line);

                    var selection = scope.svg.append('rect')
                        .attr('x', 10)
                        .attr('y', 0)
                        .attr('width', 50)
                        .attr('height', height)
                        .attr('opacity', .0)
                        .style("fill", '#729AB4');

                    var focus = scope.svg.append("g")
                        .attr("class", "focus")
                        .style("display", "none");

                    focus.append("circle")
                        .attr("r", 4.5);

                    focus.append("text")
                        .attr("x", 9)
                        .attr("dy", ".35em");

                    scope.svg.append("rect")
                        .attr("class", "overlay")
                        .attr("width", width)
                        .attr("height", height)
                        .on("mouseover", function() { focus.style("display", null); })
                        .on("mouseout", function() { focus.style("display", "none"); })
                        .on("mousemove", mousemove);

                    function mousemove() {
                        var x0 = x.invert(d3.mouse(this)[0]),
                            i = bisectDate(scope.data, x0, 1),
                            d0 = scope.data[i - 1],
                            d1 = scope.data[i],
                            d = x0 - d0.date > d1.date - x0 ? d1 : d0;
                        focus.attr("transform", "translate(" + x(d.date) + "," + y(d.count) + ")");
                        focus.select("text").text(d.date.getFullYear() + '(' + d.count +')');
                    }

                    function dragStart() {
                        var mousePosition = d3.mouse(this);
                        var xPos = mousePosition[0];

                        if(xPos < 0) xPos = 0;
                        if(xPos > width) xPos = width;

                        scope.startPosition = xPos;

                        scope.selectionStartDate = null;
                        scope.selectionEndDate = null;

                        selection.attr('width', 0);
                        selection.attr("opacity", .5);
                        selection.attr('x', xPos);

                        scope.selectionStartDate = getDateForPosition(xPos);
                    }

                    function dragMove() {
                        var mousePosition = d3.mouse(this);
                        var xPos = mousePosition[0];

                        if(xPos < 0) xPos = 0;
                        if(xPos > width) xPos = width;

                        if(scope.startPosition < xPos) {
                            selection.attr('width', xPos - scope.startPosition)
                        } else {
                            selection.attr('x', xPos);
                            selection.attr('width', scope.startPosition - xPos)
                        }

                        scope.selectionEndDate = getDateForPosition(xPos);
                        scope.updateState()
                    }

                    function dragEnd() {
                    }

                    function getDateForPosition(xPos) {
                        var i = bisectDate(scope.data, x.invert(xPos), 1);
                        var d0 = scope.data[i - 1],
                            d1 = scope.data[i],
                            date = xPos - d0.date > d1.date - xPos ? d1 : d0;

                        return date;
                    }

                    var dragBehavior = d3.drag()
                        .on("drag", dragMove)
                        .on("start", dragStart)
                        .on("end", dragEnd);

                    scope.svg.call(dragBehavior);
                };

                scope.updateState = function () {

                    if(scope.selectionStartDate != null && scope.selectionEndDate != null){
                        scope.from = null;
                        scope.to = null;

                        if(scope.selectionStartDate['date'] < scope.selectionEndDate['date']){
                            scope.from = scope.selectionStartDate['date'];
                            scope.to = scope.selectionEndDate['date'];

                        } else if(scope.selectionStartDate['date'] > scope.selectionEndDate['date']){
                            scope.from = scope.selectionEndDate['date'];
                            scope.to = scope.selectionStartDate['date'];
                        } else {
                            scope.from = scope.to = scope.selectionEndDate['date'];
                        }

                        scope.display.innerHTML =
                            scope.from.toISOString()
                            + ' to '
                            + scope.to.toISOString();
                    }
                }
            }
        }
    }]);<|endoftext|>


<commit_before>
/*
#     CloudBoost - Core Engine that powers Bakend as a Service
#     (c) 2014 HackerBay, Inc.
#     CloudBoost may be freely distributed under the Apache 2 License
*/

var q = require('q');

module.exports = function () {
    return {
        _makeHashKey: function (appId, cacheName) {
            try{
                return appId + ":" + cacheName;
            }catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                return null;
            }
        },

        _makeCacheDocument : function(cacheName, size) {
            try{
                return { _type : 'cache', name: cacheName, size : size };
            }catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                return null;
            }
        },

        _getCaches: function (cacheName) {
            var deferred = q.defer();

            try{
                global.redisClient.hvals(cacheName, function (err, cacheItems) {
                    if (err) {
                        deferred.reject(err);
                    } else {
                        var cacheDocument = { _type : 'cache', name: null, size : null, items: null };
                        cacheDocument.name = String(cacheName).slice(cacheName.indexOf(":") + 1, cacheName.length);
                        cacheDocument.size = String(parseFloat(Buffer.byteLength(cacheItems, 'utf8') / 1025).toFixed(4)) + "kb";
                        cacheDocument.items = cacheItems;

                    }
                    deferred.resolve(cacheDocument);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },

        create: function (appId, cacheName) {

            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hset(appId, hashKey, hashKey, function (err) {
                    if (err)
                        deferred.reject(err);
                    deferred.resolve(global.cacheService._makeCacheDocument(cacheName, "0kb"));
                });
            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },

        put: function (appId, cacheName, key, item) {
            var deferred = q.defer();
            try{
                var namespace = key;
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hset(hashKey, namespace, JSON.stringify(item), function (err) {
                    if (err)
                        deferred.reject(err);
                    global.redisClient.hset(appId, hashKey, hashKey);
                    deferred.resolve(item);
                });
            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },
        getItem: function (appId, cacheName, key) {
            var deferred = q.defer();

            try{
                var namespace = key;
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hget(hashKey, namespace, function (err, result) {
                    if (err)
                        deferred.reject(err);
                    deferred.resolve(JSON.parse(result));
                });
            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },
        getAllItems: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hgetall(hashKey, function (err, items) {
                    if (err) deferred.reject(err);
                    var values = [];
                    for (var prop in items) {
                        values.push({key :prop, value : JSON.parse(items[prop])});
                    }
                    deferred.resolve(values);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },
        getItemsCount: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hlen(hashKey, function (err, count) {
                    if (err) deferred.reject(err);
                    deferred.resolve(count);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },
        getInfo: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);

                global.redisClient.hget(appId, hashKey, function (err, value) {
                    if (err) deferred.reject(err);
                    if (!value) {
                        deferred.resolve(null);
                    } else {
                        global.redisClient.hvals(hashKey, function (err, caches) {
                            if (err) deferred.reject(err);
                            var cacheSize = String(parseFloat(Buffer.byteLength(caches, 'utf8') / 1025).toFixed(4)) + "kb";
                            deferred.resolve(global.cacheService._makeCacheDocument(cacheName, cacheSize));
                        });
                    }

                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },
        getCache: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hvals(hashKey, function (err, caches) {
                    if (err) deferred.reject(err);
                    var cacheDocument = { _type : 'cache', name: null, size : null, items: [] };
                    cacheDocument.name = String(cacheName).slice(cacheName.indexOf(":") + 1, cacheName.length);
                    cacheDocument.size = String(parseFloat(Buffer.byteLength(caches, 'utf8') / 1025).toFixed(4)) + "kb";
                    cacheDocument.items.push(JSON.parse(caches));
                    deferred.resolve(cacheDocument);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },
        getAllAppCache: function (appId) {
            var deferred = global.q.defer();

            try{
                global.redisClient.hvals(appId, function (err, caches) {
                    if (err)
                        deferred.reject(err);
                    // var i = 0;
                    var promises = [];
                    for (var i = 0; i < caches.length; i++) {
                        promises.push(global.cacheService._getCaches(caches[i]));
                    }
                    q.all(promises).then(function (cacheItems) {
                        deferred.resolve(cacheItems);
                    }, function (err) {
                        deferred.reject(err)
                    });

                });
            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },

        deleteCache: function (appId, cacheName) {
            var deferred = q.defer();
            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hget(appId, hashKey, function (err, value) {
                    if (err)
                        deferred.reject(err);
                    if (!value) {
                        deferred.reject("Cache does not exist");
                    } else {
                        global.redisClient.del(hashKey, function (err, caches) {
                            if (err)
                                deferred.reject(err);

                            global.redisClient.hdel(appId, hashKey, function (err, caches) {
                                if (err)
                                    deferred.reject(err);
                                deferred.resolve(global.cacheService._makeCacheDocument(cacheName, "0kb"));
                            });

                        });
                    }
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },

        deleteItem: function (appId, cacheName, key) {
            var deferred = q.defer();

            try{

                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hdel(hashKey, key, function (err, item) {
                    if (err)
                        deferred.reject(err);
                    deferred.resolve(key);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },

        clearCache: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hget(appId, hashKey, function (err, value) {
                    if (err)
                        deferred.reject(err);
                    if (!value) {
                        deferred.reject("Cache does not exist");
                    } else {
                        global.redisClient.del(hashKey, function (err, caches) {
                            if (err)
                                deferred.reject(err);
                            deferred.resolve(global.cacheService._makeCacheDocument(cacheName, "0kb"));
                        });
                    }
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },

        deleteAllAppCache: function (appId) {
            var deferred = q.defer();

            try{
                global.redisClient.hvals(appId, function (err, caches) {
                    if (err)
                        deferred.reject(err);
                    var promises = [];
                    for (var i = 0; i < caches.length; i++) {
                        promises.push(global.cacheService.deleteCache(appId, caches[i].split(':')[1]));
                    }

                    global.q.all(promises).then(function (values) {
                        deferred.resolve(values);
                    }, function (error) {
                        deferred.reject(error);
                    });

                    deferred.resolve(caches);

                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        }

    };

};

<commit_msg>Cache Size Big fixed<commit_after>
/*
#     CloudBoost - Core Engine that powers Bakend as a Service
#     (c) 2014 HackerBay, Inc.
#     CloudBoost may be freely distributed under the Apache 2 License
*/

var q = require('q');

module.exports = function () {
    return {
        _makeHashKey: function (appId, cacheName) {
            try{
                return appId + ":" + cacheName;
            }catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                return null;
            }
        },

        _makeCacheDocument : function(cacheName, size) {
            try{
                return { _type : 'cache', name: cacheName, size : size };
            }catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                return null;
            }
        },

        _getCaches: function (cacheName) {
            var deferred = q.defer();

            try{
                global.redisClient.hvals(cacheName, function (err, cacheItems) {
                    if (err) {
                        deferred.reject(err);
                    } else {
                        var cacheDocument = { _type : 'cache', name: null, size : null, items: null };
                        cacheDocument.name = String(cacheName).slice(cacheName.indexOf(":") + 1, cacheName.length);
                        cacheDocument.size = String(parseFloat(Buffer.byteLength(JSON.stringify(cacheItems), 'utf8') / 1025).toFixed(4)) + "kb";
                        cacheDocument.items = cacheItems;

                    }
                    deferred.resolve(cacheDocument);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },

        create: function (appId, cacheName) {

            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hset(appId, hashKey, hashKey, function (err) {
                    if (err)
                        deferred.reject(err);
                    deferred.resolve(global.cacheService._makeCacheDocument(cacheName, "0kb"));
                });
            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },

        put: function (appId, cacheName, key, item) {
            var deferred = q.defer();
            try{
                var namespace = key;
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hset(hashKey, namespace, JSON.stringify(item), function (err) {
                    if (err)
                        deferred.reject(err);
                    global.redisClient.hset(appId, hashKey, hashKey);
                    deferred.resolve(item);
                });
            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },
        getItem: function (appId, cacheName, key) {
            var deferred = q.defer();

            try{
                var namespace = key;
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hget(hashKey, namespace, function (err, result) {
                    if (err)
                        deferred.reject(err);
                    deferred.resolve(JSON.parse(result));
                });
            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },
        getAllItems: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hgetall(hashKey, function (err, items) {
                    if (err) deferred.reject(err);
                    var values = [];
                    for (var prop in items) {
                        values.push({key :prop, value : JSON.parse(items[prop])});
                    }
                    deferred.resolve(values);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },
        getItemsCount: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hlen(hashKey, function (err, count) {
                    if (err) deferred.reject(err);
                    deferred.resolve(count);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },
        getInfo: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);

                global.redisClient.hget(appId, hashKey, function (err, value) {
                    if (err) deferred.reject(err);
                    if (!value) {
                        deferred.resolve(null);
                    } else {
                        global.redisClient.hvals(hashKey, function (err, caches) {
                            if (err) deferred.reject(err);
                            var length = Buffer.byteLength(JSON.stringify(caches), 'utf8') / 1025;
                            var cacheSize = String(parseFloat(length).toFixed(4)) + "KB";
                            deferred.resolve(global.cacheService._makeCacheDocument(cacheName, cacheSize));
                        });
                    }

                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },
        getCache: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hvals(hashKey, function (err, caches) {
                    if (err) deferred.reject(err);
                    var cacheDocument = { _type : 'cache', name: null, size : null, items: [] };
                    cacheDocument.name = String(cacheName).slice(cacheName.indexOf(":") + 1, cacheName.length);
                    cacheDocument.size = String(parseFloat(Buffer.byteLength(caches, 'utf8') / 1025).toFixed(4)) + "kb";
                    cacheDocument.items.push(JSON.parse(caches));
                    deferred.resolve(cacheDocument);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },
        getAllAppCache: function (appId) {
            var deferred = global.q.defer();

            try{
                global.redisClient.hvals(appId, function (err, caches) {
                    if (err)
                        deferred.reject(err);
                    // var i = 0;
                    var promises = [];
                    for (var i = 0; i < caches.length; i++) {
                        promises.push(global.cacheService._getCaches(caches[i]));
                    }
                    q.all(promises).then(function (cacheItems) {
                        deferred.resolve(cacheItems);
                    }, function (err) {
                        deferred.reject(err)
                    });

                });
            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },

        deleteCache: function (appId, cacheName) {
            var deferred = q.defer();
            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hget(appId, hashKey, function (err, value) {
                    if (err)
                        deferred.reject(err);
                    if (!value) {
                        deferred.reject("Cache does not exist");
                    } else {
                        global.redisClient.del(hashKey, function (err, caches) {
                            if (err)
                                deferred.reject(err);

                            global.redisClient.hdel(appId, hashKey, function (err, caches) {
                                if (err)
                                    deferred.reject(err);
                                deferred.resolve(global.cacheService._makeCacheDocument(cacheName, "0kb"));
                            });

                        });
                    }
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },

        deleteItem: function (appId, cacheName, key) {
            var deferred = q.defer();

            try{

                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hdel(hashKey, key, function (err, item) {
                    if (err)
                        deferred.reject(err);
                    deferred.resolve(key);
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        },

        clearCache: function (appId, cacheName) {
            var deferred = q.defer();

            try{
                var hashKey = global.cacheService._makeHashKey(appId, cacheName);
                global.redisClient.hget(appId, hashKey, function (err, value) {
                    if (err)
                        deferred.reject(err);
                    if (!value) {
                        deferred.reject("Cache does not exist");
                    } else {
                        global.redisClient.del(hashKey, function (err, caches) {
                            if (err)
                                deferred.reject(err);
                            deferred.resolve(global.cacheService._makeCacheDocument(cacheName, "0kb"));
                        });
                    }
                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }

            return deferred.promise;
        },

        deleteAllAppCache: function (appId) {
            var deferred = q.defer();

            try{
                global.redisClient.hvals(appId, function (err, caches) {
                    if (err)
                        deferred.reject(err);
                    var promises = [];
                    for (var i = 0; i < caches.length; i++) {
                        promises.push(global.cacheService.deleteCache(appId, caches[i].split(':')[1]));
                    }

                    global.q.all(promises).then(function (values) {
                        deferred.resolve(values);
                    }, function (error) {
                        deferred.reject(error);
                    });

                    deferred.resolve(caches);

                });

            } catch(err){
                global.winston.log('error',{"error":String(err),"stack": new Error().stack});
                deferred.reject(err);
            }
            return deferred.promise;
        }

    };

};
<|endoftext|>


<commit_before>"use strict";
const config = require('config');
const socketio = require('socket.io');
const cookieParser = require('cookie-parser');
const gp = require('./gpxplayer');
const db = require('../database/db');
const usr = require('../models/user');
const dev = require('../models/device');
const pos = require('../models/position');
const JSONValidator = require('../utils/validator');
const logger = require('../utils/logger');

const LivemapValidator = new JSONValidator('livemap');
var socketClients = [];

function getUserIdFromSession(sid) {
    return new Promise ((resolve, reject) => {
        db.getStore().get(sid, (error, session) => {
            if (session && session.passport && typeof session.passport.user !== 'undefined') {
                resolve(session.passport.user);
            } else {
                reject();
            }
        });
    });
}

//
// Exported modules
//

function start(server) {
    let io = socketio.listen(server);

    // On every incoming socket get the ID of the current session. Used to access user information for authentication.
    io.use((socket, next) => {
        // Create the fake request that cookieParser will expect
        let req = {
            "headers": {
                "cookie": socket.request.headers.cookie
            }
        };
        // Run the parser and store the sessionID
        cookieParser(config.get('sessions.secret'))(req, null, () => {});
        let name = config.get('sessions.name');
        socket.sessionID = req.signedCookies[name] || req.cookies[name];
        next();
    });

    // On a new socket connection add the user information to the socket
    io.sockets.on('connection', async (socket) => {
        try {
            const userId = await getUserIdFromSession(socket.sessionID);
            const queryRes = await usr.getUserByField('user_id', userId);
            if (queryRes.rowCount === 0) {
                throw new Error();
            }
            socket.user = queryRes.rows[0];
            socketClients.push(socket);
            logger.info(`Client connected (${socketClients.length}): ${socket.user.fullname}`);
            gp.startAll();
        } catch(error) {
            // Ignore socket connections with unknown/invalid session ID
        }

        socket.on('disconnect', () => {
            socketClients.splice(socketClients.indexOf(socket), 1);
        });
    });
}

async function sendToClient(destData) {
    // On a valid location reception:
    // 1. Send a location update to every client that is authorized for this device
    // 2. Store the location in the database
    if (LivemapValidator.validate(destData)) {
        for (let i = 0; i < socketClients.length; i += 1) {
            let client = socketClients[i];
            if (typeof client.user.username !== 'undefined' && client.user.username !== null) {
                let queryRes = await dev.getAllowedDevices(client.user.user_id);
                client.devices = [];
                for (let j = 0; j < queryRes.rows.length; j += 1) {
                    client.devices.push(queryRes.rows[j].device_id);
                    if (queryRes.rows[j].device_id === destData.device_id) {
                        client.emit('positionUpdate', JSON.stringify({type: 'gps', data: destData}));
                    }
                }
            }
        }
        await pos.insertPosition([destData.device_id, destData.device_id_tag, destData.loc_timestamp, destData.loc_lat, destData.loc_lon, destData.loc_type, destData.loc_attr]);
    } else {
        logger.info(`Invalid: ${LivemapValidator.errorsText()}`);
    }
}

module.exports.start = start;
module.exports.sendToClient = sendToClient;
<commit_msg>Remove socket cookie to prevent SameSite warning<commit_after>"use strict";
const config = require('config');
const socketio = require('socket.io');
const cookieParser = require('cookie-parser');
const gp = require('./gpxplayer');
const db = require('../database/db');
const usr = require('../models/user');
const dev = require('../models/device');
const pos = require('../models/position');
const JSONValidator = require('../utils/validator');
const logger = require('../utils/logger');

const LivemapValidator = new JSONValidator('livemap');
var socketClients = [];

function getUserIdFromSession(sid) {
    return new Promise ((resolve, reject) => {
        db.getStore().get(sid, (error, session) => {
            if (session && session.passport && typeof session.passport.user !== 'undefined') {
                resolve(session.passport.user);
            } else {
                reject();
            }
        });
    });
}

//
// Exported modules
//

function start(server) {
    let io = socketio.listen(server, {cookie: false});

    // On every incoming socket get the ID of the current session. Used to access user information for authentication.
    io.use((socket, next) => {
        // Create the fake request that cookieParser will expect
        let req = {
            "headers": {
                "cookie": socket.request.headers.cookie
            }
        };
        // Run the parser and store the sessionID
        cookieParser(config.get('sessions.secret'))(req, null, () => {});
        let name = config.get('sessions.name');
        socket.sessionID = req.signedCookies[name] || req.cookies[name];
        next();
    });

    // On a new socket connection add the user information to the socket
    io.sockets.on('connection', async (socket) => {
        try {
            const userId = await getUserIdFromSession(socket.sessionID);
            const queryRes = await usr.getUserByField('user_id', userId);
            if (queryRes.rowCount === 0) {
                throw new Error();
            }
            socket.user = queryRes.rows[0];
            socketClients.push(socket);
            logger.info(`Client connected (${socketClients.length}): ${socket.user.fullname}`);
            gp.startAll();
        } catch(error) {
            // Ignore socket connections with unknown/invalid session ID
        }

        socket.on('disconnect', () => {
            socketClients.splice(socketClients.indexOf(socket), 1);
        });

        socket.on('authenticate', (data) => {
            logger.info(`Data: ${data}`);
        });
    });
}

async function sendToClient(destData) {
    // On a valid location reception:
    // 1. Send a location update to every client that is authorized for this device
    // 2. Store the location in the database
    if (LivemapValidator.validate(destData)) {
        for (let i = 0; i < socketClients.length; i += 1) {
            let client = socketClients[i];
            if (typeof client.user.username !== 'undefined' && client.user.username !== null) {
                let queryRes = await dev.getAllowedDevices(client.user.user_id);
                client.devices = [];
                for (let j = 0; j < queryRes.rows.length; j += 1) {
                    client.devices.push(queryRes.rows[j].device_id);
                    if (queryRes.rows[j].device_id === destData.device_id) {
                        client.emit('positionUpdate', JSON.stringify({type: 'gps', data: destData}));
                    }
                }
            }
        }
        await pos.insertPosition([destData.device_id, destData.device_id_tag, destData.loc_timestamp, destData.loc_lat, destData.loc_lon, destData.loc_type, destData.loc_attr]);
    } else {
        logger.info(`Invalid: ${LivemapValidator.errorsText()}`);
    }
}

module.exports.start = start;
module.exports.sendToClient = sendToClient;
<|endoftext|>


<commit_before>/**
 * Created by momchillgorchev on 28/10/15.
 */

Meteor.startup(function(){

    return Meteor.methods({

        /**
         * Not used
         * @param to
         * @param from
         * @param subject
         * @param text
         */
        sendEmail: function (to, from, subject, text) {

            check([to, from, subject, text], [String]);

            // Let other method calls from the same client start running,
            // without waiting for the email sending to complete.
            this.unblock();

            Email.send({
                to: to,
                from: from,
                subject: subject,
                text: text
            });
        },

        /**
         * Add endpoint to the DB
         * @param service - object containing the new service data
         * @returns {*} - _id of the newly created entry
         */

        // TODO - Implement check if that service already exist and dont add it if yes
        // TODO - also implement immediate service check once its added
        // TODO - also investigate why is all that empty space in the service name
        addEndpoint: function(service){
            if(service){
                // Validate the service URL
                if(service.url.match(core.VALID_URL) !== null){

                    // Check for existing entry with that URL
                    var existingRecord = Endpoints.findOne({url: service.url});
                    if(existingRecord === undefined){

                        // Reset status
                        service.status = null;
                        // Find the next available id
                        var existingEntries = Endpoints.find().count();
                        service.order = existingEntries + 1;
                        // And insert to DB
                        // log('Before insert', service);
                        return Endpoints.insert(service);
                    } else {
                        throw new Meteor.Error(409, 'Service URL already exist');
                    }

                } else {
                    // Throw an error for not valid URL
                    throw new Meteor.Error(500, 'Not a valid URL: ['+ service.url +']');
                }
            }
            // Empty input
            return false;
        },

        /**
         * Removes DB entry by _id
         * @param id
         * @returns {*|any}
         */
        deleteEndpoint: function(id){

            // If valid input return the result of the DB operation
            // Else false
            return id ? Endpoints.remove({_id: id}) : false;
        },

        /**
         * Update DB entry with data passed from the client
         * @param data
         * @returns {boolean}
         */
        updateEndpointInfo: function(data){
            // This will be an existing service every time
            // But its a good measure as this method call
            // is coming from the client
            var service = Endpoints.find({_id: data.id}, {}).fetch();
            if(service.length){
                // Select by _id and update
                Endpoints.update(
                    {
                        _id: data.id
                    },
                    {
                        $set: {
                            name: data.name,
                            url: data.url,
                            info: data.info,
                            status: data.status
                        }
                    }
                );
                return true;
            }
            return false;
        },

        /**
         * Updates endpoint status
         * @param service - endpoint to update
         */
        updateEndpointStatus: function(service){

            if(service){
                try{
                    // Select by URL and update
                    return Endpoints.update(
                        {
                            url: service.url
                        },
                        {
                            $set: {
                                lastStatusCode: service.lastStatusCode,
                                status: service.status
                            }
                        }
                    );

                } catch(e){
                    throw new Meteor.Error(500, 'Internal Server Error');
                }
            }
        },

        /**
         * Ping single service to check the status
         * Built to be reusable from the client and internal server processes
         * @param service - Object containing the service details
         * @returns {any} - Returns the result of updateEndpointStatus method
         */
        checkSingleService: function(service){

            // Validate the input
            // This is necessary as this method is used by the client as well
            check(service, Object);

            // Request the db entry and compare urls
            // This is necessary as this method is used by the client as well
            var dbEntry = Endpoints.findOne({_id: service._id}),
                result, actualStatus;

            // If everything match
            if(service.url === dbEntry.url){

                // Init check call
                try{
                    // Plain GET request, needs to be updated when
                    // specifying a method is implemented
                    result = HTTP.get(service.url, {});

                    // Keep the orange status
                    // Or look for 'updated manually' flag (not implemented)
                    if(dbEntry.status === 'orange' || result.statusCode !== 200){
                        actualStatus = 'orange';
                    } else if(result.statusCode === '503'){
                        actualStatus = 'red';
                    } else {
                        actualStatus = 'green';
                    }

                    // [DEBUG]
                    //log('Status color code after ping: '+ dbEntry.status);

                    // Update with new response data
                    dbEntry.lastStatusCode = result.statusCode;
                    dbEntry.status = actualStatus;

                // Catch any exceptions
                } catch(e){

                    // [DEBUG]
                    log(e);
                    //// TODO handle all error codes
                    //result.statusCode = '501';
                    //error = true;

                    dbEntry.status = 'red';
                    dbEntry.lastStatusCode = '503';

                    // TODO Implement send email here
                    // If alert is set for this service

                }

                // [DEBUG]
                //console.log('updateEndpointStatus called with:', service);

                // Update the DB
                return Meteor.call('updateEndpointStatus', dbEntry);

            }

        },

        /**
         * Run HTTP call for each entry in the DB
         * @returns {boolean}
         */
        checkServicesStatus: function(){

            // Allow other messages to use the DDP
            this.unblock();
            // Get the DB data
            var allServices = Endpoints.find().fetch(),
                error = false;

            // Iterate over all entries
            // This needs to be updated when pagination is implemented
            // Right now it doesn't scale
            for(var i = 0, count = allServices.length; i < count; i++){
                var current = allServices[i];

                // [DEBUG]
                //log('Calling '+ current.url);

                // Call method to check single service
                Meteor.call('checkSingleService', current, function(err, res){
                    //log(err ? err : res);
                });
            }
            return !error;
        },

        dropDB: function(){
            return Endpoints.remove({});
        }
    });

});
<commit_msg>Server method for new order functionality<commit_after>/**
 * Created by momchillgorchev on 28/10/15.
 */

Meteor.startup(function(){

    return Meteor.methods({

        /**
         * Not used
         * @param to
         * @param from
         * @param subject
         * @param text
         */
        sendEmail: function (to, from, subject, text) {

            check([to, from, subject, text], [String]);

            // Let other method calls from the same client start running,
            // without waiting for the email sending to complete.
            this.unblock();

            Email.send({
                to: to,
                from: from,
                subject: subject,
                text: text
            });
        },

        /**
         * Add endpoint to the DB
         * @param service - object containing the new service data
         * @returns {*} - _id of the newly created entry
         */
        addEndpoint: function(service){
            if(service){
                // Validate the service URL
                if(service.url.match(core.VALID_URL) !== null){

                    // Check for existing entry with that URL
                    var existingRecord = Endpoints.findOne({url: service.url});
                    if(existingRecord === undefined){

                        // Reset status
                        service.status = null;
                        // Find the next available id
                        var existingEntries = Endpoints.find().count();
                        service.order = existingEntries + 1;
                        // And insert to DB
                        // log('Before insert', service);
                        return Endpoints.insert(service);
                    } else {
                        throw new Meteor.Error(409, 'Service URL already exist');
                    }

                } else {
                    // Throw an error for not valid URL
                    throw new Meteor.Error(500, 'Not a valid URL: ['+ service.url +']');
                }
            }
            // Empty input
            return false;
        },

        /**
         * Removes DB entry by _id
         * @param id
         * @returns {*|any}
         */
        deleteEndpoint: function(id){

            // If valid input return the result of the DB operation
            // Else false
            return id ? Endpoints.remove({_id: id}) : false;
        },

        /**
         * Update DB entry with data passed from the client
         * @param data
         * @returns {boolean}
         */
        updateEndpointInfo: function(data){
            // This will be an existing service every time
            // But its a good measure as this method call
            // is coming from the client
            var service = Endpoints.find({_id: data.id}, {}).fetch();
            if(service.length){
                // Select by _id and update
                Endpoints.update(
                    {
                        _id: data.id
                    },
                    {
                        $set: {
                            name: data.name,
                            url: data.url,
                            info: data.info,
                            status: data.status
                        }
                    }
                );
                return true;
            }
            return false;
        },

        /**
         * Updates endpoint status
         * @param service - endpoint to update
         */
        updateEndpointStatus: function(service){

            if(service){
                try{
                    // Select by URL and update
                    return Endpoints.update({url: service.url},
                        {
                            $set: {
                                lastStatusCode: service.lastStatusCode,
                                status: service.status
                            }
                        }
                    );

                } catch(e){
                    throw new Meteor.Error(500, 'Internal Server Error');
                }
            }
        },

        /**
         * Set new order to endpoints after client side rearrange (drag and drop)
         * @param endpoints -
         * Array of objects containing the ID to be updated
         * and the new order numerical value
         */
        updateEndpointsOrder: function(endpoints){

            // Check input
            check(endpoints, Array);

            // Iterate and update
            for(var i = 0, count = endpoints.length; i < count; i++){

                var current = endpoints[i];

                // Select by ID and update the order field
                Endpoints.update({_id: current.itemId},
                    {
                        $set: {
                            order: current.newOrder
                        }
                    }
                );
            }

            return true;
        },

        /**
         * Ping single service to check the status
         * Built to be reusable from the client and internal server processes
         * @param service - Object containing the service details
         * @returns {any} - Returns the result of updateEndpointStatus method
         */
        checkSingleService: function(service){

            // Validate the input
            // This is necessary as this method is used by the client as well
            check(service, Object);

            // Request the db entry and compare urls
            // This is necessary as this method is used by the client as well
            var dbEntry = Endpoints.findOne({_id: service._id}),
                result, actualStatus;

            // If everything match
            if(service.url === dbEntry.url){

                // Init check call
                try{
                    // Plain GET request, needs to be updated when
                    // specifying a method is implemented
                    result = HTTP.get(service.url, {});

                    // Keep the orange status
                    // Or look for 'updated manually' flag (not implemented)
                    if(dbEntry.status === 'orange' || result.statusCode !== 200){
                        actualStatus = 'orange';
                    } else if(result.statusCode === '503'){
                        actualStatus = 'red';
                    } else {
                        actualStatus = 'green';
                    }

                    // [DEBUG]
                    //log('Status color code after ping: '+ dbEntry.status);

                    // Update with new response data
                    dbEntry.lastStatusCode = result.statusCode;
                    dbEntry.status = actualStatus;

                // Catch any exceptions
                } catch(e){

                    // [DEBUG]
                    log(e);
                    //// TODO handle all error codes
                    //result.statusCode = '501';
                    //error = true;

                    dbEntry.status = 'red';
                    dbEntry.lastStatusCode = '503';

                    // TODO Implement send email here
                    // If alert is set for this service

                }

                // [DEBUG]
                //console.log('updateEndpointStatus called with:', service);

                // Update the DB
                return Meteor.call('updateEndpointStatus', dbEntry);

            }

        },

        /**
         * Run HTTP call for each entry in the DB
         * @returns {boolean}
         */
        checkServicesStatus: function(){

            // Allow other messages to use the DDP
            this.unblock();
            // Get the DB data
            var allServices = Endpoints.find().fetch(),
                error = false;

            // Iterate over all entries
            // This needs to be updated when pagination is implemented
            // Right now it doesn't scale
            for(var i = 0, count = allServices.length; i < count; i++){
                var current = allServices[i];

                // [DEBUG]
                //log('Calling '+ current.url);

                // Call method to check single service
                Meteor.call('checkSingleService', current, function(err, res){
                    //log(err ? err : res);
                });
            }
            return !error;
        },

        dropDB: function(){
            return Endpoints.remove({});
        }
    });

});
<|endoftext|>


<commit_before>// Primary Node.js server file

/**
 * Initializes the web server and starts it listening on the given port
 */
var run = function(port) {
	/*
	 * Load all dependencies
	 */
	var express = require('express');
	var app = express();

	/**
	 * Enables static serving of .css and .js files from the server/view folder. Static
	 * files are set to remain cached by the client for one full day.
	 */
	var loadStaticServing = function(app) {
		var oneDay = 86400*1000;

		// Makes sure content will be compressed when sent
		app.use(express.compress());

		// Uncomment to use cached version (eventually)
		// app.use(express.static(process.cwd() + "/view", {maxAge: oneDay}));

		// Uncached version
		app.use(express.static(process.cwd() + "/view"));
	};

	/**
	 * Initializes the functions to handle certain specific requests. Used for serving up
	 * dynamic content.
	 */
	var loadRoutes = function(app) {
		app.get('/', homepage);

		app.post('/github/pull', updateRepository);
	};

	/**
	 * Dynamically populates the contents of the homepage. Used in place of an index.html
	 * file.
	 */
	var homepage = function(req, res) {
		res.send('BYU Class wiki, served direct to you from Node.js! Testing webHook and endpoint. test_zero');
	};

	/**
	 * Runs a bash script that pulls from the github repository and reloads the server
	 */
	var updateRepository = function(req, res) {
		var spawnOne = require('child_process').spawn;
		var spawnTwo = require('child_process').spawn;

		console.log('Pulling the latest code from github');
		res.send('Please verify server has run update.sh');
		spawnOne('./update.sh');
		spawnTwo('sudo ./restart.sh');

	};

	loadStaticServing(app);
	loadRoutes(app);

	app.listen(port);

	console.log('Server listening on port ' + port);
};

exports.run = run;
<commit_msg>Update server.js<commit_after>// Primary Node.js server file

/**
 * Initializes the web server and starts it listening on the given port
 */
var run = function(port) {
	/*
	 * Load all dependencies
	 */
	var express = require('express');
	var app = express();

	/**
	 * Enables static serving of .css and .js files from the server/view folder. Static
	 * files are set to remain cached by the client for one full day.
	 */
	var loadStaticServing = function(app) {
		var oneDay = 86400*1000;

		// Makes sure content will be compressed when sent
		app.use(express.compress());

		// Uncomment to use cached version (eventually)
		// app.use(express.static(process.cwd() + "/view", {maxAge: oneDay}));

		// Uncached version
		app.use(express.static(process.cwd() + "/view"));
	};

	/**
	 * Initializes the functions to handle certain specific requests. Used for serving up
	 * dynamic content.
	 */
	var loadRoutes = function(app) {
		app.get('/', homepage);

		app.post('/github/pull', updateRepository);
	};

	/**
	 * Dynamically populates the contents of the homepage. Used in place of an index.html
	 * file.
	 */
	var homepage = function(req, res) {
		res.send('BYU Class wiki, served direct to you from Node.js! Testing webHook and endpoint. test_one');
	};

	/**
	 * Runs a bash script that pulls from the github repository and reloads the server
	 */
	var updateRepository = function(req, res) {
		var spawnOne = require('child_process').spawn;
		var spawnTwo = require('child_process').spawn;

		console.log('Pulling the latest code from github');
		res.send('Please verify server has run update.sh');
		spawnOne('./update.sh');
		spawnTwo('sudo ./restart.sh');

	};

	loadStaticServing(app);
	loadRoutes(app);

	app.listen(port);

	console.log('Server listening on port ' + port);
};

exports.run = run;
<|endoftext|>


<commit_before>/********************************************************************************
* Syntax conventions:                                                           *
* -> indices and powers: "x^2", "x_2";                                          *
* -> special symbols: "<=>", "*", "->";                                         *
* -> whitespace sequences: "   ", "  ", and "\ " denote (in order) em-space,    *
*    en-space, and thin-space;                                                  *
* -> any correct HTML, including tags and entities.                             *
* Notes:                                                                        *
* 1) "<=>" and "=" preserve appropriate spacing on both sides;                  *
* 2) "{}"-groupings in indices and powers are also available;                   *
* 3) "\" is the escape character, except when it occurs before the space        *
*    character in "\ ".                                                         *
********************************************************************************/

var submit = function() {
    var code = document.getElementById('editor').value;
    var html = document.getElementById('preview').innerHTML = convert(code);
    document.getElementById('source').value = html ? '
' + html + '
' : '';
};

var replace = function(code, dict) {
    var keys = Object.keys(dict);
    for (var k = 0; k < keys.length; ++k) {
        code = code.replace(keys[k], dict[keys[k]]);
    }
    return code;
};

var convert = function(code) {
    code = replace(code, {
        '<=>': ' ⇔ ',
        '   ': ' ',
        '*': '·',
        '->': '→',
        '  ': ' '
    });
    var output = '';
    var escapeChar = '\\', escaped = false;
    var curlyState = null, curlies = {'_': 'sub', '^': 'sup'};
    // DFA begin
    for (var k = 0; k < code.length; ++k) {
        var c = code[k];
        // Toss escaped character away
        if (escaped) {
            output += c == ' ' ? ' ' : c;
            escaped = false;
            continue;
        }
        // Render brace-enclosed code
        if (curlyState) {
            output += '<' + curlyState + '>';
            var rightBrace;
            if (c == '{' && ((rightBrace = code.indexOf('}', k)) != -1)) {
                output += code.slice(k + 1, rightBrace);
                k = rightBrace;
            }
            else {
                output += c;
            }
            output += '</' + curlyState + '>';
            curlyState = null;
            continue;
        }
        // Check for brace-enclosure flag
        if ((function() {
            var found = curlies.hasOwnProperty(c);
            if (found) {
                curlyState = curlies[c];
            }
            return found;
        })()) {
            continue;
        }
        // Handle the rest of characters
        switch (c) {
        case escapeChar:
            escaped = true;
            break;
        case '=':
            output += ' ' + c + ' ';
            break;
        default:
            output += c;
        }
    }
    return output;
};
<commit_msg>Descriptions synchronized<commit_after>/********************************************************************************
* Syntax conventions:                                                           *
* -> indices and powers: "x^2", "x_2";                                          *
* -> special symbols: "<=>", "*", "->";                                         *
* -> whitespace sequences: "   ", "  ", "\ " denote (in order) em-space,        *
*    en-space, and thin-space;                                                  *
* -> any correct HTML, including tags and entities.                             *
* Notes:                                                                        *
* 1) "<=>" and "=" preserve appropriate spacing on both sides;                  *
* 2) "{}"-groupings in indices and powers are also available;                   *
* 3) "\" is the escape character, except when it occurs before the space        *
*    character in "\ ".                                                         *
********************************************************************************/

var submit = function() {
    var code = document.getElementById('editor').value;
    var html = document.getElementById('preview').innerHTML = convert(code);
    document.getElementById('source').value = html ? '
' + html + '
' : '';
};

var replace = function(code, dict) {
    var keys = Object.keys(dict);
    for (var k = 0; k < keys.length; ++k) {
        code = code.replace(keys[k], dict[keys[k]]);
    }
    return code;
};

var convert = function(code) {
    code = replace(code, {
        '<=>': ' ⇔ ',
        '   ': ' ',
        '*': '·',
        '->': '→',
        '  ': ' '
    });
    var output = '';
    var escapeChar = '\\', escaped = false;
    var curlyState = null, curlies = {'_': 'sub', '^': 'sup'};
    // DFA begin
    for (var k = 0; k < code.length; ++k) {
        var c = code[k];
        // Toss escaped character away
        if (escaped) {
            output += c == ' ' ? ' ' : c;
            escaped = false;
            continue;
        }
        // Render brace-enclosed code
        if (curlyState) {
            output += '<' + curlyState + '>';
            var rightBrace;
            if (c == '{' && ((rightBrace = code.indexOf('}', k)) != -1)) {
                output += code.slice(k + 1, rightBrace);
                k = rightBrace;
            }
            else {
                output += c;
            }
            output += '</' + curlyState + '>';
            curlyState = null;
            continue;
        }
        // Check for brace-enclosure flag
        if ((function() {
            var found = curlies.hasOwnProperty(c);
            if (found) {
                curlyState = curlies[c];
            }
            return found;
        })()) {
            continue;
        }
        // Handle the rest of characters
        switch (c) {
        case escapeChar:
            escaped = true;
            break;
        case '=':
            output += ' ' + c + ' ';
            break;
        default:
            output += c;
        }
    }
    return output;
};
<|endoftext|>


<commit_before>var express = require('express');

var app = express.Router();
var auth = require('./auth');
var helpers = require('../lib/helpers');

var ntb = require('turbasen');

var js = require('JSONStream');
var es = require('event-stream');

ntb.configure({USER_AGENT: 'Hytteadmin/' + require('../package.json').version});

app.use(function(req, res, next) {
  // @TODO validate user authentication
  next();
});

app.get('/cabin', function(req, res) {
  req.query.tilbyder = 'DNT';
  req.query['tags.0'] = 'Hytte';
  req.query.sort = 'navn';
  // @TODO set or validate req.query.grupper

  var cabins = ntb.steder(req.query);

  cabins.pipe(res);
  cabins.pipe(js.parse('documents.*')).pipe(es.mapSync(function(data) {
    //console.log(data);
  }));
});

app.post('/cabin', function(req, res) {
  // @TODO set private fields
  ntb.steder.post(req.body).pipe(res);
});

app.get('/cabin/:id', function(req, res) {
  // @TODO validate user authorization
  var cabin = ntb.steder.get(req.params.id);

  cabin.pipe(res);
  cabin.pipe(js.parse()).pipe(es.mapSync(function(data) {
    //console.log(data);
  }));
});

app.post('/cabin/:id', function(req, res) {
  // @TODO validate user authorization

  req.body.privat = req.body.privat || {};

  // UT is expecting a cababin type integer property in the private scope in
  // order to display the correct map icon for the cabin.
  req.body.privat.hyttetype = helpers.hyttetype(
    req.body.privat.hyttetype,
    req.body.betjeningsgrad
  );

  // In Turadmin we have separated cabin access between private and public
  // transportation. UT.no has not caught up with these changes, so for the time
  // being we have to make sure the old `adkomst` filed stays populated.
  req.body.adkomst = req.body.tilkomst.privat;

  // UT.no is expecting `senger` object property to be in the private scope.
  req.body.privat.senger = req.body.senger;

  ntb.steder.patch(req.params.id, req.body).pipe(res);
});

app.post('/photo', function(req, res) {
  ntb.bilder.post(req.body).pipe(res);
});

app.get('/photo/:id', function(req, res) {
  // @TODO validate user authorization
  ntb.bilder.get(req.params.id).pipe(res);
});

app.post('/photo/:id', function(req, res) {
  // @TODO validate user authorization
  ntb.bilder.patch(req.params.id, req.body).pipe(res);
});

app.get('/group', function(req, res) {
  req.query.sort = 'navn';

  var groups = ntb.grupper(req.query);

  groups.pipe(res);
  groups.pipe(js.parse('documents.*')).pipe(es.mapSync(function(data) {
    //console.log(data);
  }));
});

app.get('/group/:id', function(req, res) {
  // @TODO validate user authorization
  ntb.grupper.get(req.params.id).pipe(res);
});

app.get('/area', function(req, res) {
  var areas = ntb.områder(req.query);

  areas.pipe(res);
  areas.pipe(js.parse('documents.*')).pipe(es.mapSync(function(data) {
    //console.log(data);
  }));
});

app.get('/area/:id', function(req, res) {
  // @TODO validate user authorization
  ntb.områder.get(req.params.id).pipe(res);
});

module.exports = app;
<commit_msg>Update comment for `senger` object property<commit_after>var express = require('express');

var app = express.Router();
var auth = require('./auth');
var helpers = require('../lib/helpers');

var ntb = require('turbasen');

var js = require('JSONStream');
var es = require('event-stream');

ntb.configure({USER_AGENT: 'Hytteadmin/' + require('../package.json').version});

app.use(function(req, res, next) {
  // @TODO validate user authentication
  next();
});

app.get('/cabin', function(req, res) {
  req.query.tilbyder = 'DNT';
  req.query['tags.0'] = 'Hytte';
  req.query.sort = 'navn';
  // @TODO set or validate req.query.grupper

  var cabins = ntb.steder(req.query);

  cabins.pipe(res);
  cabins.pipe(js.parse('documents.*')).pipe(es.mapSync(function(data) {
    //console.log(data);
  }));
});

app.post('/cabin', function(req, res) {
  // @TODO set private fields
  ntb.steder.post(req.body).pipe(res);
});

app.get('/cabin/:id', function(req, res) {
  // @TODO validate user authorization
  var cabin = ntb.steder.get(req.params.id);

  cabin.pipe(res);
  cabin.pipe(js.parse()).pipe(es.mapSync(function(data) {
    //console.log(data);
  }));
});

app.post('/cabin/:id', function(req, res) {
  // @TODO validate user authorization

  req.body.privat = req.body.privat || {};

  // UT is expecting a cababin type integer property in the private scope in
  // order to display the correct map icon for the cabin.
  req.body.privat.hyttetype = helpers.hyttetype(
    req.body.privat.hyttetype,
    req.body.betjeningsgrad
  );

  // In Turadmin we have separated cabin access between private and public
  // transportation. UT.no has not caught up with these changes, so for the time
  // being we have to make sure the old `adkomst` filed stays populated.
  req.body.adkomst = req.body.tilkomst.privat;

  // UT.no is expecting `senger` to be an object property in the private scope.
  req.body.privat.senger = req.body.senger;

  ntb.steder.patch(req.params.id, req.body).pipe(res);
});

app.post('/photo', function(req, res) {
  ntb.bilder.post(req.body).pipe(res);
});

app.get('/photo/:id', function(req, res) {
  // @TODO validate user authorization
  ntb.bilder.get(req.params.id).pipe(res);
});

app.post('/photo/:id', function(req, res) {
  // @TODO validate user authorization
  ntb.bilder.patch(req.params.id, req.body).pipe(res);
});

app.get('/group', function(req, res) {
  req.query.sort = 'navn';

  var groups = ntb.grupper(req.query);

  groups.pipe(res);
  groups.pipe(js.parse('documents.*')).pipe(es.mapSync(function(data) {
    //console.log(data);
  }));
});

app.get('/group/:id', function(req, res) {
  // @TODO validate user authorization
  ntb.grupper.get(req.params.id).pipe(res);
});

app.get('/area', function(req, res) {
  var areas = ntb.områder(req.query);

  areas.pipe(res);
  areas.pipe(js.parse('documents.*')).pipe(es.mapSync(function(data) {
    //console.log(data);
  }));
});

app.get('/area/:id', function(req, res) {
  // @TODO validate user authorization
  ntb.områder.get(req.params.id).pipe(res);
});

module.exports = app;
<|endoftext|>