Services and Factories¶
The Stratpoint Timesheet Application uses AngularJS services and factories defined directly on the main StratpointTSApp module. All services are implemented in /public/app/js/mine/services.js. This section details the actual service implementation and key services.
Service Architecture¶
All Services Defined on Main Module¶
// All services/factories are defined directly on StratpointTSApp in /public/app/js/mine/services.js
StratpointTSApp
.factory('ServiceName', ['dependency1', 'dependency2', function(dependency1, dependency2) {
// Implementation
}])
HTTP Interceptors¶
Response Interceptor¶
Handles authentication token refresh and error responses.
// From /public/app/js/mine/services.js
StratpointTSApp
.factory('responseInterceptors', ["$rootScope", "$location", "$q", "$window", "$cookieStore", "Flash", "indexedDBDataSvc", "Authenticate", "ActiveForm", function ($rootScope, $location, $q, $window, $cookieStore, Flash, indexedDBDataSvc, Authenticate, ActiveForm) {
var clearSession = function (){
Authenticate.customClearLocalStorage();
$cookieStore.remove('timesheet.user');
$cookieStore.remove('timesheet.permissions');
$rootScope.loggedPermissionList = [];
$rootScope.$broadcast('permissionsChanged');
delete $rootScope.navItems;
delete $rootScope.currentUser;
delete $rootScope.currentToken;
};
var checkNewAuth = function(response){
if(response.headers("content-type") == 'application/json'){
if(typeof response.data.body.newAuth != 'undefined'){
var newAuthData = response.data.body.newAuth;
$rootScope.userId = newAuthData.user.id;
var perms = newAuthData.user.permission_ids.split(',');
Authenticate.setUser(newAuthData, true);
Authenticate.setPermissions(perms, true);
}
}
}
return {
response: function(response){
checkNewAuth(response);
return response;
},
responseError: function(response){
checkNewAuth(response);
if(response.status == 429) { // too many request
Flash.show(response.data.message, 'error');
} else if(response.status == 503) {
$window.location.reload();
} else if(response.status == 504) { // cloudfront timeout
Flash.show("Server Timeout error was encountered. Please report to timesheet@stratpoint.com");
} else if (response.status == 403 || response.status == 401 || response.status == 406) {
if(response.status == 401){
Flash.show("Authentication error was encountered. You will be redirected to the login page.", 'error', 3000);
} else if (response.status == 403){
Flash.show("Access not allowed", 'error');
} else if (response.status == 406){
Flash.show("Invalid request", 'error');
}
clearSession();
$location.path('/login');
}
return $q.reject(response);
}
};
}])
Request Interceptor¶
Adds authentication headers to outgoing requests.
// From /public/app/js/mine/services.js
StratpointTSApp
.factory('requestInterceptors', ["$rootScope", "$window", function ($rootScope, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
// Add authentication token if available
if ($rootScope.currentToken) {
config.headers.Authorization = 'Bearer ' + $rootScope.currentToken;
}
return config;
}
};
}])
Authentication Services¶
Authenticate Service¶
Core authentication service handling user login, logout, and permission management.
// From /public/app/js/mine/services.js
StratpointTSApp
.factory('Authenticate', ['$cookieStore', '$rootScope', '$location', '$q', 'Flash', 'BASE_URL', 'ActiveForm', function($cookieStore, $rootScope, $location, $q, Flash, BASE_URL, ActiveForm){
return {
setUser: function(userData, remember) {
if (remember) {
localStorage['timesheet.user'] = JSON.stringify(userData);
} else {
$cookieStore.put('timesheet.user', userData);
}
$rootScope.currentUser = userData.user;
$rootScope.currentToken = userData.access_token;
$rootScope.userId = userData.user.id;
},
getUser: function() {
var user = localStorage['timesheet.user'] || $cookieStore.get('timesheet.user');
return user ? (typeof user === 'string' ? JSON.parse(user) : user) : null;
},
hasPermission: function(permissionId) {
var permissions = $rootScope.loggedPermissionList || [];
return permissions.indexOf(permissionId.toString()) !== -1;
},
setPermissions: function(permissions, remember) {
if (remember) {
localStorage['timesheet.permissions'] = JSON.stringify(permissions);
} else {
$cookieStore.put('timesheet.permissions', permissions);
}
$rootScope.loggedPermissionList = permissions;
},
customClearLocalStorage: function() {
delete localStorage['timesheet.user'];
delete localStorage['timesheet.permissions'];
},
logout: function() {
this.customClearLocalStorage();
$cookieStore.remove('timesheet.user');
$cookieStore.remove('timesheet.permissions');
$rootScope.loggedPermissionList = [];
delete $rootScope.currentUser;
delete $rootScope.currentToken;
delete $rootScope.navItems;
$location.path('/login');
}
};
}])
AuthRequest Service¶
Handles authentication API requests.
// From /public/app/js/mine/services.js
StratpointTSApp
.factory('AuthRequest', ['$resource', '$http', '$rootScope', '$location', '$q', 'BASE_URL', 'BasicData', 'Flash', 'Authenticate', function($resource, $http, $rootScope, $location, $q, BASE_URL, BasicData, Flash, Authenticate){
return $resource(BASE_URL + "/api/v2/authenticate/:id", {id: '@id'}, {
login: {
method: 'POST'
},
logout: {
method: 'DELETE'
},
refreshToken: {
method: 'PATCH'
}
});
}])
Data Services¶
BasicData Service¶
Core data service for CRUD operations using $resource.
// From /public/app/js/mine/services.js
StratpointTSApp
.factory('BasicData', ['$http','$resource', '$q', '$filter', '$timeout', 'BASE_URL', 'Cache', function($http, $resource, $q, $filter, $timeout, BASE_URL, Cache){
var rs = $resource(BASE_URL + "/api/v2/:backendRoute/:id", {id: '@id', backendRoute: '@backendRoute' } , {
update: { method: 'PUT' },
Add: { method: 'POST' },
Edit: { method: 'PUT' }
});
rs.getFilterDefer = function (backendRoute) {
var deferred = $q.defer();
var cacheName = backendRoute + '.filters';
if(typeof ( result = Cache.get(cacheName)) == 'undefined' ) {
$http.get(BASE_URL + "/api/v2/" + backendRoute+ "/getfilters").then( function(response){
if(response.data.success){
var result = response.data.data;
Cache.put(cacheName, result);
deferred.resolve(angular.copy(result));
} else {
deferred.reject();
}
});
} else {
deferred.resolve(angular.copy(result));
}
return deferred;
};
rs.makePost = function(data) {
return $http.post(BASE_URL + "/api/v2/" + data.backendRoute, data );
};
rs.makePut = function(data) {
return $http.put(BASE_URL + "/api/v2/" + data.backendRoute, data );
};
rs.makeDelete = function(data) {
return $http.delete(BASE_URL + "/api/v2/" + data.backendRoute + '/' + data.id, data );
};
rs.makeGet = function(url, data) {
var deferred = $q.defer();
var cacheName = url + JSON.stringify(data || {});
if(typeof (result = Cache.get(cacheName)) == 'undefined') {
$http.get(BASE_URL + "/api/v2/" + url, {params: data}).then(function(response){
Cache.put(cacheName, response.data);
deferred.resolve(response.data);
}, function(error) {
deferred.reject(error);
});
} else {
deferred.resolve(angular.copy(result));
}
return deferred.promise;
};
return rs;
}])
Specialized Data Services¶
TimelogData Service¶
// From /public/app/js/mine/services.js
StratpointTSApp
.factory("TimelogData", ["BasicData", "Cache", "$q", "$filter", function(BasicData, Cache, $q, $filter){
return {
getTimelogs: function(userId, startDate, endDate) {
return BasicData.makeGet('timelogs/' + userId + '/' + startDate + '/' + endDate);
},
saveTimelog: function(timelogData) {
timelogData.backendRoute = 'timelogs';
return timelogData.id ? BasicData.makePut(timelogData) : BasicData.makePost(timelogData);
},
deleteTimelog: function(timelogId) {
return BasicData.makeDelete({
backendRoute: 'timelogs',
id: timelogId
});
}
};
}])
UserData Service¶
// From /public/app/js/mine/services.js
StratpointTSApp
.factory("UserData", ["BasicData", "Cache", "$q", "$filter", function(BasicData, Cache, $q, $filter){
return {
getUsers: function(filters) {
return BasicData.makeGet('users', filters);
},
getUserById: function(userId) {
return BasicData.makeGet('users/' + userId);
},
getFilters: function() {
return BasicData.getFilterDefer('users');
}
};
}])
ProjectData Service¶
// From /public/app/js/mine/services.js
StratpointTSApp
.factory("ProjectData", ["BasicData", "Cache", "Flash", "$q", "$filter", function(BasicData, Cache, Flash, $q, $filter){
return {
getProjects: function(filters) {
return BasicData.makeGet('projects', filters);
},
getProjectById: function(projectId) {
return BasicData.makeGet('projects/' + projectId);
},
saveProject: function(projectData) {
projectData.backendRoute = 'projects';
return projectData.id ? BasicData.makePut(projectData) : BasicData.makePost(projectData);
}
};
}])
Utility Services¶
Flash Message Service¶
// From /public/app/js/mine/services.js
StratpointTSApp
.factory('Flash', ['$rootScope','$timeout', function($rootScope, $timeout){
return {
show: function(message, type, timeout) {
type = type || 'info';
timeout = timeout || 5000;
$rootScope.flashMessage = {
message: message,
type: type,
show: true
};
$timeout(function() {
$rootScope.flashMessage.show = false;
}, timeout);
},
hide: function() {
if ($rootScope.flashMessage) {
$rootScope.flashMessage.show = false;
}
}
};
}])
Cache Service¶
Client-side caching with IndexedDB fallback.
// From /public/app/js/mine/services.js
StratpointTSApp
.factory('Cache', ['$http', '$q', '$filter', '$rootScope', '$timeout', 'indexedDBDataSvc', 'BASE_URL', 'CACHE_TIMEOUT', 'Flash', 'Authenticate', function($http, $q, $filter, $rootScope, $timeout, indexedDBDataSvc, BASE_URL, CACHE_TIMEOUT, Flash, Authenticate){
var memoryCache = {};
return {
put: function(key, value, timeout) {
timeout = timeout || CACHE_TIMEOUT;
memoryCache[key] = {
value: value,
timestamp: Date.now(),
timeout: timeout * 1000
};
// Also store in IndexedDB for persistence
indexedDBDataSvc.setData(key, value);
},
get: function(key) {
var cached = memoryCache[key];
if (cached) {
var age = Date.now() - cached.timestamp;
if (age < cached.timeout) {
return cached.value;
} else {
delete memoryCache[key];
}
}
// Try IndexedDB
return indexedDBDataSvc.getData(key);
},
clear: function(pattern) {
if (pattern) {
Object.keys(memoryCache).forEach(function(key) {
if (key.indexOf(pattern) !== -1) {
delete memoryCache[key];
}
});
} else {
memoryCache = {};
}
indexedDBDataSvc.clearData(pattern);
}
};
}])
Data Export Service¶
// From /public/app/js/mine/services.js
StratpointTSApp
.factory('ExportDataToCsv', function(){
return {
exportToCsv: function(data, filename) {
if (!data || !data.length) {
return;
}
var csvContent = "";
var headers = Object.keys(data[0]);
// Add headers
csvContent += headers.join(",") + "\n";
// Add data rows
data.forEach(function(row) {
var values = headers.map(function(header) {
var value = row[header] || '';
// Escape commas and quotes
if (value.toString().indexOf(',') !== -1 || value.toString().indexOf('"') !== -1) {
value = '"' + value.toString().replace(/"/g, '""') + '"';
}
return value;
});
csvContent += values.join(",") + "\n";
});
// Download file
var blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
var link = document.createElement("a");
if (link.download !== undefined) {
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename || 'export.csv');
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
};
})
Encryption Service¶
// From /public/app/js/mine/services.js
StratpointTSApp
.factory("EncryptData", function(){
return {
encrypt: function(data, key) {
// Simple encryption implementation
// Note: This is for basic obfuscation, not secure encryption
var encrypted = "";
for (var i = 0; i < data.length; i++) {
encrypted += String.fromCharCode(data.charCodeAt(i) ^ key.charCodeAt(i % key.length));
}
return btoa(encrypted);
},
decrypt: function(encryptedData, key) {
try {
var data = atob(encryptedData);
var decrypted = "";
for (var i = 0; i < data.length; i++) {
decrypted += String.fromCharCode(data.charCodeAt(i) ^ key.charCodeAt(i % key.length));
}
return decrypted;
} catch (e) {
return null;
}
}
};
})
Summary¶
The service layer in the Stratpoint Timesheet Application provides:
- HTTP Interceptors: Authentication and error handling
- Authentication Services: User login, logout, and permission management
- Data Services: CRUD operations with caching support
- Utility Services: Flash messages, caching, data export, encryption
Key Characteristics:
- All services defined directly on StratpointTSApp module
- Located in single file: /public/app/js/mine/services.js
- Extensive use of $resource for RESTful API communication
- Client-side caching with IndexedDB persistence
- Integrated authentication and permission management
- Support for data export and basic encryption