From fdc8727044bdd3da1ca68e6a8a6e5f72ef212490 Mon Sep 17 00:00:00 2001 From: Dobie Wollert Date: Wed, 5 Aug 2015 06:03:02 -0700 Subject: [PATCH] Added a bunch of stuff --- app/controllers/checkLists.js | 73 ++++++ app/controllers/devices.js | 32 ++- app/controllers/testRuns.js | 73 ++++++ app/controllers/workorders.js | 4 +- app/model/checkList.js | 11 + app/model/device.js | 2 + app/model/deviceType.js | 1 + app/model/testRun.js | 14 + app/model/workorder.js | 3 +- app/views/index.jade | 4 + config/auth.js | 8 +- config/passport.js | 4 +- config/routes.js | 20 +- public/js/app.js | 33 ++- public/js/controllers.js | 23 +- public/js/controllers/checkLists.js | 102 ++++++++ public/js/controllers/deviceTypes.js | 13 +- public/js/controllers/devices.js | 159 ++++++++++++ public/js/controllers/testRuns.js | 58 +++++ public/js/directives.js | 33 +++ public/js/lib/hashids.js | 352 ++++++++++++++++++++++++++ public/js/services.js | 35 +++ public/partials/checkLists/add.html | 71 ++++++ public/partials/checkLists/index.html | 36 +++ public/partials/clients/edit.html | 4 +- public/partials/deviceTypes/add.html | 16 ++ public/partials/deviceTypes/edit.html | 190 +++++++++----- public/partials/devices/add.html | 118 +++++++-- public/partials/devices/edit.html | 255 ++++++++++++++----- public/partials/devices/index.html | 41 --- public/partials/testRuns/add.html | 70 +++++ public/partials/testRuns/view.html | 65 +++++ public/partials/workorders/add.html | 17 ++ public/partials/workorders/edit.html | 27 ++ server.js | 124 ++++----- 35 files changed, 1815 insertions(+), 276 deletions(-) create mode 100644 app/controllers/checkLists.js create mode 100644 app/controllers/testRuns.js create mode 100644 app/model/checkList.js create mode 100644 app/model/testRun.js create mode 100644 public/js/controllers/checkLists.js create mode 100644 public/js/controllers/testRuns.js create mode 100644 public/js/lib/hashids.js create mode 100644 public/partials/checkLists/add.html create mode 100644 public/partials/checkLists/index.html delete mode 100644 public/partials/devices/index.html create mode 100644 public/partials/testRuns/add.html create mode 100644 public/partials/testRuns/view.html diff --git a/app/controllers/checkLists.js b/app/controllers/checkLists.js new file mode 100644 index 0000000..0521fee --- /dev/null +++ b/app/controllers/checkLists.js @@ -0,0 +1,73 @@ +var mongoose = require('mongoose'), + CheckList = mongoose.model('CheckList'); + +var _ = require('lodash'); +var md5 = require('MD5'); + +var log = require('log4node'); + +exports.index = function(req, res, next) { + log.info('check_lists.index'); + + CheckList.find({ deleted: false }) + .exec(returnResult(res)); +}; + +exports.get = function(req, res, next) { + var id = req.param('check_list_id'); + + log.info("check_lists.get %s", id); + + CheckList.findById(id) + .exec(returnResult(res)); +}; + +exports.create = function(req, res, next) { + log.info("check_lists.create %j", res.body); + + var checkList = new CheckList(req.body); + checkList.save(returnResult(res)); +}; + +exports.update = function(req, res, next) { + var id = req.param('check_list_id'); + log.info('check_lists.update %s %j', id, req.body); + + CheckList.findById(id, function(err, checkList) { + if (err) { + log.error("Error: %s", err); + res.json(500, err); + } else if (!checkList) { + res.json(404, 'Unknown CheckList: %s', id); + } else { + _.assign(checkList, req.body); + checkList.save(returnResult(res, checkList)); + } + }); +}; + +function returnResult(res, result) { + return function(err, data) { + if (err) { + log.error("Error: %s", err); + res.json(500, err); + } else { + if (result) { + res.json(result); + } else { + res.json(data); + } + } + } +} + +function mutateResult(res, mutator) { + return function(err, results) { + if (err) { + log.error("Error: %s", err); + res.json(500, err); + } else { + res.json(mutator(results)); + } + } +} \ No newline at end of file diff --git a/app/controllers/devices.js b/app/controllers/devices.js index 7018885..9ad8ef4 100644 --- a/app/controllers/devices.js +++ b/app/controllers/devices.js @@ -1,5 +1,6 @@ var mongoose = require('mongoose'), - Device = mongoose.model('Device'); + Device = mongoose.model('Device'), + TestRun = mongoose.model('TestRun'); var _ = require('lodash'); var md5 = require('MD5'); @@ -9,7 +10,18 @@ var log = require('log4node'); exports.index = function(req, res, next) { log.info('devices.index'); - Device.find({ deleted: false }) + var query = { + deleted: false + }; + + var deviceType = req.param('deviceType'); + if (deviceType) { + query.deviceType = deviceType; + } + + Device.find(query) + .populate('deviceType', 'category make model') + .populate('client', 'name identifier') .exec(returnResult(res)); }; @@ -19,9 +31,25 @@ exports.get = function(req, res, next) { log.info("devices.get %s", id); Device.findById(id) + .populate('deviceType', 'category make model checkList') + .populate('deviceType.checkList', 'name fields') + .populate('client', 'name identifier') .exec(returnResult(res)); }; +exports.testRuns = function(req, res, next) { + var id = req.param('device_id'); + log.info("devices.testRuns %s", id); + + TestRun.find({device: id, deleted: false }) + .exec(function(err, devices) { + if (err) return next(err); + if (!devices) return next(new Error('Failed to load testRuns ' + id)); + + res.json(devices); + }); +} + exports.create = function(req, res, next) { log.info("devices.create %j", res.body); diff --git a/app/controllers/testRuns.js b/app/controllers/testRuns.js new file mode 100644 index 0000000..d733b28 --- /dev/null +++ b/app/controllers/testRuns.js @@ -0,0 +1,73 @@ +var mongoose = require('mongoose'), + TestRun = mongoose.model('TestRun'); + +var _ = require('lodash'); +var md5 = require('MD5'); + +var log = require('log4node'); + +exports.index = function(req, res, next) { + log.info('test_runs.index'); + + TestRun.find({ deleted: false }) + .exec(returnResult(res)); +}; + +exports.get = function(req, res, next) { + var id = req.param('test_run_id'); + + log.info("test_runs.get %s", id); + + TestRun.findById(id) + .exec(returnResult(res)); +}; + +exports.create = function(req, res, next) { + log.info("test_runs.create %j", res.body); + + var testRun = new TestRun(req.body); + testRun.save(returnResult(res)); +}; + +exports.update = function(req, res, next) { + var id = req.param('test_run_id'); + log.info('test_runs.update %s %j', id, req.body); + + TestRun.findById(id, function(err, testRun) { + if (err) { + log.error("Error: %s", err); + res.json(500, err); + } else if (!testRun) { + res.json(404, 'Unknown TestRun: %s', id); + } else { + _.assign(testRun, req.body); + testRun.save(returnResult(res, testRun)); + } + }); +}; + +function returnResult(res, result) { + return function(err, data) { + if (err) { + log.error("Error: %s", err); + res.json(500, err); + } else { + if (result) { + res.json(result); + } else { + res.json(data); + } + } + } +} + +function mutateResult(res, mutator) { + return function(err, results) { + if (err) { + log.error("Error: %s", err); + res.json(500, err); + } else { + res.json(mutator(results)); + } + } +} \ No newline at end of file diff --git a/app/controllers/workorders.js b/app/controllers/workorders.js index e667fa3..77e3784 100644 --- a/app/controllers/workorders.js +++ b/app/controllers/workorders.js @@ -77,7 +77,8 @@ module.exports = function(config, calendar) { scheduling: req.body.scheduling, techs: req.body.techs, alternativeContact: req.body.alternativeContact, - trackingNumber: req.body.trackingNumber + trackingNumber: req.body.trackingNumber, + devices: req.body.devices }); var notify = req.body._notify || ""; @@ -241,6 +242,7 @@ module.exports = function(config, calendar) { workorder.paidOn = req.body.paidOn; workorder.alternativeContact = req.body.alternativeContact; workorder.trackingNumber = req.body.trackingNumber; + workorder.devices = req.body.devices; callback(err); }); }, diff --git a/app/model/checkList.js b/app/model/checkList.js new file mode 100644 index 0000000..a857479 --- /dev/null +++ b/app/model/checkList.js @@ -0,0 +1,11 @@ +var mongoose = require('mongoose') + Schema = mongoose.Schema, + ObjectId = Schema.ObjectId; + +var checkListSchema = new Schema({ + name: String, + fields: [{}], + deleted: { type: Boolean, default: false } +}); + +module.exports = mongoose.model('CheckList', checkListSchema); diff --git a/app/model/device.js b/app/model/device.js index 1cbd44f..65aa8d7 100644 --- a/app/model/device.js +++ b/app/model/device.js @@ -11,6 +11,8 @@ var deviceSchema = new Schema({ purchaseDate: Date, warrantyExpiration: Date, location: String, + frequencyType: String, + frequencySchedule: [], deleted: { type: Boolean, default: false } }); diff --git a/app/model/deviceType.js b/app/model/deviceType.js index 9d3882c..5052b32 100644 --- a/app/model/deviceType.js +++ b/app/model/deviceType.js @@ -10,6 +10,7 @@ var deviceTypeSchema = new Schema({ links: String, partsRecommended: String, images: [{ type: String }], + checkList: { type: ObjectId, ref: 'CheckList' }, deleted: { type: Boolean, default: false } }); diff --git a/app/model/testRun.js b/app/model/testRun.js new file mode 100644 index 0000000..a083cea --- /dev/null +++ b/app/model/testRun.js @@ -0,0 +1,14 @@ +var mongoose = require('mongoose') + Schema = mongoose.Schema, + ObjectId = Schema.ObjectId; + +var testRunSchema = new Schema({ + device: { type: ObjectId, ref: 'Device' }, + fields: [{}], + date: Date, + result: Boolean, + comment: String, + deleted: { type: Boolean, default: false } +}); + +module.exports = mongoose.model('TestRun', testRunSchema); diff --git a/app/model/workorder.js b/app/model/workorder.js index 8615c74..dbc0d3e 100644 --- a/app/model/workorder.js +++ b/app/model/workorder.js @@ -30,7 +30,8 @@ var workorderSchema = new Schema({ checkNumber: String, paidOn: Date, alternativeContact: String, - trackingNumber: String + trackingNumber: String, + devices: [{ type: ObjectId, ref: 'Device' }] }); module.exports = mongoose.model('Workorder', workorderSchema); diff --git a/app/views/index.jade b/app/views/index.jade index 3b14b33..296554e 100644 --- a/app/views/index.jade +++ b/app/views/index.jade @@ -64,6 +64,10 @@ html(lang="en", ng-app="biomed", ng-controller="PageCtrl") a(href='/deviceTypes') | Devices + li(data-match-route='/checkLists.*') + a(href='/checkLists') + | Check Lists + li(data-match-route='/posts.*', ng-show="accountHasPermission('system.admin')") a(href='/posts') | Posts diff --git a/config/auth.js b/config/auth.js index 3277ce3..4b17735 100644 --- a/config/auth.js +++ b/config/auth.js @@ -15,8 +15,14 @@ module.exports = function(app, passport) { }); app.get('/auth/callback', function(req, res, next) { + + var callbackHost = req.headers['x-forwarded-host']; + if (!callbackHost) { + callbackHost = "localhost:9000"; + } + var options = { - callbackURL: 'http://' + req.headers['x-forwarded-host'] + '/auth/callback' + callbackURL: 'http://' + callbackHost + '/auth/callback' }; passport.authenticate('google', options, function(err, user, info) { var redirectUrl = '/'; diff --git a/config/passport.js b/config/passport.js index 275988b..bafd1ed 100644 --- a/config/passport.js +++ b/config/passport.js @@ -12,11 +12,11 @@ module.exports = function(passport, config) { done(err, user); }); }); - + console.log(config.auth.callback); passport.use(new GoogleStrategy({ clientID: config.auth.clientId, clientSecret: config.auth.clientSecret, -// callbackURL: config.auth.callback, + callbackURL: config.auth.callback, passReqToCallback: true }, function(req, accessToken, refreshToken, profile, done) { diff --git a/config/routes.js b/config/routes.js index e4bdf91..56d6620 100644 --- a/config/routes.js +++ b/config/routes.js @@ -9,18 +9,21 @@ module.exports = function(app, auth, piler, calendar, directory, config) { piler.addJsUrl("//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"); piler.addJsUrl("//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-route.js"); piler.addJsUrl("//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-resource.js"); - - piler.addJsUrl("http://d3js.org/d3.v2.js"); + piler.addJsUrl("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js") + piler.addJsFile("/js/lib/moment.js"); piler.addJsFile("/js/lib/bootstrap-datepicker.js"); piler.addJsFile("/js/lib/dialog.js"); piler.addJsFile("/js/lib/select2.js"); piler.addJsFile("/js/lib/dropzone.js"); + piler.addJsFile("/js/lib/hashids.js"); piler.addJsFile("/js/app.js"); piler.addJsFile("/js/controllers.js"); + piler.addJsFile("/js/controllers/checkLists.js"); piler.addJsFile("/js/controllers/devices.js"); piler.addJsFile("/js/controllers/deviceTypes.js"); + piler.addJsFile("/js/controllers/testRuns.js"); piler.addJsFile("/js/directives.js"); piler.addJsFile("/js/filters.js"); piler.addJsFile("/js/services.js"); @@ -65,6 +68,7 @@ module.exports = function(app, auth, piler, calendar, directory, config) { app.get('/api/devices', devices.index); app.get('/api/devices/isUnique', devices.isUnique); app.get('/api/devices/:device_id', devices.get); + app.get('/api/devices/:device_id/test_runs', devices.testRuns); app.post('/api/devices', devices.create); app.post('/api/devices/:device_id', devices.update); @@ -78,6 +82,18 @@ module.exports = function(app, auth, piler, calendar, directory, config) { app.post('/api/device_types', deviceTypes.create); app.post('/api/device_types/:device_type_id', deviceTypes.update); + var checkLists = require('../app/controllers/checkLists'); + app.get('/api/check_lists', checkLists.index); + app.get('/api/check_lists/:check_list_id', checkLists.get); + app.post('/api/check_lists', checkLists.create); + app.post('/api/check_lists/:check_list_id', checkLists.update); + + var testRuns = require('../app/controllers/testRuns'); + app.get('/api/test_runs', testRuns.index); + app.get('/api/test_runs/:test_run_id', testRuns.get); + app.post('/api/test_runs', testRuns.create); + app.post('/api/test_runs/:test_run_id', testRuns.update); + var pms = require('../app/controllers/pms'); app.get('/api/pms', pms.index); diff --git a/public/js/app.js b/public/js/app.js index 6c1d0c0..4952755 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -66,10 +66,6 @@ angular.module('biomed', ['biomed.filters', 'biomed.services', 'biomed.directive controller: "DeviceTypeIndexCtrl", reloadOnSearch: false }) - .when('/devices/add', { - templateUrl: '/partials/devices/add.html', - controller: "DeviceAddCtrl" - }) .when('/deviceTypes/add', { templateUrl: '/partials/deviceTypes/add.html', controller: "DeviceTypeAddCtrl" @@ -78,6 +74,35 @@ angular.module('biomed', ['biomed.filters', 'biomed.services', 'biomed.directive templateUrl: '/partials/deviceTypes/edit.html', controller: "DeviceTypeEditCtrl" }) + .when('/devices/add', { + templateUrl: '/partials/devices/add.html', + controller: "DeviceAddCtrl" + }) + .when('/devices/:id', { + templateUrl: '/partials/devices/edit.html', + controller: "DeviceEditCtrl" + }) + .when('/checkLists', { + templateUrl: '/partials/checkLists/index.html', + controller: "CheckListIndexCtrl", + reloadOnSearch: false + }) + .when('/checkLists/add', { + templateUrl: '/partials/checkLists/add.html', + controller: "CheckListAddCtrl" + }) + .when('/checkLists/:id', { + templateUrl: '/partials/checkLists/add.html', + controller: "CheckListEditCtrl" + }) + .when('/testRuns/add', { + templateUrl: '/partials/testRuns/add.html', + controller: "TestRunAddCtrl" + }) + .when('/testRuns/:id', { + templateUrl: '/partials/testRuns/view.html', + controller: "TestRunViewCtrl" + }) .when('/accounting', { templateUrl: '/partials/accounting/index.html', controller: "AccountingIndexCtrl", diff --git a/public/js/controllers.js b/public/js/controllers.js index 2b1a723..3c2dca4 100644 --- a/public/js/controllers.js +++ b/public/js/controllers.js @@ -936,6 +936,10 @@ angular.module('biomed') var client = $scope.clientPicker.data; $scope.model.client = client._id; $scope.currentClient = client; + + $scope.devices = Clients.devices({id: client._id}, function() { + console.log($scope.devices); + }); } else { $scope.model.client = null; $scope.currentClient = null; @@ -1082,7 +1086,7 @@ angular.module('biomed') } }) -.controller("WorkorderEditCtrl", function($scope, $routeParams, Workorders, Schedule, Users) { +.controller("WorkorderEditCtrl", function($scope, $routeParams, Workorders, Schedule, Users, Clients) { $scope.emailsOptions = { 'multiple': true, 'simple_tags': true, @@ -1099,17 +1103,24 @@ angular.module('biomed') $scope.$watch('group', updateUsers); - $scope.master = Workorders.get($routeParams, function() { - $scope.loading = false; + Workorders.get($routeParams, function(workorderData) { + Clients.devices({id: workorderData.client._id}, function(devicesData) { - if ($scope.master.reason == "Meeting") { - $scope.workorderType = "meeting"; - } + $scope.allDevices = devicesData; + $scope.master = workorderData; + + if ($scope.master.reason == "Meeting") { + $scope.workorderType = "meeting"; + } + + $scope.loading = false; + }); }); $scope.emails = createController(); $scope.status = createController(); $scope.remarks = createController(); + $scope.devices = createController(); $scope.scheduling = createSchedulingController(); function updateStatus() { diff --git a/public/js/controllers/checkLists.js b/public/js/controllers/checkLists.js new file mode 100644 index 0000000..a360843 --- /dev/null +++ b/public/js/controllers/checkLists.js @@ -0,0 +1,102 @@ +angular.module('biomed') +.controller("CheckListIndexCtrl", checkListsIndexController) +.controller("CheckListAddCtrl", checkListsControllerFactory(false)) +.controller("CheckListEditCtrl", checkListsControllerFactory(true)) + +function checkListsIndexController($scope, $filter, $routeParams, CheckLists, LocationBinder) { + $scope.loading = true; + + var allData = CheckLists.index(function() { + $scope.loading = false; + $scope.filter(); + }); + + var filteredData = []; + var index = 0; + var initialPageSize = 100; + var pageSize = 5; + + $scope.canLoad = true; + + $scope.$watch('query', function() { + $scope.filter(); + }); + + LocationBinder($scope, ['query']); + + $scope.filter = function() { + filteredData = $filter('orderBy')($filter('filter')(allData, $scope.query), $scope.sort.column, $scope.sort.descending); + index = initialPageSize; + $scope.canLoad = true; + $scope.checkLists = filteredData.slice(0, initialPageSize); + }; + + $scope.addItems = function() { + $scope.checkLists = $scope.checkLists.concat(filteredData.slice(index, index + pageSize)); + index += pageSize; + $scope.canLoad = index < filteredData.length; + } + + $scope.sort = { + column: 'name', + descending: false + }; + + $scope.selectedCls = function(column) { + return column == $scope.sort.column && 'sort-' + $scope.sort.descending; + } + + $scope.changeSorting = function(column) { + var sort = $scope.sort; + if (sort.column == column) { + sort.descending = !sort.descending; + } else { + sort.column = column; + sort.descending = false; + } + + $scope.filter(); + }; +} + +function checkListsControllerFactory(isEdit) { + return function($scope, CheckLists, $location, $filter, $routeParams) { + + function addField() { + $scope.model.fields.push({ type: 'boolean' }) + } + + function removeField(index) { + console.log('Index: ', index); + if (index != -1) { + $scope.model.fields.splice(index, 1); + } + } + + function save() { + if (isEdit) { + CheckLists.update({id: $scope.model._id}, $scope.model); + } else { + CheckLists.create($scope.model, function(result) { + $location.path("/checkLists/" + result._id); + }); + } + } + + $scope.addField = addField; + $scope.removeField = removeField; + $scope.save = save; + $scope.isEdit = isEdit; + + if (!isEdit) { + $scope.model = { + name: '', + fields: [] + }; + + addField(); + } else { + $scope.model = CheckLists.get($routeParams); + } + } +} \ No newline at end of file diff --git a/public/js/controllers/deviceTypes.js b/public/js/controllers/deviceTypes.js index fa5fa54..06349ec 100644 --- a/public/js/controllers/deviceTypes.js +++ b/public/js/controllers/deviceTypes.js @@ -56,12 +56,14 @@ angular.module('biomed') }; }) -.controller("DeviceTypeAddCtrl", function($scope, DeviceTypes, $location, $filter) { +.controller("DeviceTypeAddCtrl", function($scope, DeviceTypes, CheckLists, $location, $filter) { $scope.model = {}; $scope.categories = DeviceTypes.categories(); $scope.deviceMakes = DeviceTypes.makes(); + $scope.checkLists = CheckLists.index(); + $scope.categoryOpts = { containerCssClass: 'input-xxlarge', placeholder: 'Choose a Device Type', @@ -147,7 +149,7 @@ angular.module('biomed') }; }) -.controller("DeviceTypeEditCtrl", function($scope, DeviceTypes, $location, $filter, $routeParams) { +.controller("DeviceTypeEditCtrl", function($scope, DeviceTypes, Devices, CheckLists, $location, $filter, $routeParams) { var images = {}; $scope.model = DeviceTypes.get($routeParams, function() { @@ -164,9 +166,16 @@ angular.module('biomed') $scope.makePicker = {id: $scope.model.make, text: $scope.model.make}; }); + console.log($routeParams); + + $scope.devices = Devices.index({ deviceType: $routeParams.id }); + $scope.categories = DeviceTypes.categories(); $scope.deviceMakes = DeviceTypes.makes(); + $scope.checkLists = CheckLists.index(); + + $scope.categoryOpts = { containerCssClass: 'input-xxlarge', placeholder: 'Choose a Device Type', diff --git a/public/js/controllers/devices.js b/public/js/controllers/devices.js index 8b13789..79ecaf8 100644 --- a/public/js/controllers/devices.js +++ b/public/js/controllers/devices.js @@ -1 +1,160 @@ +angular.module('biomed') +.controller("DeviceAddCtrl", devicesControllerFactory(false)) +.controller("DeviceEditCtrl", devicesControllerFactory(true)) + +function devicesControllerFactory(isEdit) { + return function($scope, Devices, DeviceTypes, $location, $filter, $routeParams) { + function buildDeviceTypeFilterQuery(ignore) { + var query = {}; + + _.each(['category', 'make', 'model'], function(key) { + if (key == ignore) + return; + + if ($scope.deviceTypes[key].picker) { + query[key] = $scope.deviceTypes[key].picker.id; + } + }) + + return query; + } + + function filterDeviceTypeSelectors() { + console.log('Filtering Device Data'); + + var data = {}; + + _.each(['category', 'make', 'model'], function(key) { + var query = buildDeviceTypeFilterQuery(key); + var filteredResults = $filter('filter')(deviceTypesList, query); + + data[key] = []; + + _.each(filteredResults, function(entry) { + data[key].push(entry[key]); + }); + }); + + _.each(['category', 'make', 'model'], function(key) { + $scope.deviceTypes[key].data = _.uniq(data[key]); + + if (data[key].length == 1) { + var value = data[key][0]; + $scope.deviceTypes[key].picker = { id: value, text: value }; + } + }); + } + + function deviceTypePickerFactory(key, label) { + var optsKey = key + 'Opts'; + + $scope.deviceTypes[key] = {}; + $scope.deviceTypes[key].opts = { + containerCssClass: 'input-xxlarge', + placeholder: 'Choose a ' + label, + query: function(query) { + var data = $filter('filter')($scope.deviceTypes[key].data, query.term); + query.callback({ + results: _.map(data, function(entry) { + return { id: entry, text: entry } + }) + }); + } + }; + + $scope.$watch('deviceTypes.' + key + '.picker',function() { + filterDeviceTypeSelectors(); + updateDeviceTypeSelection(); + }, true); + } + + function clearDeviceTypePickers() { + _.each(['category', 'make', 'model'], function(key) { + $scope.deviceTypes[key].picker = null; + }); + } + + function updateDeviceTypeSelection() { + var query = buildDeviceTypeFilterQuery(); + var results = $filter('filter')(deviceTypesList, query); + + $scope.model.deviceType = (results.length == 1) ? results[0]._id : null; + } + + function generateRandomIdentifier() { + $scope.model.biomedId = hashids.encode(Date.now()); + } + + function toggleFrequency(index) { + $scope.model.frequencySchedule[index] = !$scope.model.frequencySchedule[index]; + + console.log($scope.model); + } + + function create() { + Devices.create($scope.model, function(result) { + console.log('here'); + $location.path("/devices/" + result._id); + }); + } + + function update() { + Devices.update({id: $scope.model._id}, $scope.model); + } + + var hashids = new Hashids("biomed"); + var search = $location.search(); + + $scope.model = { + frequencySchedule: [false, false, false, false, false, false, false, false, false, false, false, false] + }; + + $scope.toggleFrequency = toggleFrequency; + + $scope.deviceTypes = {}; + $scope.deviceTypes.reset = clearDeviceTypePickers; + + $scope.biomedId = {}; + $scope.biomedId.reset = generateRandomIdentifier; + + $scope.create = create; + $scope.update = update; + + deviceTypePickerFactory('category', 'Device Type'); + deviceTypePickerFactory('make', 'Make'); + deviceTypePickerFactory('model', 'Model'); + + var deviceTypesList = DeviceTypes.index(filterDeviceTypeSelectors) + + console.log((isEdit ? "Edit" : "Create") + " Mode"); + + if (isEdit) { + $scope.model = Devices.get($routeParams, function() { + $scope.loading = false; + + var deviceType = $scope.model.deviceType; + + _.each(['category', 'make', 'model'], function(key) { + $scope.deviceTypes[key].picker = { id: deviceType[key], text: deviceType[key] }; + }); + + $scope.model.client = $scope.model.client._id; + $scope.model.deviceType = $scope.model.deviceType._id; + + $scope.testRuns = Devices.testRuns($routeParams, function() { + console.log($scope.testRuns); + }); + }); + } else { + if (search.clientId) { + $scope.model.client = search.clientId; + } else { + $location.path("/deviceTypes"); + return; + } + + generateRandomIdentifier(); + } + } +} diff --git a/public/js/controllers/testRuns.js b/public/js/controllers/testRuns.js new file mode 100644 index 0000000..12cba84 --- /dev/null +++ b/public/js/controllers/testRuns.js @@ -0,0 +1,58 @@ +angular.module('biomed') +.controller("TestRunAddCtrl", testRunAddController) +.controller("TestRunViewCtrl", testRunViewController) + + +function testRunAddController($scope, Devices, CheckLists, TestRuns, $location, $filter, $routeParams) { + var search = $location.search(); + + console.log(search); + + $scope.device = Devices.get({id: search.deviceId}, function() { + console.log($scope.device); + + $scope.checkList = CheckLists.get({id: $scope.device.deviceType.checkList}, function() { + $scope.loading = false; + + $scope.model = { + device: $scope.device._id, + date: new Date(), + fields: [] + }; + + _.each($scope.checkList.fields, function(field) { + + if (field.type == 'boolean') { + field.value = 'false' + } + + field.result = false; + $scope.model.fields.push(field); + }); + }) + }); + + $scope.$watch('model', function() { + $scope.model.result = true; + + _.each($scope.model.fields, function(field) { + if (field.type == 'boolean') { + field.result = (field.value == 'true'); + } else if (field.type == 'range') { + field.result = field.value >= field.min && field.value <= field.max; + } + + $scope.model.result &= field.result; + }) + }, true); + + $scope.save = function() { + TestRuns.create($scope.model, function(result) { + $location.path("/testRuns/" + result._id); + }); + } +} + +function testRunViewController($scope, Devices, CheckLists, TestRuns, $location, $filter, $routeParams) { + $scope.model = TestRuns.get($routeParams); +} \ No newline at end of file diff --git a/public/js/directives.js b/public/js/directives.js index 363025c..7129b68 100644 --- a/public/js/directives.js +++ b/public/js/directives.js @@ -872,3 +872,36 @@ angular.module('biomed.directives', []) } }; }) +.directive('abDeviceUnique', function(Devices, $timeout) { + return { + restrict: 'A', + require: 'ngModel', + link: function(scope, element, attrs, ngModel) { + var stop_timeout; + return scope.$watch(function() { + return ngModel.$modelValue; + }, function(name) { + $timeout.cancel(stop_timeout); + + if (!name) { + ngModel.$setValidity('unique', true); + } + + stop_timeout = $timeout(function() { + var keyProperty = scope.$eval(attrs.abDeviceUnique); + + if (name) { + Devices.isUnique({ + key: keyProperty.key, + field: keyProperty.field, + value: name + }, function(result) { + console.log('unique = ' + result.isUnique); + ngModel.$setValidity('unique', result.isUnique); + }); + } + }, 200); + }); + } + }; +}) \ No newline at end of file diff --git a/public/js/lib/hashids.js b/public/js/lib/hashids.js new file mode 100644 index 0000000..703d0a4 --- /dev/null +++ b/public/js/lib/hashids.js @@ -0,0 +1,352 @@ + +/* + + Hashids + http://hashids.org/javascript + (c) 2013 Ivan Akimov + + https://github.com/ivanakimov/hashids.js + hashids may be freely distributed under the MIT license. + +*/ + +/*jslint plusplus: true, nomen: true, browser: true */ +/*global define */ + +var Hashids = (function () { + + "use strict"; + + function Hashids(salt, minHashLength, alphabet) { + + var uniqueAlphabet, i, j, len, sepsLength, diff, guardCount; + + this.version = "1.0.2"; + + /* internal settings */ + + this.minAlphabetLength = 16; + this.sepDiv = 3.5; + this.guardDiv = 12; + + /* error messages */ + + this.errorAlphabetLength = "error: alphabet must contain at least X unique characters"; + this.errorAlphabetSpace = "error: alphabet cannot contain spaces"; + + /* alphabet vars */ + + this.alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + this.seps = "cfhistuCFHISTU"; + this.minHashLength = parseInt(minHashLength, 10) > 0 ? minHashLength : 0; + this.salt = (typeof salt === "string") ? salt : ""; + + if (typeof alphabet === "string") { + this.alphabet = alphabet; + } + + for (uniqueAlphabet = "", i = 0, len = this.alphabet.length; i !== len; i++) { + if (uniqueAlphabet.indexOf(this.alphabet.charAt(i)) === -1) { + uniqueAlphabet += this.alphabet.charAt(i); + } + } + + this.alphabet = uniqueAlphabet; + + if (this.alphabet.length < this.minAlphabetLength) { + throw this.errorAlphabetLength.replace("X", this.minAlphabetLength); + } + + if (this.alphabet.search(" ") !== -1) { + throw this.errorAlphabetSpace; + } + + /* seps should contain only characters present in alphabet; alphabet should not contains seps */ + + for (i = 0, len = this.seps.length; i !== len; i++) { + + j = this.alphabet.indexOf(this.seps.charAt(i)); + if (j === -1) { + this.seps = this.seps.substr(0, i) + " " + this.seps.substr(i + 1); + } else { + this.alphabet = this.alphabet.substr(0, j) + " " + this.alphabet.substr(j + 1); + } + + } + + this.alphabet = this.alphabet.replace(/ /g, ""); + + this.seps = this.seps.replace(/ /g, ""); + this.seps = this.consistentShuffle(this.seps, this.salt); + + if (!this.seps.length || (this.alphabet.length / this.seps.length) > this.sepDiv) { + + sepsLength = Math.ceil(this.alphabet.length / this.sepDiv); + + if (sepsLength === 1) { + sepsLength++; + } + + if (sepsLength > this.seps.length) { + + diff = sepsLength - this.seps.length; + this.seps += this.alphabet.substr(0, diff); + this.alphabet = this.alphabet.substr(diff); + + } else { + this.seps = this.seps.substr(0, sepsLength); + } + + } + + this.alphabet = this.consistentShuffle(this.alphabet, this.salt); + guardCount = Math.ceil(this.alphabet.length / this.guardDiv); + + if (this.alphabet.length < 3) { + this.guards = this.seps.substr(0, guardCount); + this.seps = this.seps.substr(guardCount); + } else { + this.guards = this.alphabet.substr(0, guardCount); + this.alphabet = this.alphabet.substr(guardCount); + } + + } + + Hashids.prototype.encode = function () { + + var ret = "", i, len, + numbers = Array.prototype.slice.call(arguments); + + if (!numbers.length) { + return ret; + } + + if (numbers[0] instanceof Array) { + numbers = numbers[0]; + } + + for (i = 0, len = numbers.length; i !== len; i++) { + if (typeof numbers[i] !== "number" || numbers[i] % 1 !== 0 || numbers[i] < 0) { + return ret; + } + } + + return this._encode(numbers); + + }; + + Hashids.prototype.decode = function (hash) { + + var ret = []; + + if (!hash.length || typeof hash !== "string") { + return ret; + } + + return this._decode(hash, this.alphabet); + + }; + + Hashids.prototype.encodeHex = function (str) { + + var i, len, numbers; + + str = str.toString(); + if (!/^[0-9a-fA-F]+$/.test(str)) { + return ""; + } + + numbers = str.match(/[\w\W]{1,12}/g); + + for (i = 0, len = numbers.length; i !== len; i++) { + numbers[i] = parseInt("1" + numbers[i], 16); + } + + return this.encode.apply(this, numbers); + + }; + + Hashids.prototype.decodeHex = function (hash) { + + var ret = [], i, len, + numbers = this.decode(hash); + + for (i = 0, len = numbers.length; i !== len; i++) { + ret += (numbers[i]).toString(16).substr(1); + } + + return ret; + + }; + + Hashids.prototype._encode = function (numbers) { + + var ret, lottery, i, len, number, buffer, last, sepsIndex, guardIndex, guard, halfLength, excess, + alphabet = this.alphabet, + numbersSize = numbers.length, + numbersHashInt = 0; + + for (i = 0, len = numbers.length; i !== len; i++) { + numbersHashInt += (numbers[i] % (i + 100)); + } + + lottery = ret = alphabet.charAt(numbersHashInt % alphabet.length); + for (i = 0, len = numbers.length; i !== len; i++) { + + number = numbers[i]; + buffer = lottery + this.salt + alphabet; + + alphabet = this.consistentShuffle(alphabet, buffer.substr(0, alphabet.length)); + last = this.hash(number, alphabet); + + ret += last; + + if (i + 1 < numbersSize) { + number %= (last.charCodeAt(0) + i); + sepsIndex = number % this.seps.length; + ret += this.seps.charAt(sepsIndex); + } + + } + + if (ret.length < this.minHashLength) { + + guardIndex = (numbersHashInt + ret[0].charCodeAt(0)) % this.guards.length; + guard = this.guards[guardIndex]; + + ret = guard + ret; + + if (ret.length < this.minHashLength) { + + guardIndex = (numbersHashInt + ret[2].charCodeAt(0)) % this.guards.length; + guard = this.guards[guardIndex]; + + ret += guard; + + } + + } + + halfLength = parseInt(alphabet.length / 2, 10); + while (ret.length < this.minHashLength) { + + alphabet = this.consistentShuffle(alphabet, alphabet); + ret = alphabet.substr(halfLength) + ret + alphabet.substr(0, halfLength); + + excess = ret.length - this.minHashLength; + if (excess > 0) { + ret = ret.substr(excess / 2, this.minHashLength); + } + + } + + return ret; + + }; + + Hashids.prototype._decode = function (hash, alphabet) { + + var ret = [], i = 0, + lottery, len, subHash, buffer, + r = new RegExp("[" + this.guards + "]", "g"), + hashBreakdown = hash.replace(r, " "), + hashArray = hashBreakdown.split(" "); + + if (hashArray.length === 3 || hashArray.length === 2) { + i = 1; + } + + hashBreakdown = hashArray[i]; + if (typeof hashBreakdown[0] !== "undefined") { + + lottery = hashBreakdown[0]; + hashBreakdown = hashBreakdown.substr(1); + + r = new RegExp("[" + this.seps + "]", "g"); + hashBreakdown = hashBreakdown.replace(r, " "); + hashArray = hashBreakdown.split(" "); + + for (i = 0, len = hashArray.length; i !== len; i++) { + + subHash = hashArray[i]; + buffer = lottery + this.salt + alphabet; + + alphabet = this.consistentShuffle(alphabet, buffer.substr(0, alphabet.length)); + ret.push(this.unhash(subHash, alphabet)); + + } + + if (this._encode(ret) !== hash) { + ret = []; + } + + } + + return ret; + + }; + + Hashids.prototype.consistentShuffle = function (alphabet, salt) { + + var integer, j, temp, i, v, p; + + if (!salt.length) { + return alphabet; + } + + for (i = alphabet.length - 1, v = 0, p = 0; i > 0; i--, v++) { + + v %= salt.length; + p += integer = salt.charAt(v).charCodeAt(0); + j = (integer + v + p) % i; + + temp = alphabet.charAt(j); + alphabet = alphabet.substr(0, j) + alphabet.charAt(i) + alphabet.substr(j + 1); + alphabet = alphabet.substr(0, i) + temp + alphabet.substr(i + 1); + + } + + return alphabet; + + }; + + Hashids.prototype.hash = function (input, alphabet) { + + var hash = "", + alphabetLength = alphabet.length; + + do { + hash = alphabet.charAt(input % alphabetLength) + hash; + input = parseInt(input / alphabetLength, 10); + } while (input); + + return hash; + + }; + + Hashids.prototype.unhash = function (input, alphabet) { + + var number = 0, pos, i; + + for (i = 0; i < input.length; i++) { + pos = alphabet.indexOf(input[i]); + number += pos * Math.pow(alphabet.length, input.length - i - 1); + } + + return number; + + }; + + /* require.js bit */ + + if (typeof define === "function" && typeof define.amd === "object" && define.amd) { + + define(function () { + return Hashids; + }); + + } + + return Hashids; + +}()); \ No newline at end of file diff --git a/public/js/services.js b/public/js/services.js index 39e9313..71562f0 100644 --- a/public/js/services.js +++ b/public/js/services.js @@ -29,6 +29,41 @@ angular.module('biomed.services', []) destroy: { method: 'DELETE', params: { id: 0 } }, }); }) +.factory("Devices", function($resource) { + return $resource('/api/devices/:id/:cmd', + { id: "@id", cmd: "@cmd" }, + { + index: { method: 'GET', params: {}, isArray: true }, + get: { method: 'GET', params: { id: 0} }, + create: { method: 'POST', params: {} }, + update: { method: 'POST', params: { id: 0} }, + destroy: { method: 'DELETE', params: { id: 0 } }, + testRuns: { method: 'GET', params: { id: 0, cmd: 'test_runs' }, isArray: true }, + isUnique: { method: 'GET', params: { cmd: 'isUnique' } }, + }); +}) +.factory("CheckLists", function($resource) { + return $resource('/api/check_lists/:id/:cmd', + { id: "@id", cmd: "@cmd" }, + { + index: { method: 'GET', params: {}, isArray: true }, + get: { method: 'GET', params: { id: 0} }, + create: { method: 'POST', params: {} }, + update: { method: 'POST', params: { id: 0} }, + destroy: { method: 'DELETE', params: { id: 0 } }, + }); +}) +.factory("TestRuns", function($resource) { + return $resource('/api/test_runs/:id/:cmd', + { id: "@id", cmd: "@cmd" }, + { + index: { method: 'GET', params: {}, isArray: true }, + get: { method: 'GET', params: { id: 0} }, + create: { method: 'POST', params: {} }, + update: { method: 'POST', params: { id: 0} }, + destroy: { method: 'DELETE', params: { id: 0 } }, + }); +}) .factory("Posts", function($resource) { return $resource('/api/posts/:id', { id: "@id" }, diff --git a/public/partials/checkLists/add.html b/public/partials/checkLists/add.html new file mode 100644 index 0000000..0d97f78 --- /dev/null +++ b/public/partials/checkLists/add.html @@ -0,0 +1,71 @@ + +
+

New Check List

+
+
+
+ +
+
+
+ +
+ +
+
+
+
+
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+ +
+ + +
+
+
diff --git a/public/partials/checkLists/index.html b/public/partials/checkLists/index.html new file mode 100644 index 0000000..317975e --- /dev/null +++ b/public/partials/checkLists/index.html @@ -0,0 +1,36 @@ + +
+

Check Lists

+
+ +
+
+
+ Create new Check List +
+ Search: +
+ + +
+
+
+ + + + + + + + + + + + + + +
Name
There is no information to display.
{{checkList.name}}
+
+
diff --git a/public/partials/clients/edit.html b/public/partials/clients/edit.html index e7c6424..f7aff98 100644 --- a/public/partials/clients/edit.html +++ b/public/partials/clients/edit.html @@ -299,7 +299,7 @@ Device ID - Device + Category Make Model Serial No. @@ -313,7 +313,7 @@ There is no information to display. {{device.biomedId}} - + {{device.deviceType.category}} {{device.deviceType.make}} {{device.deviceType.model}} {{device.serialNumber}} diff --git a/public/partials/deviceTypes/add.html b/public/partials/deviceTypes/add.html index dd15240..8643fee 100644 --- a/public/partials/deviceTypes/add.html +++ b/public/partials/deviceTypes/add.html @@ -57,6 +57,22 @@ +
+ +
+
+
+ +
+ +
+
+
+
+
diff --git a/public/partials/deviceTypes/edit.html b/public/partials/deviceTypes/edit.html index 0a3f6c3..1f0b728 100644 --- a/public/partials/deviceTypes/edit.html +++ b/public/partials/deviceTypes/edit.html @@ -6,75 +6,127 @@

Edit Device

-
-
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
- -
-
-
- -
-
-
-
-
-
-
+
+
+
-
- -
- + +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+ +
+
+
+ +
+ +
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+ +
+ +
+ +
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
Device IDClientSerial No.Purchase DateWarranty ExpirationLocation
There is no information to display.
{{device.biomedId}}{{device.client.name}} ({{device.client.identifier}}){{device.serialNumber}}{{device.purchaseDate | date}}{{device.warrantyExpiration | date}}{{device.location}}
+
+
- +
diff --git a/public/partials/devices/add.html b/public/partials/devices/add.html index 72dd30a..e5cba49 100644 --- a/public/partials/devices/add.html +++ b/public/partials/devices/add.html @@ -8,25 +8,54 @@
- +
- +
- +
- +
- + +
+
+
+ +
+ +
+
+
+
+
+
+ +
+
+
+ + +
+ + Identifier must be unique
@@ -37,44 +66,101 @@
- +
- +
- +
- +
- +
- + +
+
+
+ +
+
- +
- +
-
+ +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC
+ + + +
-
- +
diff --git a/public/partials/devices/edit.html b/public/partials/devices/edit.html index 0a3f6c3..e5cc980 100644 --- a/public/partials/devices/edit.html +++ b/public/partials/devices/edit.html @@ -6,75 +6,196 @@

Edit Device

-
-
- -
-
-
- -
- +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
-
- -
- -
-
-
- -
- -
-
-
-
-
-
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
-
-
- -
-
-
- -
-
-
-
-
-
-
+
+ +
+
+
-
- -
- + +
+ + Identifier must be unique +
+
+
+
+
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC
+ + + +
+
+
+
+
+
+ +
+ +
+ +
+
+ +
+
+
+
+ New Test Run + + + + + + + + + + + + + + + +
RunResult
There is no information to display.
{{testRun.date | date}} + Passed + Failed +
+
+
- +
diff --git a/public/partials/devices/index.html b/public/partials/devices/index.html deleted file mode 100644 index 01a9e91..0000000 --- a/public/partials/devices/index.html +++ /dev/null @@ -1,41 +0,0 @@ - -
-

Devices

-
- -
-
-
- Create new Device -
- Search: -
- - -
-
-
- - - - - - - - - - - - - - - - - - - -
Device TypeMakeModel
There is no information to display.
{{device.category}}{{device.make}}{{device.model}}Edit
-
-
diff --git a/public/partials/testRuns/add.html b/public/partials/testRuns/add.html new file mode 100644 index 0000000..95e174b --- /dev/null +++ b/public/partials/testRuns/add.html @@ -0,0 +1,70 @@ + +
+

New Test Run

+
+
+
+ +
+
+
+ +
+

{{field.label}}

+

Passing Values: {{field.min}} - {{field.max}}

+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+ +
+
+
+ +
+ Passed + Failed +
+
+
+ +
+ +
+
+
+
+
+
+ +
+ +
+
+
diff --git a/public/partials/testRuns/view.html b/public/partials/testRuns/view.html new file mode 100644 index 0000000..c15a8fe --- /dev/null +++ b/public/partials/testRuns/view.html @@ -0,0 +1,65 @@ + +
+

Test Results

+
+
+
+ +
+
+
+ +
+

{{field.label}}

+

Passing Values: {{field.min}} - {{field.max}}

+
+
+
+ +
+

+ Passed + Failed +

+
+
+
+ +
+

{{field.value}}

+
+
+
+ +
+

{{field.comments}}

+
+
+
+
+
+
+ +
+
+
+ +
+

+ Passed + Failed +

+
+
+
+ +
+

{{model.comments}}

+
+
+
+
+
+
diff --git a/public/partials/workorders/add.html b/public/partials/workorders/add.html index 0343ede..b73bb2b 100644 --- a/public/partials/workorders/add.html +++ b/public/partials/workorders/add.html @@ -116,6 +116,23 @@
+
+ +
+
+
+ +
+ +
+
+
+
+
diff --git a/public/partials/workorders/edit.html b/public/partials/workorders/edit.html index e5a083f..8f9be34 100644 --- a/public/partials/workorders/edit.html +++ b/public/partials/workorders/edit.html @@ -121,6 +121,33 @@
+
+ +
+
+ Devices: {{master.devices.length}}
+ Edit +
+
+
+ +
+ {{devices.devices}} + +
+
+
+ + + +
+
+
+
diff --git a/server.js b/server.js index c284598..80ef3dd 100644 --- a/server.js +++ b/server.js @@ -1,40 +1,36 @@ + +var PUSHOVER_ENABLED = true; + +var env = 'prod'; + var pushover = require('pushover-notifications'); - -var express = require('express') - fs = require('fs'), - passport = require('passport'); - -var env = 'prod', - config = require('./config/config')[env], - mongoose = require('mongoose'), - Promise = require('bluebird'); - +var express = require('express'); +var fs = require('fs'); +var passport = require('passport'); +var config = require('./config/config')[env]; +var mongoose = require('mongoose'); +var Promise = require('bluebird'); var log = require('log4node'); Promise.promisifyAll(mongoose); - process.on('uncaughtException', function(err) { - console.log('Uncaught Exception:', err); - console.log(err.stack); +var pushoverApi = new pushover({ + user: 'aJmPD4KigO0vLwim76n3WqWKwbKA3k', + token: 'YxspDLz3WinbPmwBThuZXCME9QmkDb' +}); - var p = new pushover({ - user: 'aJmPD4KigO0vLwim76n3WqWKwbKA3k', - token: 'YxspDLz3WinbPmwBThuZXCME9QmkDb' - }); +process.on('uncaughtException', function(err) { + console.log('Uncaught Exception:', err); + console.log(err.stack); - var message = { - title: 'Unhandled error in portal', - message: 'Process was reset on ' + new Date(), - sound: 'falling' - }; - p.send(message, function(err, result) { - if (err) { - log.emergency('Error while sending pushover notification'); - log.emergency(err); - } - process.exit(1); - }); - }); + sendPushOver( + 'Unhandled error in portal', + 'Process was reset on ' + new Date(), + 'falling', + function() { + process.exit(1); + }); +}); log.info("----- Server Started -----"); @@ -45,15 +41,15 @@ mongoose.connect(config.database); // bootstrap model var modelPath = __dirname + '/app/model' fs.readdirSync(modelPath).forEach(function (file) { - require(modelPath + '/' + file) + require(modelPath + '/' + file) }) require('./config/passport')(passport, config); var app = express(), - http = require('http'), - server = http.createServer(app), - io = require('socket.io').listen(server); + http = require('http'), + server = http.createServer(app), + io = require('socket.io').listen(server); // Configure piler var piler = require('./config/piler')(app, server, io, config); @@ -75,35 +71,43 @@ GLOBAL.health = 'OK' var port = process.env.PORT || 9000 server.on('error', function(e) { - if (e.code == 'EADDRINUSE') { - console.log('Address in use, retrying...'); - setTimeout(function() { - server.close(); - server.listen(port, onListen); - }, 1000); - } + if (e.code == 'EADDRINUSE') { + console.log('Address in use, retrying...'); + setTimeout(function() { + server.close(); + server.listen(port, onListen); + }, 1000); + } }); - server.listen(port, onListen); - - function onListen() { - var p = new pushover({ - user: 'aJmPD4KigO0vLwim76n3WqWKwbKA3k', - token: 'YxspDLz3WinbPmwBThuZXCME9QmkDb' - }); - - var message = { - title: 'Portal is running', - message: 'Process was reset on ' + new Date(), - sound: 'bugle' - }; - p.send(message, function(err, result) { - if (err) { - log.emergency('Error while sending pushover notification'); - log.emergency(err); - } - }); + sendPushOver( + 'Portal is running', + 'Process was reset on ' + new Date(), + 'bugle'); +} + +function sendPushOver(title, message, sound, callback) { + if (!PUSHOVER_ENABLED) { + return; + } + + var data = { + title: title, + message: message, + sound: sound + }; + + pushoverApi.send(data, function(err, result) { + if (err) { + log.emergency('Error while sending pushover notification'); + log.emergency(err); + } + + if (callback) { + callback(); + } + }); }