diff --git a/__test__/unit/http/sdkVersion.test.ts b/__test__/unit/http/sdkVersion.test.ts index d65aea8a1..9779919cc 100644 --- a/__test__/unit/http/sdkVersion.test.ts +++ b/__test__/unit/http/sdkVersion.test.ts @@ -1,6 +1,10 @@ import Environment from '../../../src/shared/helpers/Environment'; import { RequestService } from '../../../src/core/requestService/RequestService'; -import { APP_ID, DUMMY_EXTERNAL_ID } from '../../support/constants'; +import { + APP_ID, + DUMMY_EXTERNAL_ID, + DUMMY_SUBSCRIPTION_ID, +} from '../../support/constants'; import { expectHeaderToBeSent } from '../../support/helpers/sdkVersion'; import AliasPair from '../../../src/core/requestService/AliasPair'; import { getDummyPushSubscriptionOSModel } from '../../support/helpers/core'; @@ -46,6 +50,20 @@ describe('Sdk Version Header Tests', () => { RequestService.createUser({ appId: APP_ID }, {}); expectHeaderToBeSent(); }); + test('POST /users: header is sent', () => { + RequestService.createUser( + { appId: APP_ID }, + { refresh_device_metadata: true }, + ); + expectHeaderToBeSent(); + }); + test('POST /users: header is sent with subscription id', () => { + RequestService.createUser( + { appId: APP_ID, subscriptionId: DUMMY_SUBSCRIPTION_ID }, + {}, + ); + expectHeaderToBeSent(); + }); test('GET /users/by//: header is sent', () => { RequestService.getUser( { appId: APP_ID }, @@ -61,6 +79,14 @@ describe('Sdk Version Header Tests', () => { ); expectHeaderToBeSent(); }); + test('PATCH /users/by//: header is sent with subscription id', () => { + RequestService.updateUser( + { appId: APP_ID, subscriptionId: DUMMY_SUBSCRIPTION_ID }, + new AliasPair(AliasPair.EXTERNAL_ID, DUMMY_EXTERNAL_ID), + {}, + ); + expectHeaderToBeSent(); + }); test('DELETE /users/by//: header is sent', () => { RequestService.deleteUser( { appId: APP_ID }, diff --git a/src/core/requestService/CreateUserPayload.ts b/src/core/requestService/CreateUserPayload.ts new file mode 100644 index 000000000..e12dea61e --- /dev/null +++ b/src/core/requestService/CreateUserPayload.ts @@ -0,0 +1,10 @@ +import { SupportedIdentity } from '../models/IdentityModel'; +import { SupportedSubscription } from '../models/SubscriptionModels'; +import { UserPropertiesModel } from '../models/UserPropertiesModel'; + +export type CreateUserPayload = { + properties?: UserPropertiesModel; + identity?: SupportedIdentity; + refresh_device_metadata?: boolean; + subscriptions?: SupportedSubscription[]; +}; diff --git a/src/core/requestService/RequestService.ts b/src/core/requestService/RequestService.ts index c4ce0d972..896769e25 100644 --- a/src/core/requestService/RequestService.ts +++ b/src/core/requestService/RequestService.ts @@ -7,7 +7,7 @@ import { } from '../models/SubscriptionModels'; import AliasPair from './AliasPair'; import { UpdateUserPayload } from './UpdateUserPayload'; -import UserData from '../models/UserData'; +import { CreateUserPayload } from './CreateUserPayload'; import { RequestMetadata } from '../models/RequestMetadata'; import { encodeRFC3986URIComponent } from '../../shared/utils/Encoding'; import OneSignalUtils from '../../shared/utils/OneSignalUtils'; @@ -26,14 +26,27 @@ export class RequestService { */ static async createUser( requestMetadata: RequestMetadata, - requestBody: Partial, + requestBody: CreateUserPayload, ): Promise { - const { appId } = requestMetadata; - return OneSignalApiBase.post( - `apps/${appId}/users`, - requestBody, - requestMetadata.jwtHeader, - ); + const { appId, subscriptionId } = requestMetadata; + + const subscriptionHeader = subscriptionId + ? { 'OneSignal-Subscription-Id': subscriptionId } + : undefined; + + let headers = {}; + + if (subscriptionHeader) { + headers = { ...headers, ...subscriptionHeader }; + } + + if (requestMetadata.jwtHeader) { + headers = { ...headers, ...requestMetadata.jwtHeader }; + } + + requestBody['refresh_device_metadata'] = true; + + return OneSignalApiBase.post(`apps/${appId}/users`, requestBody, headers); } /** diff --git a/src/core/requestService/UserPropertyRequests.ts b/src/core/requestService/UserPropertyRequests.ts index 138d5ce99..5dc2ffb5b 100644 --- a/src/core/requestService/UserPropertyRequests.ts +++ b/src/core/requestService/UserPropertyRequests.ts @@ -13,6 +13,7 @@ import { RequestService } from './RequestService'; import MainHelper from '../../shared/helpers/MainHelper'; import OneSignalApiBaseResponse from '../../shared/api/OneSignalApiBaseResponse'; import Log from '../../shared/libraries/Log'; +import { isCompleteSubscriptionObject } from '../utils/typePredicates'; /** * This class contains logic for all the UserProperty model related requests that can be made to the OneSignal API @@ -44,9 +45,21 @@ export default class UserPropertyRequests { ); const appId = await MainHelper.getAppId(); - const response = await RequestService.updateUser({ appId }, aliasPair, { - properties, - }); + const pushSubscription = + await OneSignal.coreDirector.getPushSubscriptionModel(); + + let subscriptionId; + if (isCompleteSubscriptionObject(pushSubscription?.data)) { + subscriptionId = pushSubscription?.data.id; + } + + const response = await RequestService.updateUser( + { appId, subscriptionId }, + aliasPair, + { + properties, + }, + ); return UserPropertyRequests._processUserPropertyResponse(response); } diff --git a/src/onesignal/UserDirector.ts b/src/onesignal/UserDirector.ts index dc10c355e..4df8e56ef 100644 --- a/src/onesignal/UserDirector.ts +++ b/src/onesignal/UserDirector.ts @@ -9,6 +9,7 @@ import { logMethodCall } from '../shared/utils/utils'; import User from './User'; import { RequestService } from '../core/requestService/RequestService'; import { SupportedSubscription } from '../core/models/SubscriptionModels'; +import { isCompleteSubscriptionObject } from '../core/utils/typePredicates'; export default class UserDirector { static async initializeUser(isTemporary?: boolean): Promise { @@ -95,8 +96,19 @@ export default class UserDirector { try { const appId = await MainHelper.getAppId(); + const pushSubscription = + await OneSignal.coreDirector.getPushSubscriptionModel(); + + let subscriptionId; + if (isCompleteSubscriptionObject(pushSubscription?.data)) { + subscriptionId = pushSubscription?.data.id; + } + const userData = await UserDirector.getAllUserData(); - const response = await RequestService.createUser({ appId }, userData); + const response = await RequestService.createUser( + { appId, subscriptionId }, + userData, + ); user.isCreatingUser = false; return response.result as UserData; } catch (e) { diff --git a/src/page/managers/LoginManager.ts b/src/page/managers/LoginManager.ts index 441e2ba5e..6c784ae0b 100644 --- a/src/page/managers/LoginManager.ts +++ b/src/page/managers/LoginManager.ts @@ -185,7 +185,7 @@ export default class LoginManager { if (isIdentified) { // if started off identified, upsert a user - result = await this.upsertUser(userData); + result = await this.upsertUser(userData, subscriptionId); } else { // promoting anonymous user to identified user // from user data, we only use identity (and we remove all aliases except external_id) @@ -196,9 +196,10 @@ export default class LoginManager { static async upsertUser( userData: Partial, + subscriptionId?: string, retry = 5, ): Promise { - logMethodCall('LoginManager.upsertUser', { userData }); + logMethodCall('LoginManager.upsertUser', { userData, subscriptionId }); if (retry === 0) { throw new OneSignalError('Login: upsertUser failed: max retries reached'); @@ -210,7 +211,10 @@ export default class LoginManager { // only accepts one alias, so remove other aliases only leaving external_id this.stripAliasesOtherThanExternalId(userData); - const response = await RequestService.createUser({ appId }, userData); + const response = await RequestService.createUser( + { appId, subscriptionId }, + userData, + ); const result = response?.result; const status = response?.status; @@ -221,7 +225,7 @@ export default class LoginManager { } else if (status >= 500) { Log.error('Server error. Retrying...'); await awaitableTimeout(RETRY_BACKOFF[retry]); - return this.upsertUser(userDataCopy, retry - 1); + return this.upsertUser(userDataCopy, subscriptionId, retry - 1); } return result;