Skip to content

Commit e21ea66

Browse files
zhu-xiaoweixiaoweii
andauthored
feat: delete custom user attributes from subsequent events (#36)
Co-authored-by: xiaoweii <xiaoweii@amazom.com>
1 parent 3ec2af3 commit e21ea66

File tree

4 files changed

+83
-21
lines changed

4 files changed

+83
-21
lines changed

src/provider/ClickstreamProvider.ts

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export class ClickstreamProvider implements AnalyticsProvider {
8181
this.eventRecorder = new EventRecorder(this.context);
8282
this.globalAttributes = {};
8383
this.setGlobalAttributes(configuration.globalAttributes);
84-
this.userAttributes = StorageUtil.getUserAttributes();
84+
this.userAttributes = StorageUtil.getSimpleUserAttributes();
8585
this.sessionTracker = new SessionTracker(this, this.context);
8686
this.pageViewTracker = new PageViewTracker(this, this.context);
8787
this.clickTracker = new ClickTracker(this, this.context);
@@ -130,11 +130,14 @@ export class ClickstreamProvider implements AnalyticsProvider {
130130
this.recordEvent(resultEvent, event.isImmediate);
131131
}
132132

133-
createEvent(event: ClickstreamEvent) {
133+
createEvent(
134+
event: ClickstreamEvent,
135+
allUserAttributes: UserAttribute = null
136+
) {
134137
return AnalyticsEventBuilder.createEvent(
135138
this.context,
136139
event,
137-
this.userAttributes,
140+
allUserAttributes === null ? this.userAttributes : allUserAttributes,
138141
this.globalAttributes,
139142
this.sessionTracker.session
140143
);
@@ -155,40 +158,43 @@ export class ClickstreamProvider implements AnalyticsProvider {
155158
} else if (userId !== previousUserId) {
156159
const userInfo = StorageUtil.getUserInfoFromMapping(userId);
157160
const newUserAttribute: UserAttribute = {};
158-
userInfo[Event.ReservedAttribute.USER_ID] = {
161+
newUserAttribute[Event.ReservedAttribute.USER_ID] = {
159162
value: userId,
160163
set_timestamp: new Date().getTime(),
161164
};
162-
Object.assign(newUserAttribute, userInfo);
165+
newUserAttribute[Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP] =
166+
userInfo[Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP];
167+
StorageUtil.updateUserAttributes(newUserAttribute);
163168
this.userAttributes = newUserAttribute;
164169
this.context.userUniqueId = StorageUtil.getCurrentUserUniqueId();
165-
this.recordProfileSet();
166170
}
171+
this.recordProfileSet(this.userAttributes);
167172
StorageUtil.updateUserAttributes(this.userAttributes);
168173
}
169174

170175
setUserAttributes(attributes: ClickstreamAttribute) {
171176
const timestamp = new Date().getTime();
177+
const allUserAttributes = StorageUtil.getAllUserAttributes();
172178
for (const key in attributes) {
173179
const value = attributes[key];
174180
if (value === null) {
175-
delete this.userAttributes[key];
181+
delete allUserAttributes[key];
176182
} else {
177-
const currentNumber = Object.keys(this.userAttributes).length;
183+
const currentNumber = Object.keys(allUserAttributes).length;
178184
const { checkUserAttribute } = EventChecker;
179185
const result = checkUserAttribute(currentNumber, key, value);
180186
if (result.error_code > 0) {
181187
this.recordClickstreamError(result);
182188
} else {
183-
this.userAttributes[key] = {
189+
allUserAttributes[key] = {
184190
value: value,
185191
set_timestamp: timestamp,
186192
};
187193
}
188194
}
189195
}
190-
StorageUtil.updateUserAttributes(this.userAttributes);
191-
this.recordProfileSet();
196+
StorageUtil.updateUserAttributes(allUserAttributes);
197+
this.recordProfileSet(allUserAttributes);
192198
}
193199

194200
setGlobalAttributes(attributes: ClickstreamAttribute) {
@@ -221,10 +227,11 @@ export class ClickstreamProvider implements AnalyticsProvider {
221227
this.recordEvent(errorEvent);
222228
}
223229

224-
recordProfileSet() {
225-
const profileSetEvent = this.createEvent({
226-
name: Event.PresetEvent.PROFILE_SET,
227-
});
230+
recordProfileSet(allUserAttributes: UserAttribute) {
231+
const profileSetEvent = this.createEvent(
232+
{ name: Event.PresetEvent.PROFILE_SET },
233+
allUserAttributes
234+
);
228235
this.recordEvent(profileSetEvent);
229236
}
230237

src/util/StorageUtil.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export class StorageUtil {
101101
set_timestamp: timestamp,
102102
},
103103
[Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP]:
104-
StorageUtil.getUserAttributes()[
104+
StorageUtil.getAllUserAttributes()[
105105
Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP
106106
],
107107
};
@@ -149,12 +149,25 @@ export class StorageUtil {
149149
);
150150
}
151151

152-
static getUserAttributes(): UserAttribute {
152+
static getAllUserAttributes(): UserAttribute {
153153
const userAttributes =
154154
localStorage.getItem(StorageUtil.userAttributesKey) ?? '{}';
155155
return JSON.parse(userAttributes);
156156
}
157157

158+
static getSimpleUserAttributes(): UserAttribute {
159+
const allUserAttributes = StorageUtil.getAllUserAttributes();
160+
const simpleUserAttributes: UserAttribute = {
161+
[Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP]:
162+
allUserAttributes[Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP],
163+
};
164+
if (allUserAttributes[Event.ReservedAttribute.USER_ID] !== undefined) {
165+
simpleUserAttributes[Event.ReservedAttribute.USER_ID] =
166+
allUserAttributes[Event.ReservedAttribute.USER_ID];
167+
}
168+
return simpleUserAttributes;
169+
}
170+
158171
static getFailedEvents(): string {
159172
return localStorage.getItem(StorageUtil.failedEventsKey) ?? '';
160173
}

test/provider/ClickstreamProvider.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ describe('ClickstreamProvider test', () => {
212212
expect(
213213
Event.ReservedAttribute.USER_ID in provider.userAttributes
214214
).toBeFalsy();
215-
expect(mockRecordProfileSet).toBeCalledTimes(1);
215+
expect(mockRecordProfileSet).toBeCalledTimes(2);
216216
});
217217

218218
test('test set userId not null', () => {
@@ -271,6 +271,23 @@ describe('ClickstreamProvider test', () => {
271271
).toBe(userFirstTouchTimestamp);
272272
});
273273

274+
test('test custom user attribute not in the subsequent event', async () => {
275+
(provider.configuration as any).sendMode = SendMode.Batch;
276+
provider.setUserId('123');
277+
provider.setUserAttributes({
278+
testAttribute: 'testValue',
279+
});
280+
provider.record({ name: 'testEvent' });
281+
await sleep(100);
282+
const eventList = JSON.parse(
283+
StorageUtil.getAllEvents() + Event.Constants.SUFFIX
284+
);
285+
const lastEvent = eventList[eventList.length - 1];
286+
expect(lastEvent.event_type).toBe('testEvent');
287+
expect(lastEvent.user[Event.ReservedAttribute.USER_ID].value).toBe('123');
288+
expect(lastEvent.user.testAttribute).toBeUndefined();
289+
});
290+
274291
test('test add global attribute with invalid name', () => {
275292
const clickstreamAttribute: ClickstreamAttribute = {};
276293
clickstreamAttribute['3abc'] = 'testValue';

test/util/StorageUtil.test.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ describe('StorageUtil test', () => {
3434
});
3535

3636
test('test get user Attributes return null object', () => {
37-
const userAttribute = StorageUtil.getUserAttributes();
37+
const userAttribute = StorageUtil.getAllUserAttributes();
3838
expect(JSON.stringify(userAttribute)).toBe('{}');
3939
});
4040

4141
test('test get current user unique id', () => {
4242
const userUniqueId = StorageUtil.getCurrentUserUniqueId();
4343
expect(userUniqueId).not.toBeNull();
4444
expect(userUniqueId.length > 0).toBeTruthy();
45-
const userAttribute = StorageUtil.getUserAttributes();
45+
const userAttribute = StorageUtil.getAllUserAttributes();
4646
expect(userAttribute).not.toBeNull();
4747
expect(Object.keys(userAttribute).length > 0).toBeTruthy();
4848
expect(
@@ -68,11 +68,36 @@ describe('StorageUtil test', () => {
6868
value: 'carl',
6969
},
7070
});
71-
const userAttribute = StorageUtil.getUserAttributes();
71+
const userAttribute = StorageUtil.getAllUserAttributes();
7272
expect(Object.keys(userAttribute).length).toBe(2);
7373
expect(userAttribute['userAge']['value']).toBe(18);
7474
});
7575

76+
test('test get simple user attributes', () => {
77+
const userId = Event.ReservedAttribute.USER_ID;
78+
const firstTimestamp = Event.ReservedAttribute.USER_FIRST_TOUCH_TIMESTAMP;
79+
const currentTimeStamp = new Date().getTime();
80+
StorageUtil.updateUserAttributes({
81+
[userId]: {
82+
set_timestamp: currentTimeStamp,
83+
value: 1234,
84+
},
85+
[firstTimestamp]: {
86+
set_timestamp: currentTimeStamp,
87+
value: currentTimeStamp,
88+
},
89+
userAge: {
90+
set_timestamp: currentTimeStamp,
91+
value: 18,
92+
},
93+
});
94+
const simpleUserAttribute = StorageUtil.getSimpleUserAttributes();
95+
expect(Object.keys(simpleUserAttribute).length).toBe(2);
96+
expect(simpleUserAttribute[userId].value).toBe(1234);
97+
expect(simpleUserAttribute[firstTimestamp].value).toBe(currentTimeStamp);
98+
expect(simpleUserAttribute['userAge']).toBeUndefined();
99+
});
100+
76101
test('test save and clear failed event', async () => {
77102
const event = await getTestEvent();
78103
StorageUtil.saveFailedEvent(event);

0 commit comments

Comments
 (0)