js/base/services/PushService.js
'use strict';
var PushService = ($q, $http, LoggerService, DataService, ModuleService, RegistrationService, SynthError, UserSession, SynthConfig, CheckError, $window, SynthesisRESTClient) => {
var LOG = LoggerService('PushService');
/**
* Constructor
*/
class PushServiceImpl{
constructor() {
this.deviceReady = false;
this.push = null;
}
/**
* Invoked from the Push Cordova plugin when a notification is received
*/
_onNotificationReceived(data){
SynthesisRESTClient.getPushMessage(data.additionalData.id).then((pushMessage) => {
// A test message
if(pushMessage.messageType === 1){
navigator.notification.confirm(pushMessage.message, angular.noop, pushMessage.title, ['Ok']);
/**
* If we are in the foreground and the message is an important one
* we will interupt the user with a dialog
*/
}
else if(pushMessage.emergency === true || data.additionalData.foreground === false){
// A tool update
if(pushMessage.messageType === 2){
var buttons = ['Ok', 'Cancel'],
callback = (option) => {
if(option == 1){
$window.location = '#/sync';
}
};
navigator.notification.confirm(pushMessage.message, callback, pushMessage.title, buttons);
}
}
});
}
/**
* Invoked from the Push Cordova plugin when the registration is received
*/
_onRegistrationReceived(pushRegistration){
LOG.debug('Registered! ' + pushRegistration.registrationId);
var data = {
'device' : {
'platform' : device.platform,
'model' : device.model,
'uuid' : device.uuid,
'regId' : pushRegistration.registrationId
}
};
return this._sendRequest('register', 'POST', data, true);
}
/**
* Returns a promise that will be resolved when the cordova
* thinks the device is ready and you can use the API
*/
cordovaReady() {
var deferred = $q.defer();
const self = this;
if (this.deviceReady === true) {
deferred.resolve();
}
else {
document.addEventListener('deviceready', () => {
self.deviceReady = true;
deferred.resolve();
}, false);
}
return deferred.promise;
}
_sendRequest(url, method, requestData, appendAuthentication = false){
return SynthesisRESTClient._doRequest(`/service-push/${url}`, method, requestData, appendAuthentication)
.then((response) => {
var responseData = response.data;
// Check if there is an error
if (CheckError(null, responseData)){
return $q.reject(SynthError(responseData));
}
return responseData;
},
() => {
return $q.reject(SynthError(1000));
});
}
/**
* Register the device for push notifications.
* If notifications are not enabled for this application, it will just return.
* If the device is offline - ??
* If the device is online, this method will request a registration token and send
* it to the server.
*/
registerDevice() {
// If push notifications are not enable we return
if(!SynthConfig.pushEnabled){
return $q.when(true);
}
return this.cordovaReady().then(() => {
if(this.push == null){
this.push = PushNotification.init({ 'android' : {'senderID' : SynthConfig.androidSenderID, 'image' : 'icon'}, 'ios' : {}});
// Registration to GCM/APNS is completed and we received a token
this.push.on('registration', (registrationData) => {
this._onRegistrationReceived(registrationData);
});
// A notification message is received
this.push.on('notification', (notificationData) => {
this._onNotificationReceived(notificationData);
});
// Something went wrong
this.push.on('error', (e) => {
LOG.error(`Error Registering for PushNotifications: ${e.message}`);
});
}
});
}
/**
* Get the current preferences saved locally
* When we get the preferences we need to delete the onces from the Server
* that are unknown to us
* Object format:
* {
* 'moduleId1': {
* 'announcements': false,
* 'faq': false,
* 'forums': false,
* 'welcome': false,
* 'schedule': false,
* 'learning_units': false,
* 'resources': false
* },
* 'moduleId1': {
* 'announcements': false,
* 'faq': false,
* 'forums': false,
* 'welcome': false,
* 'schedule': false,
* 'learning_units': false,
* 'resources': false
* }
* }
* }
*/
getPushToolPreferences(){
// The preferences we are working with
var preferences = {}, // What we are going to return
// Preferences that we need to delete
// This object will start off with all the preferences that are
// on the server. As we detect known ones, it is removed from
// the object. In the end this object will contain all the ones
// we need to delete
unkownPreferences;
const self = this;
function getServerPreferences(){
return self._getToolPushPreferencesServer().then((sPreferences) => {
unkownPreferences = sPreferences;
});
}
// Get registered modules
function getModules(){
return ModuleService.getLinkedModules().then((mdls) => {
return mdls;
});
}
// Loop through each module
function loopModules(modules){
var promise = $q.when();
angular.forEach(modules, function(module){
promise = promise.then(function(){
return checkModulePreferences(module.id);
});
});
return promise;
}
// Get tool preferences for module
function checkModulePreferences(moduleId){
preferences[moduleId] = {};
return ModuleService.getModuleData(moduleId).then((moduleData) => {
// Tool description object from module.json
var toolDescriptions = moduleData.toolDescriptions;
// Get the preference for each tool
for (var toolId in toolDescriptions) {
if (toolDescriptions.hasOwnProperty(toolId)) {
var tool = toolDescriptions[toolId];
// Skip tools that are not displayed on the menu
if(!tool.menu){
continue;
}
if(unkownPreferences[moduleId] && unkownPreferences[moduleId][toolId] !== undefined){
preferences[moduleId][toolId] = unkownPreferences[moduleId][toolId];
delete unkownPreferences[moduleId][toolId];
if(Object.keys(unkownPreferences[moduleId]).length === 0){
delete unkownPreferences[moduleId];
}
}
// The preference will be null if it is a
// preference not yet set on the server
if(preferences[moduleId][toolId] == null){
preferences[moduleId][toolId] = false;
}
}
}
});
}
/**
* Sends requests to the server to delete the unkown preferences
*/
function deleteUnknownPreferences(){
if(Object.keys(unkownPreferences).length === 0){
return $q.when(true);
}
else{
return self._sendRequest(`preferences/${device.uuid}`, 'DELETE', {toolPreferences : unkownPreferences}, true);
}
}
return getServerPreferences()
.then(getModules)
.then(loopModules)
.then(deleteUnknownPreferences)
.then(() => {
return preferences;
});
}
/**
* Gets the push preferences from the server
*/
_getToolPushPreferencesServer(){
return this._sendRequest(`preferences/${device.uuid}`, 'GET')
.then((data) => {
return data.map.toolPreferences;
});
}
/**
* Update the push preferences for this devices.
* It first attempts to update on the Synthesis Server
* then persists locally
*
* Object format:
* {
* 'moduleId' : {
* 'toolId' : true/false,
* 'toolId' : true/false,
* etc ...
* },
* etc ...
*
* }
*
*/
updatePushPreferences(preferences) {
var sendData = {
'toolPreferences' : preferences
};
return this._sendRequest(`preferences/${device.uuid}`, 'POST', sendData, true)
.then((data) => {
// Check if there is an error
if (CheckError(null, data)){
return $q.reject(SynthError(data));
}
return data.map.toolPreferences;
});
}
/**
*
*/
enablePushForModule(moduleId) {
return this.setPushPreferenceForModule(moduleId, true);
}
disablePushForModule(moduleId) {
return this.setPushPreferenceForModule(moduleId, false);
}
/**
* Enable push notifications for a module
*/
setPushPreferenceForModule(moduleId, enabled) {
const self = this;
function updateRegistrationDataPromise(){
// Update in the settings
var mergeData = { 'modules' : {} };
mergeData.modules[moduleId] = { 'pushEnabled' : true };
return RegistrationService.mergeRegistration(mergeData);
}
function updatePushSettingToServerPromise(){
var data = {
'uuid' : device.uuid,
'sender' : `module.${moduleId}`,
'enabled' : enabled
};
return self._sendRequest('preference', 'POST', data, true);
}
// Send request to the server
return updateRegistrationDataPromise()
.then(updatePushSettingToServerPromise);
}
}
return new PushServiceImpl();
};
PushService.$inject = ['$q', '$http', 'LoggerService', 'DataService', 'ModuleService', 'RegistrationService', 'SynthError', 'UserSession', 'SynthConfig', 'SynthCheckResponseError', '$window', 'SynthesisRESTClient'];
export default PushService;