diff --git a/app/controllers/devices.js b/app/controllers/devices.js
new file mode 100644
index 0000000..c3bae86
--- /dev/null
+++ b/app/controllers/devices.js
@@ -0,0 +1,132 @@
+var mongoose = require('mongoose'),
+ Device = mongoose.model('Device');
+
+var _ = require('lodash');
+var md5 = require('MD5');
+
+var log = require('log4node');
+
+exports.index = function(req, res) {
+ log.info('devices.index');
+ var query = Device.find({ deleted: false })
+ .exec(function(err, results) {
+ if (err) {
+ res.json(500, err);
+ } else {
+ res.json(results);
+ }
+ });
+};
+
+exports.get = function(req, res, next) {
+ var id = req.param('device_id');
+
+ log.info("devices.get %s", id);
+ Device.findById(id)
+ .exec(function(err, device) {
+ if (err) return next(err);
+ if (!device) return next(new Error('failed to load device ' + id));
+
+ res.json(device);
+ });
+};
+
+exports.deviceTypes = function(req, res, next) {
+ log.info("devices.deviceTypes");
+
+ var query = Device.find({ deleted: false })
+ .select('deviceType')
+ .exec(function(err, results) {
+ if (err) {
+ res.json(500, err);
+ } else {
+ res.json(_.uniq(_.pluck(results, 'deviceType')));
+ }
+ });
+};
+
+exports.makes = function(req, res, next) {
+ log.info("devices.makes");
+
+ var query = Device.find({ deleted: false })
+ .select('make')
+ .exec(function(err, results) {
+ if (err) {
+ res.json(500, err);
+ } else {
+ res.json(_.uniq(_.pluck(results, 'make')));
+ }
+ });
+};
+
+exports.models = function(req, res, next) {
+ log.info("devices.models");
+
+ var query = Device.find({ deleted: false })
+ .select('model')
+ .exec(function(err, results) {
+ if (err) {
+ res.json(500, err);
+ } else {
+ res.json(_.uniq(_.pluck(results, 'model')));
+ }
+ });
+};
+
+exports.create = function(req, res, next) {
+ log.info("devices.create %j", res.body);
+
+ var device = new Device({
+ deviceType: req.body.deviceType,
+ make: req.body.make,
+ model: req.body.model,
+ technicalData: req.body.technicalData,
+ links: req.body.links,
+ partsRecommended: req.body.partsRecommended,
+ images: req.body.images
+ });
+
+ return device.save(function(err) {
+ if (err)
+ log.error("Error: %s", err);
+ return res.json(device);
+ });
+};
+
+exports.update = function(req, res, next) {
+ var id = req.param('device_id');
+ log.info('devices.update %s %j', id, req.body);
+
+ return Device.findById(id, function(err, device) {
+ device.deviceType = req.body.deviceType;
+ device.make = req.body.make;
+ device.model = req.body.model;
+ device.technicalData = req.body.technicalData;
+ device.links = req.body.links;
+ device.partsRecommended = req.body.partsRecommended;
+ device.images = req.body.images;
+
+ return device.save(function(err) {
+ if (err)
+ log.error("Error: %s", err);
+ return res.json(device);
+ });
+ });
+};
+
+exports.upload = function(req, res, next) {
+ var path = req.files.file.path;
+
+ fs.readFile(path, function(err, data) {
+ var hash = md5(data);
+
+ fs.writeFile('/srv/biomed-site/images/devices/' + hash, data, function(err) {
+ if (err)
+ log.error("Error: %s", err);
+
+ return res.json({
+ filename: hash
+ });
+ });
+ });
+};
diff --git a/app/model/device.js b/app/model/device.js
new file mode 100644
index 0000000..244aff5
--- /dev/null
+++ b/app/model/device.js
@@ -0,0 +1,16 @@
+var mongoose = require('mongoose')
+ Schema = mongoose.Schema,
+ ObjectId = Schema.ObjectId;
+
+var deviceSchema = new Schema({
+ deviceType: String,
+ make: String,
+ model: String,
+ technicalData: String,
+ links: String,
+ partsRecommended: String,
+ images: [{ type: String }],
+ deleted: { type: Boolean, default: false }
+});
+
+module.exports = mongoose.model('Device', deviceSchema);
diff --git a/app/views/index.jade b/app/views/index.jade
index 854ecf8..e847859 100644
--- a/app/views/index.jade
+++ b/app/views/index.jade
@@ -60,6 +60,10 @@ html(lang="en", ng-app="biomed", ng-controller="PageCtrl")
a(href='/accounting')
| Accounting
+ li(data-match-route='/devices.*')
+ a(href='/devices')
+ | Devices
+
li(data-match-route='/posts.*', ng-show="accountHasPermission('system.admin')")
a(href='/posts')
| Posts
diff --git a/cli.js b/cli.js
new file mode 100644
index 0000000..580befb
--- /dev/null
+++ b/cli.js
@@ -0,0 +1,17 @@
+var fs = require('fs');
+
+var env = 'prod',
+ config = require('./config/config')[env],
+ mongoose = require('mongoose'),
+ Promise = require('bluebird');
+
+// bootstrap db connection
+mongoose.set('debug', config.debug);
+mongoose.connect(config.database);
+
+// bootstrap model
+var modelPath = __dirname + '/app/model'
+fs.readdirSync(modelPath).forEach(function (file) {
+ require(modelPath + '/' + file)
+})
+
diff --git a/config/routes.js b/config/routes.js
index 47498a0..7297478 100644
--- a/config/routes.js
+++ b/config/routes.js
@@ -58,6 +58,16 @@ module.exports = function(app, auth, piler, calendar, directory, config) {
app.post('/api/workorders/:workorder_id', workorders.update);
app.del('/api/workorders/:workorder_id', workorders.destroy);
+ var devices = require('../app/controllers/devices');
+ app.get('/api/devices', devices.index);
+ app.get('/api/devices/deviceTypes', devices.deviceTypes);
+ app.get('/api/devices/makes', devices.makes);
+ app.get('/api/devices/models', devices.models);
+ app.post('/api/devices/images', devices.upload);
+ app.get('/api/devices/:device_id', devices.get);
+ app.post('/api/devices', devices.create);
+ app.post('/api/devices/:device_id', devices.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 1f358cc..1ad432e 100644
--- a/public/js/app.js
+++ b/public/js/app.js
@@ -61,6 +61,19 @@ angular.module('biomed', ['biomed.filters', 'biomed.services', 'biomed.directive
templateUrl: '/partials/clients/edit.html',
controller: "ClientEditCtrl"
})
+ .when('/devices', {
+ templateUrl: '/partials/devices/index.html',
+ controller: "DeviceIndexCtrl",
+ reloadOnSearch: false
+ })
+ .when('/devices/add', {
+ templateUrl: '/partials/devices/add.html',
+ controller: "DeviceAddCtrl"
+ })
+ .when('/devices/:id', {
+ templateUrl: '/partials/devices/edit.html',
+ controller: "DeviceEditCtrl"
+ })
.when('/accounting', {
templateUrl: '/partials/accounting/index.html',
controller: "AccountingIndexCtrl",
diff --git a/public/js/controllers.js b/public/js/controllers.js
index 20ef6bd..74e658a 100644
--- a/public/js/controllers.js
+++ b/public/js/controllers.js
@@ -705,6 +705,257 @@ angular.module('biomed')
}
})
+.controller("DeviceIndexCtrl", function($scope, $filter, $routeParams, Devices, LocationBinder) {
+ $scope.loading = true;
+
+ var allData = Devices.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.devices = filteredData.slice(0, initialPageSize);
+ };
+
+ $scope.addItems = function() {
+ $scope.devices = $scope.devices.concat(filteredData.slice(index, index + pageSize));
+ index += pageSize;
+ $scope.canLoad = index < filteredData.length;
+ }
+
+ $scope.sort = {
+ column: 'deviceType',
+ 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();
+ };
+})
+
+.controller("DeviceAddCtrl", function($scope, Devices, $location, $filter) {
+ $scope.model = {};
+
+ $scope.deviceTypes = Devices.deviceTypes();
+ $scope.deviceMakes = Devices.makes();
+
+ $scope.deviceTypeOpts = {
+ containerCssClass: 'input-xxlarge',
+ placeholder: 'Choose a Device Type',
+ query: function(query) {
+ var data = $filter('filter')($scope.deviceTypes, query.term);
+ var results = [];
+ data.forEach(function(item) {
+ results.push({id: item, text: item});
+ });
+ query.callback({results: results });
+ },
+ createSearchChoice: function(term) {
+ return { id: term, text: term };
+ }
+ };
+
+ $scope.makeOpts = {
+ containerCssClass: 'input-xxlarge',
+ placeholder: 'Choose a Device Make',
+ query: function(query) {
+ var data = $filter('filter')($scope.deviceMakes, query.term);
+ var results = [];
+ data.forEach(function(item) {
+ results.push({id: item, text: item});
+ });
+ query.callback({results: results });
+ },
+ createSearchChoice: function(term) {
+ return { id: term, text: term };
+ }
+ };
+
+ var images = {};
+
+ $scope.imageOpts = {
+ options: {
+ url: '/api/devices/images',
+ addRemoveLinks: true
+ },
+ eventHandlers: {
+ success: function(file, response) {
+ file.filename = response.filename;
+
+ if (images[file.filename]) {
+ images[file.filename]++;
+ this.removeFile(file);
+ } else {
+ images[file.filename] = 1;
+ }
+ },
+ removedfile: function(file) {
+ images[file.filename]--;
+
+ if (images[file.filename] <= 0) {
+ delete images[file.filename];
+ }
+ }
+ }
+ };
+
+ $scope.$watch('deviceTypePicker', function() {
+ if ($scope.deviceTypePicker) {
+ $scope.model.deviceType = $scope.deviceTypePicker.id;
+ } else {
+ $scope.model.deviceType = null;
+ }
+ });
+
+ $scope.$watch('makePicker', function() {
+ if ($scope.makePicker) {
+ $scope.model.make = $scope.makePicker.id;
+ } else {
+ $scope.model.make = null;
+ }
+ });
+
+ $scope.save = function() {
+ $scope.model.images = Object.keys(images);
+
+ Devices.create($scope.model, function(result) {
+// $location.path("/devices/" + result._id);
+ $location.path("/devices/");
+ });
+ };
+})
+
+.controller("DeviceEditCtrl", function($scope, Devices, $location, $filter, $routeParams) {
+ var images = {};
+
+ $scope.model = Devices.get($routeParams, function() {
+ $scope.loading = false;
+
+ $scope.existingImages = $scope.model.images;
+ if ($scope.model.images) {
+ for (var i = 0; i < $scope.model.images.length; i++) {
+ images[$scope.model.images[i]] = 1;
+ }
+ }
+
+ $scope.deviceTypePicker = {id: $scope.model.deviceType, text: $scope.model.deviceType};
+ $scope.makePicker = {id: $scope.model.make, text: $scope.model.make};
+ });
+
+ $scope.deviceTypes = Devices.deviceTypes();
+ $scope.deviceMakes = Devices.makes();
+
+ $scope.deviceTypeOpts = {
+ containerCssClass: 'input-xxlarge',
+ placeholder: 'Choose a Device Type',
+ query: function(query) {
+ var data = $filter('filter')($scope.deviceTypes, query.term);
+ var results = [];
+ data.forEach(function(item) {
+ results.push({id: item, text: item});
+ });
+ query.callback({results: results });
+ },
+ createSearchChoice: function(term) {
+ return { id: term, text: term };
+ }
+ };
+
+ $scope.makeOpts = {
+ containerCssClass: 'input-xxlarge',
+ placeholder: 'Choose a Device Make',
+ query: function(query) {
+ var data = $filter('filter')($scope.deviceMakes, query.term);
+ var results = [];
+ data.forEach(function(item) {
+ results.push({id: item, text: item});
+ });
+ query.callback({results: results });
+ },
+ createSearchChoice: function(term) {
+ return { id: term, text: term };
+ }
+ };
+
+ $scope.imageOpts = {
+ options: {
+ url: '/api/devices/images',
+ addRemoveLinks: true
+ },
+ eventHandlers: {
+ success: function(file, response) {
+ file.filename = response.filename;
+
+ if (images[file.filename]) {
+ images[file.filename]++;
+ this.removeFile(file);
+ } else {
+ images[file.filename] = 1;
+ }
+ },
+ removedfile: function(file) {
+ images[file.filename]--;
+
+ if (images[file.filename] <= 0) {
+ delete images[file.filename];
+ }
+ }
+ }
+ };
+
+ $scope.$watch('deviceTypePicker', function() {
+ if ($scope.deviceTypePicker) {
+ $scope.model.deviceType = $scope.deviceTypePicker.id;
+ } else {
+ $scope.model.deviceType = null;
+ }
+ });
+
+ $scope.$watch('makePicker', function() {
+ if ($scope.makePicker) {
+ $scope.model.make = $scope.makePicker.id;
+ } else {
+ $scope.model.make = null;
+ }
+ });
+
+ $scope.save = function() {
+ $scope.model.images = Object.keys(images);
+
+ Devices.update({id: $scope.model._id}, $scope.model, function(result) {
+ $location.path("/devices/");
+ });
+ };
+})
+
.controller("AccountingIndexCtrl", function($scope, $filter, $routeParams, Workorders, LocationBinder) {
$scope.loading = true;
diff --git a/public/js/directives.js b/public/js/directives.js
index 3ec6128..363025c 100644
--- a/public/js/directives.js
+++ b/public/js/directives.js
@@ -807,7 +807,8 @@ angular.module('biomed.directives', [])
return {
scope: {
dropzone: '=',
- existing: '='
+ existing: '=',
+ prefix: '@'
},
controller: function($scope, $element, $attrs) {
var config, dropzone;
@@ -821,13 +822,16 @@ angular.module('biomed.directives', [])
$scope.$watch('existing', function() {
var existing = $scope.existing;
- console.log(dropzone);
+ var prefix = "http://atlanticbiomedical.com/images/";
+ if ($scope.prefix) {
+ prefix = prefix + $scope.prefix;
+ }
if (existing) {
for (var i = 0; i < existing.length; i++) {
var file = { name: existing[i], size: 0, accepted: true, filename: existing[i] };
dropzone.options.addedfile.call(dropzone, file);
- dropzone.options.thumbnail.call(dropzone, file, "http://atlanticbiomedical.com/images/" + existing[i]);
+ dropzone.options.thumbnail.call(dropzone, file, prefix + existing[i]);
dropzone.files.push(file);
}
}
diff --git a/public/js/services.js b/public/js/services.js
index 652a691..f71f4f5 100644
--- a/public/js/services.js
+++ b/public/js/services.js
@@ -14,6 +14,20 @@ angular.module('biomed.services', [])
isUnique: { method: 'GET', params: { cmd: 'isUnique' } },
});
})
+.factory("Devices", function($resource) {
+ return $resource('/api/devices/:id/:cmd',
+ { id: "@id", cmd: "@cmd" },
+ {
+ index: { method: 'GET', params: {}, isArray: true },
+ deviceTypes: { method: 'GET', params: { cmd: 'deviceTypes' }, isArray: true },
+ makes: { method: 'GET', params: { cmd: 'makes' }, isArray: true },
+ models: { method: 'GET', params: { cmd: 'models' }, 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/clients/edit.html b/public/partials/clients/edit.html
index 8465eca..7ccaaeb 100644
--- a/public/partials/clients/edit.html
+++ b/public/partials/clients/edit.html
@@ -6,8 +6,8 @@
{{master.identifier}}{{master.name}}
Device Type | +Make | +Model | ++ |
---|---|---|---|
{{device.deviceType}} | +{{device.make}} | +{{device.model}} | +Edit | +