mirror of
https://github.com/atlanticbiomedical/biomedjs.git
synced 2025-07-02 00:47:26 -04:00
Added clock stuff
This commit is contained in:
42
app/controllers/clock.js
Normal file
42
app/controllers/clock.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
var mongoose = require('mongoose'),
|
||||||
|
Clock = mongoose.model('Clock');
|
||||||
|
|
||||||
|
module.exports = function(piler) {
|
||||||
|
return {
|
||||||
|
index: function(req, res, next) {
|
||||||
|
host = String(req.headers['x-forwarded-host']);
|
||||||
|
host = host.split(':')[0];
|
||||||
|
|
||||||
|
if (host != 'clock.atlb.co') {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.user) {
|
||||||
|
req.session.redirectUrl = req.url
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = req.path.slice(1);
|
||||||
|
|
||||||
|
res.render('clock.jade', {
|
||||||
|
css: piler.css.renderTags()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
post: function(req, res) {
|
||||||
|
var clock = new Clock({
|
||||||
|
tech: req.user,
|
||||||
|
action: req.body.action,
|
||||||
|
lat: req.body.lat,
|
||||||
|
long: req.body.long,
|
||||||
|
dt: new Date()
|
||||||
|
});
|
||||||
|
|
||||||
|
clock.save(function(err, result) {
|
||||||
|
if (err) {
|
||||||
|
return res.json(500, err);
|
||||||
|
} else {
|
||||||
|
res.json(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
var mongoose = require('mongoose'),
|
var mongoose = require('mongoose'),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
User = mongoose.model('User');
|
User = mongoose.model('User'),
|
||||||
|
Clock = mongoose.model('Clock');
|
||||||
|
|
||||||
var log = require('log4node');
|
var log = require('log4node');
|
||||||
|
|
||||||
@ -163,6 +164,24 @@ module.exports = function(config, directory) {
|
|||||||
return res.json(user);
|
return res.json(user);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clocks: function(req, res) {
|
||||||
|
var id = req.param('user_id');
|
||||||
|
|
||||||
|
var criteria = {
|
||||||
|
tech: id
|
||||||
|
};
|
||||||
|
|
||||||
|
var query = Clock.find(criteria)
|
||||||
|
.sort('-dt')
|
||||||
|
.exec(function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
res.json(500, err);
|
||||||
|
} else {
|
||||||
|
res.json(results);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
14
app/model/clock.js
Normal file
14
app/model/clock.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
var mongoose = require('mongoose'),
|
||||||
|
Schema = mongoose.Schema,
|
||||||
|
ObjectId = Schema.ObjectId;
|
||||||
|
|
||||||
|
var clockSchema = new Schema({
|
||||||
|
_id: String,
|
||||||
|
tech: { type: ObjectId, ref: 'User' },
|
||||||
|
dt: Date,
|
||||||
|
action: String,
|
||||||
|
lat: Number,
|
||||||
|
long: Number
|
||||||
|
}, { versionKey: false })
|
||||||
|
|
||||||
|
var Clock = module.exports = mongoose.model('Clock', clockSchema);
|
40
app/views/clock.jade
Normal file
40
app/views/clock.jade
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
doctype 5
|
||||||
|
html(lang="en", ng-app="clock", ng-controller="clock.PageCtrl")
|
||||||
|
head
|
||||||
|
title Atlantic Biomedical
|
||||||
|
!{css}
|
||||||
|
link(rel='stylesheet', href='/css/clock.css')
|
||||||
|
meta(name='viewport', content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0')
|
||||||
|
body
|
||||||
|
script(type='text/javascript', src='//ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular.js')
|
||||||
|
script(type='text/javascript', src='//ajax.googleapis.com/ajax/libs/angularjs/1.1.4/angular-resource.js')
|
||||||
|
script(type='text/javascript', src='//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js')
|
||||||
|
script(type='text/javascript', src='/clock/app.js')
|
||||||
|
|
||||||
|
error-panel
|
||||||
|
.navbar
|
||||||
|
.navbar-inner
|
||||||
|
a.brand(href='/', target='_self') Atlantic Biomedical
|
||||||
|
progress-panel
|
||||||
|
|
||||||
|
.container-fluid
|
||||||
|
h1 Time Clock
|
||||||
|
|
||||||
|
div.loading(ng-show='working')
|
||||||
|
i.loader
|
||||||
|
br
|
||||||
|
| Detecting your location
|
||||||
|
|
||||||
|
div(ng-hide='working')
|
||||||
|
div.error(ng-show='error')
|
||||||
|
{{ error }}
|
||||||
|
|
||||||
|
div.success(ng-show='success')
|
||||||
|
{{ success }}
|
||||||
|
|
||||||
|
div(ng-hide='error || success')
|
||||||
|
.control-group
|
||||||
|
button.btn.btn-primary(ng-click='clockIn()') Clock In
|
||||||
|
button.btn.btn-primary(ng-click='clockOut()') Clock Out
|
||||||
|
div.mapOuter
|
||||||
|
gmap.mapInner(size='600x600', markers='markers', sensor='false', zoom='14')
|
@ -46,6 +46,7 @@ module.exports = function(app, auth, piler, calendar, directory, config) {
|
|||||||
app.get('/api/users/details', users.details);
|
app.get('/api/users/details', users.details);
|
||||||
app.post('/api/users', users.create);
|
app.post('/api/users', users.create);
|
||||||
app.post('/api/users/:user_id', users.update);
|
app.post('/api/users/:user_id', users.update);
|
||||||
|
app.get('/api/users/:user_id/clocks', users.clocks);
|
||||||
|
|
||||||
var account = require('../app/controllers/account');
|
var account = require('../app/controllers/account');
|
||||||
app.get('/api/account', account.profile);
|
app.get('/api/account', account.profile);
|
||||||
@ -56,6 +57,9 @@ module.exports = function(app, auth, piler, calendar, directory, config) {
|
|||||||
var tags = require('../app/controllers/tags')(piler);
|
var tags = require('../app/controllers/tags')(piler);
|
||||||
app.post('/api/tags', tags.post);
|
app.post('/api/tags', tags.post);
|
||||||
|
|
||||||
|
var clock = require('../app/controllers/clock')(piler);
|
||||||
|
app.post('/api/clock', clock.post);
|
||||||
|
|
||||||
var login = require('../app/controllers/login')(piler);
|
var login = require('../app/controllers/login')(piler);
|
||||||
app.get('/login', login.login);
|
app.get('/login', login.login);
|
||||||
app.get('/login/error', login.error);
|
app.get('/login/error', login.error);
|
||||||
@ -63,6 +67,6 @@ module.exports = function(app, auth, piler, calendar, directory, config) {
|
|||||||
|
|
||||||
var home = require('../app/controllers/home')(piler);
|
var home = require('../app/controllers/home')(piler);
|
||||||
|
|
||||||
app.get('/', tags.index, auth.requiresUiLogin, home.index);
|
app.get('/', tags.index, auth.requiresUiLogin, clock.index, home.index);
|
||||||
app.get('*', tags.index, auth.requiresUiLogin, home.index);
|
app.get('*', tags.index, auth.requiresUiLogin, clock.index, home.index);
|
||||||
};
|
};
|
||||||
|
172
public/clock/app.js
Normal file
172
public/clock/app.js
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
clock = {};
|
||||||
|
|
||||||
|
|
||||||
|
angular.module('clock', ['ngResource'])
|
||||||
|
.factory("Clock", function($resource) {
|
||||||
|
return $resource('/api/clock');
|
||||||
|
})
|
||||||
|
.constant('geolocation_msgs', {
|
||||||
|
'errors.location.unsupportedBrowser':'Browser does not support location services',
|
||||||
|
'errors.location.permissionDenied':'You have rejected access to your location',
|
||||||
|
'errors.location.positionUnavailable':'Unable to determine your location',
|
||||||
|
'errors.location.timeout':'Service timeout has been reached'
|
||||||
|
})
|
||||||
|
.factory('geolocation', ['$q','$rootScope','$window','geolocation_msgs',function ($q,$rootScope,$window,geolocation_msgs) {
|
||||||
|
return {
|
||||||
|
getLocation: function (opts) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
if ($window.navigator && $window.navigator.geolocation) {
|
||||||
|
$window.navigator.geolocation.getCurrentPosition(function(position){
|
||||||
|
$rootScope.$apply(function(){deferred.resolve(position);});
|
||||||
|
}, function(error) {
|
||||||
|
switch (error.code) {
|
||||||
|
case 1:
|
||||||
|
$rootScope.$broadcast('error',geolocation_msgs['errors.location.permissionDenied']);
|
||||||
|
$rootScope.$apply(function() {
|
||||||
|
deferred.reject(geolocation_msgs['errors.location.permissionDenied']);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
$rootScope.$broadcast('error',geolocation_msgs['errors.location.positionUnavailable']);
|
||||||
|
$rootScope.$apply(function() {
|
||||||
|
deferred.reject(geolocation_msgs['errors.location.positionUnavailable']);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
$rootScope.$broadcast('error',geolocation_msgs['errors.location.timeout']);
|
||||||
|
$rootScope.$apply(function() {
|
||||||
|
deferred.reject(geolocation_msgs['errors.location.timeout']);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}, opts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$rootScope.$broadcast('error',geolocation_msgs['errors.location.unsupportedBrowser']);
|
||||||
|
$rootScope.$apply(function(){deferred.reject(geolocation_msgs['errors.location.unsupportedBrowser']);});
|
||||||
|
}
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}])
|
||||||
|
.directive('gmap', function($parse) {
|
||||||
|
return {
|
||||||
|
template: '<img alt="Google Map">',
|
||||||
|
replace: true,
|
||||||
|
restrict: 'E',
|
||||||
|
controller: 'GMapController',
|
||||||
|
scope: true,
|
||||||
|
link: function postLink(scope, element, attrs, ctrl) {
|
||||||
|
var el = element[0];
|
||||||
|
|
||||||
|
var sizeBits = attrs.size.split('x');
|
||||||
|
el.width = parseInt(sizeBits[0], 10);
|
||||||
|
el.height = parseInt(sizeBits[1], 10);
|
||||||
|
|
||||||
|
scope.$watch(attrs.markers, function(value) {
|
||||||
|
el.src = ctrl.buildSourceString(attrs, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.controller('GMapController', function() {
|
||||||
|
var BASE_URL = '//maps.googleapis.com/maps/api/staticmap?';
|
||||||
|
var STYLE_ATTRIBUTES = ['color', 'label', 'size'];
|
||||||
|
|
||||||
|
function makeMarkerStrings(markers) {
|
||||||
|
return markers.map(function(marker) {
|
||||||
|
var str = Object.keys(marker).map(function(key) {
|
||||||
|
if (STYLE_ATTRIBUTES.indexOf(key) > -1) {
|
||||||
|
return key + ':' + marker[key] + '|';
|
||||||
|
}
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
return str + marker.coords.join(',');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.buildSourceString = function(attrs, markers) {
|
||||||
|
var markerStrings;
|
||||||
|
if (markers) {
|
||||||
|
if (!angular.isArray(markers)) {
|
||||||
|
markers = [markers];
|
||||||
|
}
|
||||||
|
markerStrings = makeMarkerStrings(markers);
|
||||||
|
}
|
||||||
|
|
||||||
|
var params = Object.keys(attrs).map(function(attr) {
|
||||||
|
if (attr === 'markers' && markerStrings) {
|
||||||
|
return Object.keys(markerStrings).map(function(key) {
|
||||||
|
return 'markers=' + encodeURIComponent(markerStrings[key]);
|
||||||
|
}).join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr[0] !== '$' && attr !== 'alt') {
|
||||||
|
return encodeURIComponent(attr) + '=' + encodeURIComponent(attrs[attr]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return BASE_URL + params.reduce(function(a, b) {
|
||||||
|
if (!a) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b !== undefined) {
|
||||||
|
return a + '&' + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}, '');
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
clock.PageCtrl = function($scope, $rootScope, geolocation, Clock) {
|
||||||
|
|
||||||
|
function save(action) {
|
||||||
|
Clock.save({
|
||||||
|
action: action,
|
||||||
|
lat: $scope.coords.latitude,
|
||||||
|
long: $scope.coords.longitude
|
||||||
|
}, function(success) {
|
||||||
|
$scope.success = 'Request was successful.';
|
||||||
|
}, function(error) {
|
||||||
|
$scope.error = 'Unable to complete request, Try again later';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.working = true;
|
||||||
|
|
||||||
|
|
||||||
|
$scope.clockIn = function() {
|
||||||
|
save('in');
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.clockOut = function() {
|
||||||
|
save('out');
|
||||||
|
};
|
||||||
|
|
||||||
|
$rootScope.$on('error', function(event, msg) {
|
||||||
|
$scope.working = false;
|
||||||
|
|
||||||
|
console.log("ERROR");
|
||||||
|
console.log(msg);
|
||||||
|
|
||||||
|
$scope.error = msg;
|
||||||
|
});
|
||||||
|
|
||||||
|
geolocation.getLocation().then(function(data) {
|
||||||
|
$scope.working = false;
|
||||||
|
|
||||||
|
$scope.coords = data.coords;
|
||||||
|
|
||||||
|
console.log('Got location Data');
|
||||||
|
console.log(data);
|
||||||
|
$scope.markers = [{
|
||||||
|
color: 'blue',
|
||||||
|
coords: [data.coords.latitude, data.coords.longitude]
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
44
public/css/clock.css
Normal file
44
public/css/clock.css
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
html, body {
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
height:100px;
|
||||||
|
width:200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapOuter {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapInner {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
padding: 5px 10px;
|
||||||
|
color: white;
|
||||||
|
background: #ba6d6d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
padding: 5px 10px;
|
||||||
|
color: white;
|
||||||
|
background: #6ebb72;
|
||||||
|
}
|
@ -78,6 +78,10 @@ angular.module('biomed', ['biomed.filters', 'biomed.services', 'biomed.directive
|
|||||||
controller: biomed.UsersIndexCtrl,
|
controller: biomed.UsersIndexCtrl,
|
||||||
reloadOnSearch: false
|
reloadOnSearch: false
|
||||||
})
|
})
|
||||||
|
.when('/admin/users/:id', {
|
||||||
|
templateUrl: '/partials/users/clock.html',
|
||||||
|
controller: biomed.UserClockCtrl
|
||||||
|
})
|
||||||
.otherwise({
|
.otherwise({
|
||||||
redirectTo: '/schedule'
|
redirectTo: '/schedule'
|
||||||
});
|
});
|
||||||
|
@ -172,6 +172,15 @@ biomed.UsersIndexCtrl = function($scope, $filter, $routeParams, $location, Users
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
biomed.UserClockCtrl = function($scope, $routeParams, Users) {
|
||||||
|
Users.index({userid: $routeParams.id}, function(result) {
|
||||||
|
console.log(result);
|
||||||
|
$scope.tech = result[0];
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.clocks = Users.clocks($routeParams);
|
||||||
|
};
|
||||||
|
|
||||||
biomed.ClientIndexCtrl = function($scope, $filter, $routeParams, Clients, LocationBinder) {
|
biomed.ClientIndexCtrl = function($scope, $filter, $routeParams, Clients, LocationBinder) {
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ angular.module('biomed.services', [])
|
|||||||
details: { method: 'GET', params: { cmd: 'details' }, isArray: true },
|
details: { method: 'GET', params: { cmd: 'details' }, isArray: true },
|
||||||
create: { method: 'POST', params: {} },
|
create: { method: 'POST', params: {} },
|
||||||
update: { method: 'POST', params: { id: 0 } },
|
update: { method: 'POST', params: { id: 0 } },
|
||||||
|
clocks: { method: 'GET', params: { id: 0, cmd: 'clocks' }, isArray: true }
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.factory("Schedule", function($resource) {
|
.factory("Schedule", function($resource) {
|
||||||
|
31
public/partials/users/clock.html
Normal file
31
public/partials/users/clock.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<ul class="breadcrumb">
|
||||||
|
<li><a href="/users"><i class="icon-briefcase"></i> Admin</a><li>
|
||||||
|
</ul>
|
||||||
|
<header>
|
||||||
|
<h1>{{tech.name.first}} {{tech.name.last}}</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12">
|
||||||
|
<table class="biomed-table" threshold="300">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Action</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-show="loading"><td colspan="11" class="table-loading"><i class="loader"></i></td></tr>
|
||||||
|
<tr ng-hide="loading || clocks.length"><td colspan="11" class="table-message">There is no information to display.</td></tr>
|
||||||
|
<tr ng-hide="loading" ng-repeat="clock in clocks">
|
||||||
|
<td>{{clock.action}}</td>
|
||||||
|
<td>{{clock.dt | date:'medium'}}</td>
|
||||||
|
<td>{{clock.lat}},{{clock.long}}</td>
|
||||||
|
<td><a href="https://www.google.com.au/maps/preview/?q={{clock.lat}},{{clock.long}}" target="_blank">View in Google Maps</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -41,7 +41,7 @@
|
|||||||
<tr ng-show="loading"><td colspan="11" class="table-loading"><i class="loader"></i></td></tr>
|
<tr ng-show="loading"><td colspan="11" class="table-loading"><i class="loader"></i></td></tr>
|
||||||
<tr ng-hide="loading || users.length"><td colspan="11" class="table-message">There is no information to display.</td></tr>
|
<tr ng-hide="loading || users.length"><td colspan="11" class="table-message">There is no information to display.</td></tr>
|
||||||
<tr ng-hide="loading" ng-repeat="user in users">
|
<tr ng-hide="loading" ng-repeat="user in users">
|
||||||
<td class="name">{{user.name.first}} {{user.name.last}} <span class="new" ng-show="isNew(user)">NEW</span></td>
|
<td class="name"><a href="/admin/users/{{user._id}}">{{user.name.first}} {{user.name.last}}</a> <span class="new" ng-show="isNew(user)">NEW</span></td>
|
||||||
<td class="email"><a href="mailto:{{user.email}}">{{user.email | email}}</a></td>
|
<td class="email"><a href="mailto:{{user.email}}">{{user.email | email}}</a></td>
|
||||||
|
|
||||||
<td class="group-start {{ checkGroup(user, 'all') }}"><a ng-click="toggleGroup(user, 'all')"><i ng-class="{ 'icon-ok': checkGroup(user, 'all'), 'icon-remove': !checkGroup(user, 'all')}"></i></a></td>
|
<td class="group-start {{ checkGroup(user, 'all') }}"><a ng-click="toggleGroup(user, 'all')"><i ng-class="{ 'icon-ok': checkGroup(user, 'all'), 'icon-remove': !checkGroup(user, 'all')}"></i></a></td>
|
||||||
|
Reference in New Issue
Block a user