Skip to content

Commit a49e8e7

Browse files
authored
Merge pull request #1189 from OneSignal/fix/externalIdHydration
[Fix] External Id hydration
2 parents 3cdf8a1 + 67b4d5b commit a49e8e7

19 files changed

Lines changed: 204 additions & 46 deletions

__test__/unit/user/login.test.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,13 @@ jest.mock('../../../src/shared/libraries/Log');
2222
describe('Login tests', () => {
2323
beforeEach(() => {
2424
jest.useFakeTimers();
25-
test.stub(
26-
PropertiesExecutor.prototype,
27-
'getOperationsFromCache',
28-
Promise.resolve([]),
29-
);
30-
test.stub(
31-
IdentityExecutor.prototype,
32-
'getOperationsFromCache',
33-
Promise.resolve([]),
34-
);
35-
test.stub(
36-
SubscriptionExecutor.prototype,
37-
'getOperationsFromCache',
38-
Promise.resolve([]),
39-
);
25+
test.stub(PropertiesExecutor.prototype, 'getOperationsFromCache', []);
26+
test.stub(IdentityExecutor.prototype, 'getOperationsFromCache', []);
27+
test.stub(SubscriptionExecutor.prototype, 'getOperationsFromCache', []);
4028
});
4129

4230
afterEach(() => {
31+
jest.runOnlyPendingTimers();
4332
jest.resetAllMocks();
4433
});
4534

src/core/CoreModule.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import { OSModelStoreFactory } from './modelRepo/OSModelStoreFactory';
55
import Log from '../shared/libraries/Log';
66
import { logMethodCall } from '../shared/utils/utils';
77
import { SupportedModel } from './models/SupportedModels';
8+
import { NewRecordsState } from '../shared/models/NewRecordsState';
89

910
export default class CoreModule {
1011
public modelRepo?: ModelRepo;
1112
public operationRepo?: OperationRepo;
1213
public initPromise: Promise<void>;
14+
public newRecordsState?: NewRecordsState;
1315

1416
private modelCache: ModelCache;
1517
private initResolver: () => void = () => null;
@@ -25,7 +27,11 @@ export default class CoreModule {
2527
.then((allCachedOSModels) => {
2628
const modelStores = OSModelStoreFactory.build(allCachedOSModels);
2729
this.modelRepo = new ModelRepo(this.modelCache, modelStores);
28-
this.operationRepo = new OperationRepo(this.modelRepo);
30+
this.newRecordsState = new NewRecordsState();
31+
this.operationRepo = new OperationRepo(
32+
this.modelRepo,
33+
this.newRecordsState,
34+
);
2935
this.initResolver();
3036
})
3137
.catch((e) => {

src/core/CoreModuleDirector.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,13 @@ export class CoreModuleDirector {
6363
await this.core.resetModelRepoAndCache();
6464
}
6565

66-
public hydrateUser(user: UserData): void {
67-
logMethodCall('CoreModuleDirector.hydrateUser', { user });
66+
public hydrateUser(user: UserData, externalId?: string): void {
67+
logMethodCall('CoreModuleDirector.hydrateUser', { user, externalId });
6868
try {
6969
const identity = this.getIdentityModel();
7070
const properties = this.getPropertiesModel();
7171

72-
const { onesignal_id: onesignalId, external_id: externalId } =
73-
user.identity;
72+
const { onesignal_id: onesignalId } = user.identity;
7473

7574
if (!onesignalId) {
7675
throw new OneSignalError('OneSignal ID is missing from user data');
@@ -83,6 +82,7 @@ export class CoreModuleDirector {
8382
if (externalId) {
8483
identity?.setExternalId(externalId);
8584
properties?.setExternalId(externalId);
85+
user.identity.external_id = externalId;
8686
}
8787

8888
// identity and properties models are always single, so we hydrate immediately (i.e. replace existing data)
@@ -109,6 +109,8 @@ export class CoreModuleDirector {
109109
): void {
110110
logMethodCall('CoreModuleDirector._hydrateSubscriptions', {
111111
subscriptions,
112+
onesignalId,
113+
externalId,
112114
});
113115

114116
if (!subscriptions) {
@@ -175,6 +177,9 @@ export class CoreModuleDirector {
175177
}
176178

177179
/* G E T T E R S */
180+
public getNewRecordsState(): NewRecordsState | undefined {
181+
return this.core.newRecordsState;
182+
}
178183

179184
public getModelByTypeAndId(
180185
modelName: ModelName,

src/core/executors/ExecutorBase.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import { ExecutorResult } from './ExecutorResult';
99
import Log from '../../shared/libraries/Log';
1010
import Database from '../../shared/services/Database';
1111
import LocalStorage from '../../shared/utils/LocalStorage';
12+
import { NewRecordsState } from '../../shared/models/NewRecordsState';
1213

1314
const RETRY_AFTER = 5_000;
1415

1516
export default abstract class ExecutorBase {
1617
protected _deltaQueue: CoreDelta<SupportedModel>[] = [];
1718
protected _operationQueue: Operation<SupportedModel>[] = [];
19+
protected _newRecordsState: NewRecordsState;
1820

1921
protected _executeAdd?: (
2022
operation: Operation<SupportedModel>,
@@ -31,7 +33,10 @@ export default abstract class ExecutorBase {
3133
static OPERATIONS_BATCH_PROCESSING_TIME = 5;
3234
static RETRY_COUNT = 5;
3335

34-
constructor(executorConfig: ExecutorConfig<SupportedModel>) {
36+
constructor(
37+
executorConfig: ExecutorConfig<SupportedModel>,
38+
newRecordsState: NewRecordsState,
39+
) {
3540
setInterval(() => {
3641
Log.debug('OneSignal: checking for operations to process from cache');
3742
const cachedOperations = this.getOperationsFromCache();
@@ -48,6 +53,8 @@ export default abstract class ExecutorBase {
4853
this._executeAdd = executorConfig.add;
4954
this._executeUpdate = executorConfig.update;
5055
this._executeRemove = executorConfig.remove;
56+
57+
this._newRecordsState = newRecordsState;
5158
}
5259

5360
abstract processDeltaQueue(): void;
@@ -124,7 +131,7 @@ export default abstract class ExecutorBase {
124131
if (operation) {
125132
OperationCache.enqueue(operation);
126133

127-
if (this.onlineStatus) {
134+
if (this._canExecute(operation)) {
128135
this._processOperation(operation, ExecutorBase.RETRY_COUNT).catch(
129136
(err) => {
130137
Log.error(err);
@@ -187,4 +194,18 @@ export default abstract class ExecutorBase {
187194
this._processOperationQueue.call(this);
188195
}
189196
}
197+
198+
private _canExecute(operation: Operation<SupportedModel>): boolean {
199+
if (!this.onlineStatus) {
200+
return false;
201+
}
202+
203+
if (operation.applyToRecordId) {
204+
if (!this._newRecordsState.canAccess(operation.applyToRecordId)) {
205+
return false;
206+
}
207+
}
208+
209+
return true;
210+
}
190211
}
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { NewRecordsState } from '../../shared/models/NewRecordsState';
12
import { Executor } from '../models/Executor';
23
import { ExecutorConfig } from '../models/ExecutorConfig';
34
import { ModelName, SupportedModel } from '../models/SupportedModels';
@@ -6,14 +7,17 @@ import { PropertiesExecutor } from './PropertiesExecutor';
67
import { SubscriptionExecutor } from './SubscriptionExecutor';
78

89
export class ExecutorFactory {
9-
static build(executorConfig: ExecutorConfig<SupportedModel>): Executor {
10+
static build(
11+
executorConfig: ExecutorConfig<SupportedModel>,
12+
newRecordsState: NewRecordsState,
13+
): Executor {
1014
switch (executorConfig.modelName) {
1115
case ModelName.Identity:
12-
return new IdentityExecutor(executorConfig);
16+
return new IdentityExecutor(executorConfig, newRecordsState);
1317
case ModelName.Properties:
14-
return new PropertiesExecutor(executorConfig);
18+
return new PropertiesExecutor(executorConfig, newRecordsState);
1519
case ModelName.Subscriptions:
16-
return new SubscriptionExecutor(executorConfig);
20+
return new SubscriptionExecutor(executorConfig, newRecordsState);
1721
}
1822
}
1923
}

src/core/executors/ExecutorStore.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { NewRecordsState } from '../../shared/models/NewRecordsState';
12
import { ModelName } from '../models/SupportedModels';
23
import OSExecutor from './ExecutorBase';
34
import { EXECUTOR_CONFIG_MAP } from './ExecutorConfigMap';
@@ -10,10 +11,10 @@ type ExecutorStoreInterface = {
1011
export class ExecutorStore {
1112
store: ExecutorStoreInterface = {};
1213

13-
constructor() {
14+
constructor(newRecordsState: NewRecordsState) {
1415
Object.values(ModelName).forEach((modelName) => {
1516
const config = EXECUTOR_CONFIG_MAP[modelName as ModelName];
16-
this.store[modelName] = ExecutorFactory.build(config);
17+
this.store[modelName] = ExecutorFactory.build(config, newRecordsState);
1718
});
1819
}
1920

src/core/executors/IdentityExecutor.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { NewRecordsState } from '../../shared/models/NewRecordsState';
12
import OperationCache from '../caching/OperationCache';
23
import { CoreChangeType } from '../models/CoreChangeType';
34
import { PropertyDelta } from '../models/CoreDeltas';
@@ -8,8 +9,11 @@ import { isPropertyDelta } from '../utils/typePredicates';
89
import ExecutorBase from './ExecutorBase';
910

1011
export class IdentityExecutor extends ExecutorBase {
11-
constructor(executorConfig: ExecutorConfig<SupportedModel>) {
12-
super(executorConfig);
12+
constructor(
13+
executorConfig: ExecutorConfig<SupportedModel>,
14+
newRecordsState: NewRecordsState,
15+
) {
16+
super(executorConfig, newRecordsState);
1317
}
1418

1519
processDeltaQueue(): void {

src/core/executors/PropertiesExecutor.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { NewRecordsState } from '../../shared/models/NewRecordsState';
12
import ExecutorBase from './ExecutorBase';
23
import { Operation } from '../operationRepo/Operation';
34
import { CoreChangeType } from '../models/CoreChangeType';
@@ -6,8 +7,11 @@ import { ModelName, SupportedModel } from '../models/SupportedModels';
67
import OperationCache from '../caching/OperationCache';
78

89
export class PropertiesExecutor extends ExecutorBase {
9-
constructor(executorConfig: ExecutorConfig<SupportedModel>) {
10-
super(executorConfig);
10+
constructor(
11+
executorConfig: ExecutorConfig<SupportedModel>,
12+
newRecordsState: NewRecordsState,
13+
) {
14+
super(executorConfig, newRecordsState);
1115
}
1216

1317
processDeltaQueue(): void {

src/core/executors/SubscriptionExecutor.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { NewRecordsState } from '../../shared/models/NewRecordsState';
12
import OperationCache from '../caching/OperationCache';
23
import { CoreChangeType } from '../models/CoreChangeType';
34
import { CoreDelta } from '../models/CoreDeltas';
@@ -7,8 +8,11 @@ import { Operation } from '../operationRepo/Operation';
78
import ExecutorBase from './ExecutorBase';
89

910
export class SubscriptionExecutor extends ExecutorBase {
10-
constructor(executorConfig: ExecutorConfig<SupportedModel>) {
11-
super(executorConfig);
11+
constructor(
12+
executorConfig: ExecutorConfig<SupportedModel>,
13+
newRecordsState: NewRecordsState,
14+
) {
15+
super(executorConfig, newRecordsState);
1216
}
1317

1418
processDeltaQueue(): void {

src/core/modelRepo/ModelRepo.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export class ModelRepo extends Subscribable<CoreDelta<SupportedModel>> {
6060
this.broadcast({
6161
model: payload,
6262
changeType: CoreChangeType.Add,
63+
applyToRecordId: payload?.applyToRecordId,
6364
});
6465
}
6566

@@ -77,6 +78,7 @@ export class ModelRepo extends Subscribable<CoreDelta<SupportedModel>> {
7778
this.broadcast({
7879
model: payload,
7980
changeType: CoreChangeType.Remove,
81+
applyToRecordId: payload?.applyToRecordId,
8082
});
8183
}
8284

@@ -103,6 +105,7 @@ export class ModelRepo extends Subscribable<CoreDelta<SupportedModel>> {
103105
property: payload.property,
104106
oldValue: payload.oldValue,
105107
newValue: payload.newValue,
108+
applyToRecordId: payload.model?.applyToRecordId,
106109
};
107110
this.broadcast(delta);
108111
}

0 commit comments

Comments
 (0)