zettapi_client
Version:
Client side CRUD operations in angular to use with zettapi_server rest api to get started quickly in any CMS project
1,438 lines (1,251 loc) • 287 kB
JavaScript
var app = angular.module('zapi', [
'ngSanitize',
'ngAnimate',
'ui.bootstrap',
'blockUI',
'chart.js',
'btford.socket-io',
'ngCsv',
'ngTable',
'selector',
'ngIdle',
'pascalprecht.translate',
'ngPasswordMeter'
]).config(function(TitleProvider, $locationProvider) {
TitleProvider.enabled(false);
$locationProvider.hashPrefix("");
}).provider('zapi', function(apiEntityMap) {
var map = {};
var idle = false;
var serverUrl = '',
websocketUrl;
return {
getRoutes: function(param) {
if (typeof map[param.entity] === 'undefined') return 'entity/entity.notfound.html';
if (typeof map[param.entity][param.action] === 'undefined') return 'entity/entity.notfound.html';
switch (param.action) {
case 'edit':
return 'entity/entity.edit.html';
case 'view':
if (typeof param.id === 'undefined') return 'entity/entity.notfound.html';
return 'entity/entity.view.html';
case 'list':
if (typeof param.id !== 'undefined') return 'entity/entity.notfound.html';
return 'entity/entity.list.html';
default:
return 'entity/entity.notfound.html';
}
},
setMap: function(entityMap) {
map = apiEntityMap;
for (var key in entityMap) {
map[key] = entityMap[key];
}
},
setServerUrl: function(url) {
serverUrl = url || '';
},
setWebsocket: function(url) {
websocketUrl = url || undefined;
},
setIdle: function(state) {
idle = state;
},
$get: function() {
return {
entityMap: map,
idle: idle,
serverUrl: serverUrl,
websocketUrl: websocketUrl
};
}
};
});
app.controller('entityCtrl', function($entity, zapi, $page, mySocket, $routeParams, $controller, $location, $scope, $uibModal, blockUI, NgTableParams, $translate, $license) {
//scope variables
$scope.table = { params: null };
$scope.console = null;
$scope.entities = zapi.entityMap;
$scope.entityName = $routeParams.entity;
$scope.lookup = {};
$scope.items = [];
$scope.item = {};
$scope.newFile = {};
//scope functions
$scope.add = function(item, beforeAdd, callback) {
$translate(['api.entity.sendData', $scope.entity.title, 'api.entity.newRecordSuccess', 'api.entity.editRecordSuccess']).then(function(translations) {
blockUI.start(translations['api.entity.sendData']);
var next = typeof beforeAdd === 'function' ? beforeAdd : skip;
next(function(err) {
if (err) return swal("Antes de guardar", err, "info");
$entity.add($routeParams.entity, item).then(function(response) {
if (item._id) swal("Alterado", translations[$scope.entity.title] + translations['api.entity.newRecordSuccess'], "success");
else swal("Criado", translations[$scope.entity.title] + translations['api.entity.editRecordSuccess'], "success");
if (typeof callback === 'function') callback();
}).catch(function(response) {
swal("Erro ao Guardar", response.data, "error");
if (typeof callback === 'function') callback(response.data);
}).finally(function() {
blockUI.stop();
});
});
});
};
$scope.remove = function(item) {
$translate(['api.entity.checkRemove', $scope.entity.title, 'api.entity.deleteRecordSuccess']).then(function(translations) {
blockUI.start(translations['api.entity.checkRemove']);
$entity.remove($routeParams.entity, item).then(function(response) {
swal("Removido", translations[$scope.entity.title] + translations['api.entity.deleteRecordSuccess'], "success");
}).catch(function(response) {
swal("Erro ao Remover", response.error ? response.error : response.data, "warning");
}).finally(function() {
blockUI.stop();
});
});
};
$scope.openEdit = function(item) {
if (!$scope.entity.modal) {
var url = $location.path();
url = url.substring(0, url.lastIndexOf('/')) + '/edit';
if (item) {
return $location.path(url + '/' + item._id);
} else {
return $location.path(url);
}
}
setEdit(item);
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'entity/entity.modal.html',
controller: 'entityModalCtrl',
size: 'lg',
backdrop: 'static',
scope: $scope
});
modalInstance.result.then(function(newItem) {
//item added
}, function() {
$translate('api.entity.cancelRecord').then(function(text) {
//todo
console.log(text);
});
$scope.item = {};
});
};
$scope.validate = function() {
if (typeof $scope.getError === 'function') {
var response = $scope.getError($scope.item, $scope.items);
if (response.disabled) {
$scope.console = response.tooltip;
return true;
}
}
$scope.console = null;
return false;
};
$scope.flattenArray = $entity.flattenArray;
$scope.applySearch = function(search) {
var criteria = angular.copy(search.text);
if (search.inverted) {
criteria = "!" + criteria;
}
$scope.table.params.filter({ $: criteria });
};
//main
initialize(loadFinished);
//private functions
function get(entity, id, callback) {
$translate(['api.entity.getData', 'api.entity.errorData']).then(function(translations) {
blockUI.start(translations['api.entity.getData']);
getLookups($scope.lookup, function(err, lookups) {
if (err) {
swal("Não foi possível obter os dados", translations['api.entity.errorData'], 'warning');
blockUI.stop();
return callback(err);
}
$scope.lookup = lookups;
//if user is creating a new record
if (!$routeParams.id && $routeParams.action === 'edit') {
blockUI.stop();
return callback();
}
$entity.get(entity, id).then(function(response) {
if (id) {
$scope.item = response.data;
} else {
$scope.items = response.data;
$scope.table.params = new NgTableParams({}, { dataset: $scope.items });
}
}).catch(function(response) {
swal("Não foi possível obter os dados", translations['api.entity.errorData'], 'warning');
}).finally(function() {
blockUI.stop();
callback();
});
});
});
}
function getLookups(lookup, callback) {
if (lookup) {
if (lookup.length) return callback(null, lookup);
}
$entity.getLookups($routeParams.entity, function(err, data) {
if (err) return callback(err);
callback(null, data);
});
}
function setEdit(item) {
if (item) {
$scope.item = angular.copy(item);
} else {
$scope.item = typeof $scope.blank === 'function' ? $scope.blank() : {};
}
}
function loadFinished() {
//ignore if notfound
if (!$routeParams.entity) return;
//inject child controller
try {
$controller($routeParams.entity + 'Ctrl', { $scope: $scope });
} catch (err) {
console.log(err);
}
var websocket;
if (typeof zapi.entityMap[$routeParams.entity].websocket === 'undefined') {
websocket = $routeParams.entity;
} else {
websocket = eval(zapi.entityMap[$routeParams.entity].websocket) + "." + $routeParams.entity;
}
mySocket.on(websocket + '.remove', onThisEntityRemove);
mySocket.on(websocket + '.new', onThisEntityAdd);
mySocket.on(websocket + '.edit', onThisEntityEdit);
}
function onThisEntityAdd(data) {
console.log('io.on', 'add', data);
switch ($routeParams.action) {
case 'list':
$scope.items.unshift(data);
$scope.table.params.total($scope.items.length);
$scope.table.params.reload();
break;
}
//todo update lookup
}
function onThisEntityEdit(data) {
console.log('io.on', 'edit', data);
switch ($routeParams.action) {
case 'list':
for (var i = 0; i < $scope.items.length; i++) {
if ($scope.items[i]._id === data._id) {
$scope.items[i] = data;
$scope.table.params.reload();
break;
}
}
break;
case 'view':
case 'edit':
if ($scope.item._id === data._id) {
$scope.item = data;
}
break;
}
//todo update lookup
}
function onThisEntityRemove(data) {
console.log('io.on', 'remove', data);
switch ($routeParams.action) {
case 'list':
for (var i = 0; i < $scope.items.length; i++) {
if ($scope.items[i]._id === data) {
$scope.items.splice(i, 1);
$scope.table.params.total($scope.items.length);
$scope.table.params.reload();
break;
}
}
break;
case 'view':
case 'edit':
if ($scope.item._id === data._id) {
swal("Outro utilizador apagou esta página", "Iremos redireciona-lo para a lista actualizada de " + $scope.entity.title, "info");
$location.path('/' + $routeParams.entity + '/list');
}
break;
}
//todo update lookup
}
//initialization
function initialize(callback) {
$scope.entity = zapi.entityMap[$routeParams.entity];
var words = ['api.entity.whereyougo', 'api.entity.newRecord', 'api.entity.editRecord', 'api.entity.viewRecord'];
if ($scope.entity) words.push($scope.entity.title);
$translate(words).then(function(translations) {
$page.setTitle(translations['api.entity.whereyougo']);
if (!$scope.entity) return;
if (typeof $scope.entity.license !== 'undefined') {
var isAllowed = $license.isLicensed($scope.entity.license);
if (!isAllowed) return $license.notify($scope.entity.license);
}
switch ($routeParams.action) {
case 'edit':
if (!$routeParams.id) {
$page.setTitle(translations[$scope.entity.title] + "-" + translations['api.entity.newRecord']);
get($routeParams.entity, null, callback);
} else {
$page.setTitle(translations[$scope.entity.title] + "-" + translations['api.entity.editRecord']);
get($routeParams.entity, $routeParams.id, callback);
}
break;
case 'view':
if (!$routeParams.id) return;
$page.setTitle(translations[$scope.entity.title] + "-" + translations['api.entity.viewRecord']);
get($routeParams.entity, $routeParams.id, callback);
break;
case 'list':
if ($routeParams.id) return;
$page.setTitle(translations[$scope.entity.title]);
get($routeParams.entity, null, callback);
break;
default:
return;
}
});
}
function skip(callback) {
callback();
}
});
app.controller('entityModalCtrl', function ($uibModalInstance, $scope) {
$scope.ok = function () {
$scope.add($scope.item, $scope.onBeforeSave, function (err) {
if (!err) $scope.$close($scope.item);
});
};
$scope.cancel = function () {
$scope.$dismiss('cancel');
};
});
app.filter("dateFilter", function () {
return function (items, key, from, to) {
if (typeof items === 'undefined') return;
if (!(items instanceof Array)) return;
from = typeof from === 'undefined' ? new Date('1999-01-01') : new Date(from);
to = typeof to === 'undefined' ? new Date() : new Date(to);
var result = [];
items.forEach(function (item) {
var value = new Date(item[key]);
if (value >= from && value <= to) result.push(item);
});
return result;
};
});
app.filter('makePositive', function () {
return function (num) {
if (typeof num === 'undefined') return;
return Math.abs(num);
};
});
app.filter('orderObjectBy', function () {
return function (items, field, reverse) {
var filtered = [];
angular.forEach(items, function (item) {
filtered.push(item);
});
filtered.sort(function (a, b) {
return (a[field] > b[field] ? 1 : -1);
});
if (reverse) filtered.reverse();
return filtered;
};
});
app.service('$address', function($http, blockUI, zapi) {
this.getAddressPT = function(zipcode, callback) {
if (this.validateZipcode(zipcode)) return callback("Código postal inválido");
blockUI.start('A procurar arruamento...');
$http.get(zapi.serverUrl + "/api/address/pt/" + zipcode).then(function(response) {
callback(null, response.data);
}).catch(function(response) {
callback(response);
}).finally(function() {
blockUI.stop();
});
};
this.validateZipcode = function(zipcode) {
if (!zipcode) return true;
if (typeof zipcode !== 'string') zipcode = zipcode + '';
var cps = zipcode.split('-');
if (cps.length < 1 || cps.length > 2) return true;
if (isNaN(cps[0])) return true;
return cps.length > 1 && isNaN(cps[1]);
};
this.getCoordinates = function(zipcode, callback) {
try {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({ 'address': zipcode }, function(results, status) {
if (status !== google.maps.GeocoderStatus.OK) return callback(status);
callback(null, {
lat: results[0].geometry.location.lat(),
lng: results[0].geometry.location.lng()
});
});
} catch (error) {
callback(error);
}
};
});
app.factory('$auth', function($http, $crypto, blockUI, $location, anonymousPages, customPages, routeDepth, $rootScope, Idle, zapi, $translate) {
function getUrlPaths(urlPath) {
var parts = urlPath.split('/');
var output = [];
parts.forEach(function(part) {
if (!part) return;
output.push(part);
});
return output;
}
var service = {
currentUser: null,
login: function(username, password, callback) {
$translate('api.services.auth.loginLoad', function(text) {
blockUI.start(text);
}, function(translationId) {
blockUI.start(translationId);
});
return $http.post(zapi.serverUrl + '/api/session/login/', {
username: username,
password: $crypto.isMd5(password) ? password : $crypto.md5(password)
}).then(function(response) {
if (zapi.idle) Idle.watch();
service.currentUser = response.data.user;
callback();
}).catch(function(response) {
$translate(['api.services.auth.loginErrorTitle', 'api.services.auth.loginErrorContent']).then(function(translations) {
swal(translations['api.services.auth.loginErrorTitle'], translations['api.services.auth.loginErrorContent'], "error");
//swal(loginErrorTitle, response.data, "danger");
}, function(translationsId) {
swal(translationsId.api_service_auth_loginerrortitle, translationsId.api_service_auth_loginerrorcontent, "error");
});
callback(true);
}).finally(function() {
blockUI.stop();
});
},
logout: function() {
$http.get(zapi.serverUrl + '/api/session/logout').then(function(response) {
if (zapi.idle) Idle.unwatch();
service.currentUser = null;
$rootScope.login = {};
$location.path('/');
});
},
requestCurrentUser: function(callback) {
if (service.isAuthenticated()) return callback(null, service.currentUser);
$http.get(zapi.serverUrl + '/api/session/currentuser').then(function(response) {
service.currentUser = response.data.user;
callback(null, service.currentUser);
}).catch(function(response) {
service.currentUser = null;
callback(response);
});
},
isAuthenticated: function() {
return !!service.currentUser;
},
activateAccount: function(rawCode, callback) {
if (!rawCode) return callback(true);
var codes = rawCode.split('&');
if (codes.length !== 2) return callback(true);
$translate('api.services.auth.activateAccountLoad', function(text) {
blockUI.start(text);
}, function(translationId) {
blockUI.start(translationId);
});
$http.post(zapi.serverUrl + '/api/user/activate/', {
email: codes[0],
code: codes[1]
}).then(function(response) {
callback(null, response.data);
}).catch(function(response) {
$translate(['api.services.auth.activateAccountErrorTitle', 'api.services.auth.activateAccountErrorContent']).then(function(translations) {
swal({
title: translations['api.services.auth.activateAccountErrorTitle'],
text: translations['api.services.auth.activateAccountErrorContent'],
type: "info",
confirmButtonText: "OK"
});
}, function(translationsId) {
swal({
title: translationsId.api_service_auth_activateaccounterrortitle,
text: translationsId.api_service_auth_activateaccounterrorcontent,
type: "info",
confirmButtonText: "OK"
});
});
callback(true);
}).finally(function() {
blockUI.stop();
});
},
resetPassword: function(email, username, callback) {
$translate('api.services.auth.resetPasswordLoad', function(text) {
blockUI.start(text);
}, function(translationId) {
blockUI.start(translationId);
});
return $http.post(zapi.serverUrl + '/api/user/resetpassword/', {
email: email,
username: username
}).then(function(response) {
$translate(['api.services.auth.resetPasswordSuccessTitle', 'api.services.auth.resetPasswordSuccessContent']).then(function(translations) {
swal(translations['api.services.auth.resetPasswordSuccessTitle'], translations['api.services.auth.resetPasswordSuccessContent'], "success");
}, function(translationsId) {
swal(translationsId.api_service_auth_resetpasswordsuccesstitle, translationsId.api_service_auth_resetpasswordsuccesscontent, "success");
});
callback();
}).catch(function(response) {
$translate(['api.services.auth.resetPasswordErrorTitle', 'api.services.auth.resetPasswordErrorContent']).then(function(translations) {
swal(translations['api.services.auth.resetPasswordErrorTitle'], translations['api.services.auth.resetPasswordErrorContent'], "error");
}, function(translationsId) {
swal(translationsId.api_service_auth_resetpassworderrortitle, translationsId.api_service_auth_resetpassworderrorcontent, "error");
});
callback(true);
}).finally(function() {
blockUI.stop();
});
},
changePassword: function(user, newPassword1, newPassword2, callback) {
if (!newPassword1) return;
if (newPassword1 !== newPassword2) {
$translate(['api.services.auth.changepasswordWrongPasswordTitle', 'api.services.auth.changepasswordWrongPasswordContent']).then(function(translations) {
swal(translations['api.services.auth.changepasswordWrongPasswordTitle'], translations['api.services.auth.changepasswordWrongPasswordContent'], "error");
}, function(translationsId) {
swal(translationsId.api_service_auth_changepasswordwrongpasswordtitle, translationsId.api_service_auth_changepasswordwrongpasswordcontent, "error");
});
return;
}
user.newPassword = $crypto.md5(newPassword1);
$translate('api.services.auth.changepasswordLoad', function(text) {
blockUI.start(text);
}, function(translationId) {
blockUI.start(translationId);
});
$http.post(zapi.serverUrl + '/api/user/changepassword/', user).then(function(response) {
$translate(['api.services.auth.changepasswordSuccessTitle', 'api.services.auth.changepasswordSuccessContent', 'api.services.auth.changepasswordSuccessBtnOk']).then(function(translations) {
swal({
title: translations['api.services.auth.changepasswordSuccessTitle'],
text: translations['api.services.auth.changepasswordSuccessContent'],
type: "info",
confirmButtonText: translations['api.services.auth.changepasswordSuccessBtnOk']
});
}, function(translationsId) {
swal({
title: translationsId.api_service_auth_changepasswordsuccesstitle,
text: translationsId.api_service_auth_changepasswordsuccesscontent,
type: "info",
confirmButtonText: translationsId.api_service_auth_changepasswordsuccessbtnok
});
});
callback();
}).catch(function(response) {
$translate(['api.services.auth.changepasswordErrorTitle', 'api.services.auth.changepasswordErrorContent']).then(function(translations) {
swal(translations['api.services.auth.changepasswordErrorTitle'], translations['api.services.auth.changepasswordErrorContent'], "error");
}, function(translationsId) {
swal(translationsId.api_service_auth_changepassworderrortitle, translationsId.api_service_auth_changepassworderrorcontent, "error");
});
callback(true);
}).finally(function() {
blockUI.stop();
});
},
isPageAnonymous: function() {
var urlPaths = getUrlPaths($location.path());
if (!(urlPaths instanceof Array)) return false;
if (urlPaths.length === 0) return true;
return anonymousPages.some(function(anonymousPage) {
return anonymousPage === urlPaths[0];
});
},
isPageCustom: function() {
var urlPaths = getUrlPaths($location.path());
if (!(urlPaths instanceof Array)) return false;
if (urlPaths.length === 0) return false;
return customPages.some(function(customPage) {
if (customPage.length < urlPaths.length) return false;
return !customPage.some(function(part, i) {
//ignore url wildcards by configuring the custom page with %
if (part === '%') return false;
return part !== urlPaths[i];
});
});
},
getNextRoute: function(callback) {
return function(event, next, current) {
var shortURL = next.substring(next.indexOf('/#/') + 3);
var urlPaths = getUrlPaths(shortURL);
if (service.isPageAnonymous()) return callback();
service.currentUser = null;
service.requestCurrentUser(function(err, user) {
$rootScope.login = (err ? {} : user) || {};
if (!$rootScope.login._id) return callback("Sem sessão iniciada. Isto pode ocorrer por motivos de inactividade, aceder à mesma conta noutro computador ou actualização recente ao servidor.", user);
if (urlPaths[0] === 'profile') return callback(null, user);
//Entity/Custom Pages
var isCustom = service.isPageCustom();
if (isCustom) return callback(null, user);
var entity = zapi.entityMap[urlPaths[routeDepth]];
if (!entity) return callback("A página que está a tentar consultar não existe", user);
if (urlPaths.length <= routeDepth + 1) return callback("A página que está a tentar consultar não existe", user);
var action = entity[urlPaths[routeDepth + 1]];
if (!action) return callback("A página que está a tentar consultar não existe", user);
if (user.role.admin) return callback(null, user);
if (action.admin) return callback("A página que está a tentar consultar não existe", user);
callback(null, user);
});
};
},
isAnonymous: function() {
return !service.isLoggedIn();
},
isLoggedIn: function() {
if (!service.currentUser) return false;
return !!service.currentUser._id;
},
isAdmin: function() {
if (service.isLoggedIn()) return service.currentUser.role.admin;
return false;
}
};
return service;
});
app.service('$calendar', function(moment) {
var eventTypes = {};
this.addEventType = function(key, label, promise) {
if (typeof promise !== 'object') return console.log('promise of unexpected type for eventType ' + key);
if (typeof promise.then !== 'function') return console.log('promise of unexpected type for eventType ' + key);
if (!eventTypes[key]) eventTypes[key] = {};
eventTypes[key] = {
label: label,
promise: promise,
visible: true,
data: []
};
promise.then(function(items) {
items.forEach(function(item) {
item.type = key;
});
eventTypes[key].data = items;
}).catch(function(response) {
console.log(response);
});
};
this.getEventTypes = function() {
var items = [];
for (var key in eventTypes) {
items.push({
type: key,
label: eventTypes[key].label,
visible: eventTypes[key].visible,
count: eventTypes[key].data.length
});
}
return items;
};
this.getEvents = function() {
var items = [];
for (var key in eventTypes) {
if (!eventTypes[key].visible) continue;
items = items.concat(eventTypes[key].data);
}
return items;
};
this.toggleEventType = function(key) {
if (!eventTypes[key]) return console.log(key, eventTypes);
eventTypes[key].visible = !eventTypes[key].visible;
console.log(eventTypes);
return eventTypes;
};
this.newEvent = function(title, start, end) {
if (typeof title === 'undefined') console.log('invalid title for event', title);
if (typeof start === 'undefined') console.log('invalid start for event', start);
_start = moment(start);
if (!_start.isValid()) console.log('invalid date start for event', start);
if (end) {
_end = moment(end);
if (!_end.isValid()) console.log('invalid date end for event', end);
}
var event = {
title: title,
startsAt: new Date(start),
draggable: false,
resizable: false,
incrementsBadgeTotal: true,
allDay: true
};
if (end) event.endsAt = new Date(end);
return event;
};
});
app.constant('zapiPath', 'node_modules/zettapi_client/lib/');
app.constant('chartTypes', [
['bar', 'doughnut', 'pie', 'horizontalBar'],
['line', 'radar'],
['bubble', 'polar-area']
]);
app.constant('graphOptions', {
responsive: true,
responsiveAnimationDuration: 1500,
tooltip: { enabled: true },
elements: {
line: { tension: 0.4, stepped: false }
}
});
app.constant('apiEntityMap', {
activity: {
title: "api.pages.activity.title",
list: { admin: true }
},
alert: {
title: "api.pages.alert.title",
list: { admin: true },
edit: { admin: true },
modal: true
},
country: {
title: "Países",
list: { admin: true }
},
error: {
title: "api.pages.error.title",
list: { admin: true }
},
holiday: {
title: "Feriados",
lookup: ['country'],
list: { admin: true },
edit: { admin: true },
modal: true
},
maintenance: {
title: "Agendamento de Manutenção",
list: { admin: true },
edit: { admin: true },
modal: true
},
message: {
title: "api.pages.message.title",
list: { admin: true }
},
role: {
title: "api.pages.role.title",
list: { admin: true },
edit: { admin: true },
modal: true
},
task: {
title: "api.pages.task.title",
list: { admin: true },
edit: { admin: true },
modal: true
},
user: {
title: "api.pages.user.title",
lookup: ['role'],
list: { admin: false },
edit: { admin: false },
modal: true
}
});
app.service('$crypto', function() {
function md5cycle(x, k) {
var a = x[0],
b = x[1],
c = x[2],
d = x[3];
a = ff(a, b, c, d, k[0], 7, -680876936);
d = ff(d, a, b, c, k[1], 12, -389564586);
c = ff(c, d, a, b, k[2], 17, 606105819);
b = ff(b, c, d, a, k[3], 22, -1044525330);
a = ff(a, b, c, d, k[4], 7, -176418897);
d = ff(d, a, b, c, k[5], 12, 1200080426);
c = ff(c, d, a, b, k[6], 17, -1473231341);
b = ff(b, c, d, a, k[7], 22, -45705983);
a = ff(a, b, c, d, k[8], 7, 1770035416);
d = ff(d, a, b, c, k[9], 12, -1958414417);
c = ff(c, d, a, b, k[10], 17, -42063);
b = ff(b, c, d, a, k[11], 22, -1990404162);
a = ff(a, b, c, d, k[12], 7, 1804603682);
d = ff(d, a, b, c, k[13], 12, -40341101);
c = ff(c, d, a, b, k[14], 17, -1502002290);
b = ff(b, c, d, a, k[15], 22, 1236535329);
a = gg(a, b, c, d, k[1], 5, -165796510);
d = gg(d, a, b, c, k[6], 9, -1069501632);
c = gg(c, d, a, b, k[11], 14, 643717713);
b = gg(b, c, d, a, k[0], 20, -373897302);
a = gg(a, b, c, d, k[5], 5, -701558691);
d = gg(d, a, b, c, k[10], 9, 38016083);
c = gg(c, d, a, b, k[15], 14, -660478335);
b = gg(b, c, d, a, k[4], 20, -405537848);
a = gg(a, b, c, d, k[9], 5, 568446438);
d = gg(d, a, b, c, k[14], 9, -1019803690);
c = gg(c, d, a, b, k[3], 14, -187363961);
b = gg(b, c, d, a, k[8], 20, 1163531501);
a = gg(a, b, c, d, k[13], 5, -1444681467);
d = gg(d, a, b, c, k[2], 9, -51403784);
c = gg(c, d, a, b, k[7], 14, 1735328473);
b = gg(b, c, d, a, k[12], 20, -1926607734);
a = hh(a, b, c, d, k[5], 4, -378558);
d = hh(d, a, b, c, k[8], 11, -2022574463);
c = hh(c, d, a, b, k[11], 16, 1839030562);
b = hh(b, c, d, a, k[14], 23, -35309556);
a = hh(a, b, c, d, k[1], 4, -1530992060);
d = hh(d, a, b, c, k[4], 11, 1272893353);
c = hh(c, d, a, b, k[7], 16, -155497632);
b = hh(b, c, d, a, k[10], 23, -1094730640);
a = hh(a, b, c, d, k[13], 4, 681279174);
d = hh(d, a, b, c, k[0], 11, -358537222);
c = hh(c, d, a, b, k[3], 16, -722521979);
b = hh(b, c, d, a, k[6], 23, 76029189);
a = hh(a, b, c, d, k[9], 4, -640364487);
d = hh(d, a, b, c, k[12], 11, -421815835);
c = hh(c, d, a, b, k[15], 16, 530742520);
b = hh(b, c, d, a, k[2], 23, -995338651);
a = ii(a, b, c, d, k[0], 6, -198630844);
d = ii(d, a, b, c, k[7], 10, 1126891415);
c = ii(c, d, a, b, k[14], 15, -1416354905);
b = ii(b, c, d, a, k[5], 21, -57434055);
a = ii(a, b, c, d, k[12], 6, 1700485571);
d = ii(d, a, b, c, k[3], 10, -1894986606);
c = ii(c, d, a, b, k[10], 15, -1051523);
b = ii(b, c, d, a, k[1], 21, -2054922799);
a = ii(a, b, c, d, k[8], 6, 1873313359);
d = ii(d, a, b, c, k[15], 10, -30611744);
c = ii(c, d, a, b, k[6], 15, -1560198380);
b = ii(b, c, d, a, k[13], 21, 1309151649);
a = ii(a, b, c, d, k[4], 6, -145523070);
d = ii(d, a, b, c, k[11], 10, -1120210379);
c = ii(c, d, a, b, k[2], 15, 718787259);
b = ii(b, c, d, a, k[9], 21, -343485551);
x[0] = add32(a, x[0]);
x[1] = add32(b, x[1]);
x[2] = add32(c, x[2]);
x[3] = add32(d, x[3]);
}
function cmn(q, a, b, x, s, t) {
a = add32(add32(a, q), add32(x, t));
return add32((a << s) | (a >>> (32 - s)), b);
}
function ff(a, b, c, d, x, s, t) {
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function gg(a, b, c, d, x, s, t) {
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function hh(a, b, c, d, x, s, t) {
return cmn(b ^ c ^ d, a, b, x, s, t);
}
function ii(a, b, c, d, x, s, t) {
return cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function md51(s) {
txt = '';
var n = s.length,
state = [1732584193, -271733879, -1732584194, 271733878],
i;
for (i = 64; i <= s.length; i += 64) {
md5cycle(state, md5blk(s.substring(i - 64, i)));
}
s = s.substring(i - 64);
var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for (i = 0; i < s.length; i++)
tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
if (i > 55) {
md5cycle(state, tail);
for (i = 0; i < 16; i++) tail[i] = 0;
}
tail[14] = n * 8;
md5cycle(state, tail);
return state;
}
/* there needs to be support for Unicode here,
* unless we pretend that we can redefine the MD-5
* algorithm for multi-byte characters (perhaps
* by adding every four 16-bit characters and
* shortening the sum to 32 bits). Otherwise
* I suggest performing MD-5 as if every character
* was two bytes--e.g., 0040 0025 = @%--but then
* how will an ordinary MD-5 sum be matched?
* There is no way to standardize text to something
* like UTF-8 before transformation; speed cost is
* utterly prohibitive. The JavaScript standard
* itself needs to look at this: it should start
* providing access to strings as preformed UTF-8
* 8-bit unsigned value arrays.
*/
function md5blk(s) { /* I figured global was faster. */
var md5blks = [],
i; /* Andy King said do it this way. */
for (i = 0; i < 64; i += 4) {
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
}
return md5blks;
}
var hex_chr = '0123456789abcdef'.split('');
function rhex(n) {
var s = '',
j = 0;
for (; j < 4; j++)
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
return s;
}
function hex(x) {
for (var i = 0; i < x.length; i++)
x[i] = rhex(x[i]);
return x.join('');
}
this.md5 = function(s) {
return hex(md51(s));
};
this.isMd5 = function(s) {
return /^[a-fA-F0-9]{32}$/.test(s);
};
/* this function is much faster,
so if possible we use it. Some IEs
are the only ones I know of that
need the idiotic second function,
generated by an if clause. */
var add32 = function(a, b) {
return (a + b) & 0xFFFFFFFF;
};
if (this.md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
add32 = function(x, y) {
var lsw = (x & 0xFFFF) + (y & 0xFFFF),
msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
};
}
});
app.factory('$date', function (moment) {
var factory = {};
factory.collisionDetection = function (start, end, events) {
start = moment(start).format('YYYY-MM-DD');
end = end ? moment(end).format('YYYY-MM-DD') : start;
if (end < start) {
return null;
}
for (var i = 0; i < events.length; i++) {
/*
if (events[i].approval) {
if (events[i].approval.cancelled) {
continue;
}
if (events[i].approval.level < events[i].approval.maxLevel) {
continue;
}
}
*/
var eventStart = moment(events[i].dateStart).format('YYYY-MM-DD');
var eventEnd = eventStart;
if (events[i].dateEnd) {
eventEnd = moment(events[i].dateEnd).format('YYYY-MM-DD');
}
// $ |__$__|
if (eventEnd > start && eventEnd <= end) {
return true;
}
// |__$__| $
if (eventStart >= start && eventStart < end) {
return true;
}
// $ |____| $
if (eventStart <= start && eventEnd >= end) {
return true;
}
// |___$___$____|
if (eventStart >= start && eventEnd <= end) {
return true;
}
}
return false;
};
factory.extractMinutes = function (time) {
try {
return factory.pad(time.getHours()) + ':' + factory.pad(time.getMinutes());
}
catch (err) {
time = new Date(time);
return factory.pad(time.getHours()) + ':' + factory.pad(time.getMinutes());
}
};
factory.calculateTimespan = function (startTimestamp, endTimestamp) {
var end;
if (endTimestamp) {
end = moment(endTimestamp);
}
else {
end = moment();
}
var start = new Date(startTimestamp);
var duration = moment.duration(end.diff(start));
return duration.asMinutes().toFixed(2);
};
factory.totalMinutes = function (timeString) {
var HourMinutes = timeString.split(':');
if (HourMinutes.length == 1) {
HourMinutes.push(0);
}
var hours = parseInt(HourMinutes[0]);
var minutes = parseInt(HourMinutes[1]);
return hours * 60 + minutes;
};
factory.pad = function (number, count) {
var res = number + "";
count = count || 2;
while (res.length < count) {
res = "0" + res;
}
return res;
};
factory.getTotalMinutes = function (time) {
var HourMinutes = time.split(':');
if (HourMinutes.length === 0 || HourMinutes.length > 2) {
return null;
}
if (HourMinutes.length == 1) {
HourMinutes.push(0);
}
var hours = parseInt(HourMinutes[0]);
if (hours < 0 || hours > 23) {
return null;
}
var minutes = parseInt(HourMinutes[1]);
if (minutes < 0 || minutes > 59) {
return null;
}
return hours * 60 + minutes;
};
factory.getWeekNumber = function (d) {
// Copy date so don't modify original
d = new Date(+d);
d.setHours(0, 0, 0);
// Set to nearest Thursday: current date + 4 - current day number
// Make Sunday's day number 7
d.setDate(d.getDate() + 4 - (d.getDay() || 7));
// Get first day of year
var yearStart = new Date(d.getFullYear(), 0, 1);
// Calculate full weeks to nearest Thursday
var weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
// Return array of year and week number
return [d.getFullYear(), weekNo];
};
factory.weeksInYear = function (year) {
var month = 11, day = 31, week;
// Find week that 31 Dec is in. If is first week, reduce date until
// get previous week.
do {
d = new Date(year, month, day--);
week = factory.getWeekNumber(d)[1];
} while (week == 1);
return week;
};
factory.getDateOfISOWeek = function (w, y) {
var simple = new Date(y, 0, 1 + (w - 1) * 7);
var dow = simple.getDay();
var ISOweekStart = simple;
if (dow <= 4)
ISOweekStart.setDate(simple.getDate() - simple.getDay() + 1);
else
ISOweekStart.setDate(simple.getDate() + 8 - simple.getDay());
return ISOweekStart;
};
return factory;
});
app.service('$entity', function($http, $q, blockUI, $auth, zapi) {
var svc = this;
this.get = function(entity, id) {
if (id) return $http.get(zapi.serverUrl + '/api/' + entity + '/list/' + id);
return $http.get(zapi.serverUrl + '/api/' + entity + '/list');
};
this.getByKey = function(collection, keyValuePair, callback, transform) {
var url = zapi.serverUrl + '/api/' + collection + '/fetch';
var httpOptions = { params: keyValuePair };
if (typeof transform === 'function') httpOptions.transformResponse = transform;
if (typeof callback !== 'function') return $http.get(url, httpOptions);
$http.get(url, httpOptions).then(function(response) {
callback(null, response);
}).catch(function(response) {
callback(response);
});
};
this.setFormFiles = function(fd, item, parent) {
//ignore if current object has nothing or is a string
if (!item || typeof item === 'string') return;
//array
if (item.length) {
for (var i = 0; i < item.length; i++) {
svc.setFormFiles(fd, item[i], parent + '[' + i + ']');
}
}
//not array
else {
//for each nested object
for (var property in item) {
if (typeof item[property] !== 'object') continue;
//file object
if (property === 'newFile') {
for (var file in item[property]) {
var filePath = parent ? parent + '.' + file : file;
fd.append(filePath, item[property][file]);
}
}
//non file object
else {
svc.setFormFiles(fd, item[property], parent ? parent + '.' + property : property);
}
}
}
};
this.add = function(entity, item) {
var url = '/api/' + entity + '/add/';
if (item._id) url += item._id;
var fd = new FormData();
if (entity !== 'message') {
svc.setFormFiles(fd, item);
}
fd.append('item', angular.toJson(item));
return $http.post(zapi.serverUrl + url, fd, { transformRequest: angular.identity, headers: { 'Content-Type': undefined } });
};
this.update = function(entity, id, fieldsToSet) {
return $http.post(zapi.serverUrl + "/api/" + entity + "/update/" + id, fieldsToSet);
};
this.getLookups = function(entity, callback) {
if (!zapi.entityMap[entity].lookup) return callback();
if (zapi.entityMap[entity].lookup.length === 0) return callback();
var lookups = [];
for (var i = 0; i < zapi.entityMap[entity].lookup.length; i++) {
var lookup = zapi.entityMap[entity].lookup[i];
lookups.push(svc.get(lookup));
}
$q.all(lookups).then(function(response) {
var data = {};
for (var i = 0; i < response.length; i++) {
data[zapi.entityMap[entity].lookup[i]] = response[i].data;
}
callback(null, data);
}, function(response) {
callback(response);
});
};
this.getMany = function(entities, callback) {
var lookups = entities,
promises = [];
lookups.forEach(function(lookup) {
promises.push(svc.get(lookup));
});
var response = {};
$q.all(promises).then(function(results) {
var data = {};
results.forEach(function(result, i) {
response[lookups[i]] = result.data;
});
callback(null, response);
}, function(err) {
callback(err);
});
};
this.validate = function(entity, object, dataset) {
if (typeof zapi.entityMap[entity].service.validate !== 'function') return false;
return zapi.entityMap[entity].service.validate(object, dataset);
};
this.remove = function(entity, item) {
var id = "_id";
if (typeof zapi.entityMap[entity].id !== 'undefined') id = zapi.entityMap[entity].id;
var url = zapi.serverUrl + '/api/' + entity + '/remove/' + item[id];
return $http.get(url);
};
this.blank = function(entity) {
if (typeof zapi.entityMap[entity].service.blank !== 'function') return {};
return zapi.entityMap[entity].service.blank();
};
this.flattenArray = function(items, json) {
var table = [],
keys = [],
key, data = [];
items.forEach(function(item) {
var row = flatten(item);
for (key in row) {
if (keys.indexOf(key) !== -1) continue;
keys.push(key);
}
table.push(row);
});
if (!json) data.push(keys);
table.forEach(function(row) {
var datum;
if (json) {
datum = row;
} else {
datum = [];
keys.forEach(function(key) {
if (typeof row[key] === 'undefined') datum.push("");
else datum.push(row[key]);
});
}
data.push(datum);
});
return data;
};
function flatten(data) {
var result = {};
function recurse(cur, prop) {
if (Object(cur) !== cur) {
result[prop] = cur;
} else if (Array.isArray(cur)) {
for (var i = 0, l = cur.length; i < l; i++)
recurse(cur[i], prop + "[" + i + "]");
if (l === 0)
result[prop] = [];
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop + "." + p : p);
}
if (isEmpty && prop)
result[prop] = {};
}
}
recurse(data, "");
return result;
}
});
app.service('ErrorSvc', function() {
this.validationArgs = function(disabled, tooltip) {
return {
disabled: disabled,
tooltip: tooltip
};
};
});
app.service('$graph', function($http, graphOptions, zapi) {
this.get = function(namespace, collection, query, obj, seriesKey, dataKey, labelsKey, callback, driver) {
var params = {
query: query,
obj: obj,
seriesKey: seriesKey,
dataKey: dataKey,
labelsKey: labelsKey
};
if (typeof driver === 'undefined') driver = 'mongo';
$http.post(zapi.serverUrl + '/api/graph/auto/' + namespace + '/' + collection + '/' + driver, params).then(function(response) {
response.data.options = angular.copy(graphOptions);
if (response.data.series.length > 0) response.data.options.legend = { display: true };
callback(response.data);
}).catch(function(response) {
swal("Atenção", response.data, "warning");
callback();
});
};
this.custom = function(namespace, graph, callback) {
var driver = namespace === 'sql' ? 'sql' : 'mongo';
$http.get(zapi.serverUrl + '/api/graph/custom/' + namespace + '/' + gra