From e972b0af8f2e44e0d6c5df2958699686fdeb0366 Mon Sep 17 00:00:00 2001 From: Daniel Passos Date: Tue, 28 May 2019 16:33:28 -0300 Subject: [PATCH 1/8] Add unregister method --- packages/push/src/PushRegistration.ts | 74 +++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/packages/push/src/PushRegistration.ts b/packages/push/src/PushRegistration.ts index 3d56fb27..fe71056f 100644 --- a/packages/push/src/PushRegistration.ts +++ b/packages/push/src/PushRegistration.ts @@ -119,6 +119,80 @@ export class PushRegistration { }); } + /** + * Register deviceToken for Android or IOS platforms + * + * @param deviceToken token that will be sent to Unified Push server + */ + public unregister(deviceToken: string): Promise { + if (!window || !window.device) { + return Promise.reject(new Error("Registration requires cordova plugin. Verify the " + + "@aerogear/cordova-plugin-aerogear-push plugin is installed.")); + } + + if (!this.pushConfig || !this.pushConfig.config || !this.pushConfig.url) { + return Promise.reject(new Error("UPS registration: configuration is invalid")); + } + + if (!deviceToken) { + return Promise.reject(new Error("Device token should not be empty")); + } + + let platformConfig; + const url = this.pushConfig.url; + if (isCordovaAndroid()) { + platformConfig = this.pushConfig.config.android; + } else if (isCordovaIOS()) { + platformConfig = this.pushConfig.config.ios; + } else { + return Promise.reject(new Error("UPS registration: Platform is not supported.")); + } + + if (!platformConfig) { + return Promise.reject(new Error("UPS registration: Platform is configured." + + "Please add UPS variant and generate mobile - config.json again")); + } + + const variantId = platformConfig.variantId || platformConfig.variantID; + if (!variantId) { + return Promise.reject(new Error("UPS registration: variantId is not defined.")); + } + + const variantSecret = platformConfig.variantSecret; + if (!variantSecret) { + return Promise.reject(new Error("UPS registration: variantSecret is not defined.")); + } + + this._objectInstance = window.PushNotification.init( + { + android: {}, + ios: { + alert: true, + badge: true, + sound: true + } + } + ); + + const authToken = window.btoa(`${variantId}:${variantSecret}`); + + const instance = axios.create({ + baseURL: url, + timeout: 5000, + headers: {"Authorization": `Basic ${authToken}`} + }); + + return new Promise((resolve, reject) => { + return instance.delete(PushRegistration.API_PATH, {}) + .then( + () => { + resolve(); + } + ) + .catch(reject); + }); + } + /** * Return the config used for the push service */ From 82bedfdb63aef972e8e2e44226af3f9c2788d032 Mon Sep 17 00:00:00 2001 From: Daniel Passos Date: Thu, 13 Jun 2019 18:17:42 -0300 Subject: [PATCH 2/8] Store device token to use on unregistration --- packages/push/src/PushRegistration.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/push/src/PushRegistration.ts b/packages/push/src/PushRegistration.ts index fe71056f..e9eb27fc 100644 --- a/packages/push/src/PushRegistration.ts +++ b/packages/push/src/PushRegistration.ts @@ -16,6 +16,7 @@ export class PushRegistration { public static readonly TYPE: string = "push"; public static readonly API_PATH: string = "rest/registry/device"; + private static readonly TOKEN_KEY = "UPS_DEVICE_TOKEN"; private readonly pushConfig?: ServiceConfiguration; private _objectInstance: any; @@ -96,22 +97,26 @@ export class PushRegistration { "categories": categories }; - const instance = axios.create({ + const http = axios.create({ baseURL: url, timeout: 5000, headers: {"Authorization": `Basic ${authToken}`} }); return new Promise((resolve, reject) => { - return instance.post(PushRegistration.API_PATH, postData) + return http.post(PushRegistration.API_PATH, postData) .then( () => { + const storage = window.localStorage; + storage.setItem(PushRegistration.TOKEN_KEY, deviceToken); + if (isCordovaAndroid()) { this.subscribeToFirebaseTopic(variantId); for (const category of categories) { this.subscribeToFirebaseTopic(category); } } + resolve(); } ) @@ -121,10 +126,8 @@ export class PushRegistration { /** * Register deviceToken for Android or IOS platforms - * - * @param deviceToken token that will be sent to Unified Push server */ - public unregister(deviceToken: string): Promise { + public unregister(): Promise { if (!window || !window.device) { return Promise.reject(new Error("Registration requires cordova plugin. Verify the " + "@aerogear/cordova-plugin-aerogear-push plugin is installed.")); @@ -134,6 +137,9 @@ export class PushRegistration { return Promise.reject(new Error("UPS registration: configuration is invalid")); } + const storage = window.localStorage; + const deviceToken = storage.getItem(PushRegistration.TOKEN_KEY); + if (!deviceToken) { return Promise.reject(new Error("Device token should not be empty")); } @@ -176,14 +182,15 @@ export class PushRegistration { const authToken = window.btoa(`${variantId}:${variantSecret}`); - const instance = axios.create({ + const http = axios.create({ baseURL: url, timeout: 5000, headers: {"Authorization": `Basic ${authToken}`} }); return new Promise((resolve, reject) => { - return instance.delete(PushRegistration.API_PATH, {}) + const endpoint = PushRegistration.API_PATH + "/" + deviceToken; + return http.delete(endpoint, {}) .then( () => { resolve(); From 657999919479438a347dcf7dde130e4e9baad813 Mon Sep 17 00:00:00 2001 From: Daniel Passos Date: Thu, 13 Jun 2019 23:00:11 -0300 Subject: [PATCH 3/8] Fix JSDoc --- packages/push/src/PushRegistration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/push/src/PushRegistration.ts b/packages/push/src/PushRegistration.ts index e9eb27fc..7015a66a 100644 --- a/packages/push/src/PushRegistration.ts +++ b/packages/push/src/PushRegistration.ts @@ -125,7 +125,7 @@ export class PushRegistration { } /** - * Register deviceToken for Android or IOS platforms + * Unregister device for Android or IOS platforms */ public unregister(): Promise { if (!window || !window.device) { From 676e1088a582faac98fb5ea0a6ff6e4cb9ba88cd Mon Sep 17 00:00:00 2001 From: Daniel Passos Date: Thu, 13 Jun 2019 23:06:13 -0300 Subject: [PATCH 4/8] Fix push test --- packages/push/test/PushRegistrationTest.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/push/test/PushRegistrationTest.ts b/packages/push/test/PushRegistrationTest.ts index c6331cc3..3ed197a2 100644 --- a/packages/push/test/PushRegistrationTest.ts +++ b/packages/push/test/PushRegistrationTest.ts @@ -7,6 +7,7 @@ declare var global: any; global.window = { btoa: () => "dGVzdA==" }; global.window.PushNotification = { init: () => "" }; +global.window.localStorage = { setItem: () => "" }; window.device = { platform: "iOS" }; describe("Registration tests", () => { From 2965635d092a8c4008e5c1f30e70791211ee6c31 Mon Sep 17 00:00:00 2001 From: Daniel Passos Date: Tue, 18 Jun 2019 09:58:04 -0300 Subject: [PATCH 5/8] Move push config checks to the constructor --- packages/push/src/PushRegistration.ts | 256 ++++++++++++-------------- 1 file changed, 113 insertions(+), 143 deletions(-) diff --git a/packages/push/src/PushRegistration.ts b/packages/push/src/PushRegistration.ts index 7015a66a..8da198bf 100644 --- a/packages/push/src/PushRegistration.ts +++ b/packages/push/src/PushRegistration.ts @@ -1,5 +1,9 @@ -import { isCordovaAndroid, isCordovaIOS, ServiceConfiguration, ConfigurationService } from "@aerogear/core"; -import axios from "axios"; +import { + ConfigurationService, + isCordovaAndroid, + isCordovaIOS +} from "@aerogear/core"; +import axios, { AxiosInstance } from "axios"; declare var window: any; @@ -15,16 +19,85 @@ declare var window: any; export class PushRegistration { public static readonly TYPE: string = "push"; - public static readonly API_PATH: string = "rest/registry/device"; + + private static readonly API_PATH: string = "rest/registry/device"; private static readonly TOKEN_KEY = "UPS_DEVICE_TOKEN"; - private readonly pushConfig?: ServiceConfiguration; - private _objectInstance: any; + private readonly validationError?: string; + private readonly variantId?: string; + private readonly http?: AxiosInstance; + private readonly push?: any; constructor(config: ConfigurationService) { const configuration = config.getConfigByType(PushRegistration.TYPE); + if (configuration && configuration.length > 0) { - this.pushConfig = configuration[0]; + const pushConfig = configuration[0]; + + if (!window || !window.device || !window.PushNotification) { + const errorMessage = "@aerogear/cordova-plugin-aerogear-push plugin not installed."; + this.validationError = errorMessage; + console.warn(errorMessage); + } + + if (!pushConfig || !pushConfig.config) { + const errorMessage = "UnifiedPush server configuration not found"; + this.validationError = errorMessage; + console.warn(errorMessage); + } + + const unifiedPushServerURL = pushConfig.url; + if (!pushConfig.url) { + const errorMessage = "UnifiedPush server URL not found"; + this.validationError = errorMessage; + console.warn(errorMessage); + } + + let platformConfig; + if (isCordovaAndroid()) { + platformConfig = pushConfig.config.android; + } else if (isCordovaIOS()) { + platformConfig = pushConfig.config.ios; + } else { + const errorMessage = "Platform is not supported by UnifiedPush"; + this.validationError = errorMessage; + console.warn(errorMessage); + } + + this.variantId = platformConfig.variantId || platformConfig.variantID; + if (!this.variantId) { + const errorMessage = "UnifiedPush VariantId is not defined"; + this.validationError = errorMessage; + console.warn(errorMessage); + } + + const variantSecret = platformConfig.variantSecret; + if (!variantSecret) { + const errorMessage = "UnifiedPush VariantSecret is not defined"; + this.validationError = errorMessage; + console.warn(errorMessage); + } + + if (!this.validationError) { + const token = window.btoa(`${this.variantId}:${variantSecret}`); + this.http = axios.create({ + baseURL: unifiedPushServerURL, + timeout: 5000, + headers: {"Authorization": `Basic ${token}`} + }); + } + + this.push = window.PushNotification.init( + { + android: {}, + ios: { + alert: true, + badge: true, + sound: true + } + } + ); + } else { console.warn("Push configuration is missing. UPS server registration will not work."); } @@ -38,56 +111,15 @@ export class PushRegistration { * @param categories array list of categories that device should be register to. */ public register(deviceToken: string, alias: string = "", categories: string[] = []): Promise { - if (!window || !window.device || !window.PushNotification) { - return Promise.reject(new Error("Registration requires cordova plugin. Verify the " + - "@aerogear/cordova-plugin-aerogear-push plugin is installed.")); - } - - if (!this.pushConfig || !this.pushConfig.config || !this.pushConfig.url) { - return Promise.reject(new Error("UPS registration: configuration is invalid")); - } if (!deviceToken) { return Promise.reject(new Error("Device token should not be empty")); } - let platformConfig; - const url = this.pushConfig.url; - if (isCordovaAndroid()) { - platformConfig = this.pushConfig.config.android; - } else if (isCordovaIOS()) { - platformConfig = this.pushConfig.config.ios; - } else { - return Promise.reject(new Error("UPS registration: Platform is not supported.")); - } - - if (!platformConfig) { - return Promise.reject(new Error("UPS registration: Platform is configured." + - "Please add UPS variant and generate mobile - config.json again")); + if (this.validationError) { + return Promise.reject(new Error(this.validationError)); } - const variantId = platformConfig.variantId || platformConfig.variantID; - if (!variantId) { - return Promise.reject(new Error("UPS registration: variantId is not defined.")); - } - - const variantSecret = platformConfig.variantSecret; - if (!variantSecret) { - return Promise.reject(new Error("UPS registration: variantSecret is not defined.")); - } - - this._objectInstance = window.PushNotification.init( - { - android: {}, - ios: { - alert: true, - badge: true, - sound: true - } - } - ); - - const authToken = window.btoa(`${variantId}:${variantSecret}`); const postData = { "deviceToken": deviceToken, "deviceType": window.device.model, @@ -97,30 +129,29 @@ export class PushRegistration { "categories": categories }; - const http = axios.create({ - baseURL: url, - timeout: 5000, - headers: {"Authorization": `Basic ${authToken}`} - }); - return new Promise((resolve, reject) => { - return http.post(PushRegistration.API_PATH, postData) - .then( - () => { - const storage = window.localStorage; - storage.setItem(PushRegistration.TOKEN_KEY, deviceToken); - - if (isCordovaAndroid()) { - this.subscribeToFirebaseTopic(variantId); - for (const category of categories) { - this.subscribeToFirebaseTopic(category); + if (this.http) { + return this.http.post(PushRegistration.API_PATH, postData) + .then( + () => { + const storage = window.localStorage; + storage.setItem(PushRegistration.TOKEN_KEY, deviceToken); + + if (isCordovaAndroid() && this.variantId) { + this.subscribeToFirebaseTopic(this.variantId); + for (const category of categories) { + this.subscribeToFirebaseTopic(category); + } } - } - resolve(); - } - ) - .catch(reject); + resolve(); + } + ) + .catch(reject); + } else { + // It should never happend but... + return Promise.reject(new Error("Push is not properly configured")); + } }); } @@ -128,14 +159,6 @@ export class PushRegistration { * Unregister device for Android or IOS platforms */ public unregister(): Promise { - if (!window || !window.device) { - return Promise.reject(new Error("Registration requires cordova plugin. Verify the " + - "@aerogear/cordova-plugin-aerogear-push plugin is installed.")); - } - - if (!this.pushConfig || !this.pushConfig.config || !this.pushConfig.url) { - return Promise.reject(new Error("UPS registration: configuration is invalid")); - } const storage = window.localStorage; const deviceToken = storage.getItem(PushRegistration.TOKEN_KEY); @@ -144,78 +167,25 @@ export class PushRegistration { return Promise.reject(new Error("Device token should not be empty")); } - let platformConfig; - const url = this.pushConfig.url; - if (isCordovaAndroid()) { - platformConfig = this.pushConfig.config.android; - } else if (isCordovaIOS()) { - platformConfig = this.pushConfig.config.ios; - } else { - return Promise.reject(new Error("UPS registration: Platform is not supported.")); - } - - if (!platformConfig) { - return Promise.reject(new Error("UPS registration: Platform is configured." + - "Please add UPS variant and generate mobile - config.json again")); - } - - const variantId = platformConfig.variantId || platformConfig.variantID; - if (!variantId) { - return Promise.reject(new Error("UPS registration: variantId is not defined.")); - } - - const variantSecret = platformConfig.variantSecret; - if (!variantSecret) { - return Promise.reject(new Error("UPS registration: variantSecret is not defined.")); + if (this.validationError) { + return Promise.reject(new Error(this.validationError)); } - this._objectInstance = window.PushNotification.init( - { - android: {}, - ios: { - alert: true, - badge: true, - sound: true - } - } - ); - - const authToken = window.btoa(`${variantId}:${variantSecret}`); - - const http = axios.create({ - baseURL: url, - timeout: 5000, - headers: {"Authorization": `Basic ${authToken}`} - }); - return new Promise((resolve, reject) => { - const endpoint = PushRegistration.API_PATH + "/" + deviceToken; - return http.delete(endpoint, {}) - .then( - () => { - resolve(); - } - ) - .catch(reject); + if (this.http) { + const endpoint = PushRegistration.API_PATH + "/" + deviceToken; + return this.http.delete(endpoint, {}) + .then(() => resolve()) + .catch(reject); + } else { + // It should never happend but... + return Promise.reject(new Error("Push is not properly configured")); + } }); } - /** - * Return the config used for the push service - */ - public getConfig(): ServiceConfiguration | undefined { - return this.pushConfig; - } - - /** - * Return true if config is present - */ - public hasConfig(): boolean { - return !!this.pushConfig; - } - private subscribeToFirebaseTopic(topic: string) { - this._objectInstance.subscribe( + this.push.subscribe( topic, () => { console.warn("FCM topic: " + topic + " subscribed"); From 900cb5ab904813cca55d192f6eeae5955f25d30f Mon Sep 17 00:00:00 2001 From: Daniel Passos Date: Thu, 20 Jun 2019 18:30:22 -0300 Subject: [PATCH 6/8] Rename http push variable to httpClient --- packages/push/src/PushRegistration.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/push/src/PushRegistration.ts b/packages/push/src/PushRegistration.ts index 8da198bf..d260693b 100644 --- a/packages/push/src/PushRegistration.ts +++ b/packages/push/src/PushRegistration.ts @@ -25,7 +25,7 @@ export class PushRegistration { private readonly validationError?: string; private readonly variantId?: string; - private readonly http?: AxiosInstance; + private readonly httpClient?: AxiosInstance; private readonly push?: any; constructor(config: ConfigurationService) { @@ -80,7 +80,7 @@ export class PushRegistration { if (!this.validationError) { const token = window.btoa(`${this.variantId}:${variantSecret}`); - this.http = axios.create({ + this.httpClient = axios.create({ baseURL: unifiedPushServerURL, timeout: 5000, headers: {"Authorization": `Basic ${token}`} @@ -130,8 +130,8 @@ export class PushRegistration { }; return new Promise((resolve, reject) => { - if (this.http) { - return this.http.post(PushRegistration.API_PATH, postData) + if (this.httpClient) { + return this.httpClient.post(PushRegistration.API_PATH, postData) .then( () => { const storage = window.localStorage; @@ -172,9 +172,9 @@ export class PushRegistration { } return new Promise((resolve, reject) => { - if (this.http) { + if (this.httpClient) { const endpoint = PushRegistration.API_PATH + "/" + deviceToken; - return this.http.delete(endpoint, {}) + return this.httpClient.delete(endpoint, {}) .then(() => resolve()) .catch(reject); } else { From 3af57ba104aadab7cb70b413d3dcd60c9f8712af Mon Sep 17 00:00:00 2001 From: Daniel Passos Date: Fri, 21 Jun 2019 09:42:05 -0300 Subject: [PATCH 7/8] Only create cordova push instance if there is no error --- packages/push/src/PushRegistration.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/push/src/PushRegistration.ts b/packages/push/src/PushRegistration.ts index d260693b..6e7c19dc 100644 --- a/packages/push/src/PushRegistration.ts +++ b/packages/push/src/PushRegistration.ts @@ -85,18 +85,18 @@ export class PushRegistration { timeout: 5000, headers: {"Authorization": `Basic ${token}`} }); - } - this.push = window.PushNotification.init( - { - android: {}, - ios: { - alert: true, - badge: true, - sound: true + this.push = window.PushNotification.init( + { + android: {}, + ios: { + alert: true, + badge: true, + sound: true + } } - } - ); + ); + } } else { console.warn("Push configuration is missing. UPS server registration will not work."); From b2d6d91ddf4a530331a2dbcf25e2e3269b99246d Mon Sep 17 00:00:00 2001 From: Daniel Passos Date: Fri, 21 Jun 2019 09:47:41 -0300 Subject: [PATCH 8/8] Add push unregister test --- packages/push/test/PushRegistrationTest.ts | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/push/test/PushRegistrationTest.ts b/packages/push/test/PushRegistrationTest.ts index 3ed197a2..53c1caa8 100644 --- a/packages/push/test/PushRegistrationTest.ts +++ b/packages/push/test/PushRegistrationTest.ts @@ -53,4 +53,27 @@ describe("Registration tests", () => { } }); }); + + describe("#unregister", async () => { + it("should fail to unregister in push server", async () => { + try { + await registration.unregister(); + assert.fail(); + } catch (_) { + return "ok"; + } + }); + + it("should unregister in push server", async function() { + // in CI environment this test sometimes fails because of the default timeout 2s + // increase timeout to 10s + this.timeout(10000); + try { + global.window.localStorage = { getItem: () => "deviceToken" }; + await registration.unregister(); + } catch (error) { + assert.fail(error); + } + }); + }); });