UNPKG

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
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