diff --git a/backend/src/services/__tests__/activityService.test.ts b/backend/src/services/__tests__/activityService.test.ts index 51f515be57..2381445537 100644 --- a/backend/src/services/__tests__/activityService.test.ts +++ b/backend/src/services/__tests__/activityService.test.ts @@ -1464,7 +1464,7 @@ describe('ActivityService tests', () => { }) }) - it('It should replace joinedAt if the orginal was in year 1000', async () => { + it('It should replace joinedAt if the orginal was in year 1970', async () => { const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) const memberAttributeSettingsService = new MemberAttributeSettingsService( mockIRepositoryOptions, @@ -1499,7 +1499,7 @@ describe('ActivityService tests', () => { }, }, organisation: 'Crowd', - joinedAt: new Date('1000-01-01T00:00:00Z'), + joinedAt: new Date('1970-01-01T00:00:00Z'), } await MemberRepository.create(member, mockIRepositoryOptions) @@ -1576,6 +1576,55 @@ describe('ActivityService tests', () => { [PlatformType.GITHUB]: 'anil_github', }) }) + + it('Should respect joinedAt when an existing activity comes in with a different timestamp', async () => { + // This can happen in cases like the Twitter integration. + // For follow activities, if we are onboarding we set the timestamp to 1970, + // but if we are not onboarding, we set the timestamp to the current time. + // This can cause having 2 activities with different timestamps, but the same sourceId. + // The joinedAt should stay untouched in this case. + const mockIRepositoryOptions = await SequelizeTestUtils.getTestIRepositoryOptions(db) + const memberAttributeSettingsService = new MemberAttributeSettingsService( + mockIRepositoryOptions, + ) + + await memberAttributeSettingsService.createPredefined(GithubMemberAttributes) + await memberAttributeSettingsService.createPredefined(TwitterMemberAttributes) + + const data = { + member: { + username: 'anil,', + }, + timestamp: '1970-01-01T00:00:00.000Z', + type: 'follow', + platform: PlatformType.TWITTER, + sourceId: '#sourceId1', + } + + const activityWithMember = await new ActivityService( + mockIRepositoryOptions, + ).createWithMember(data) + + const data2 = { + member: { + username: 'anil,', + }, + timestamp: '2021-09-30T14:20:27.000Z', + type: 'follow', + platform: PlatformType.TWITTER, + sourceId: '#sourceId1', + } + data.timestamp = + // Upsert the same activity with a different timestamp + await new ActivityService(mockIRepositoryOptions).createWithMember(data2) + + const memberFound = await MemberRepository.findById( + activityWithMember.memberId, + mockIRepositoryOptions, + ) + // The joinedAt should stay untouched + expect(memberFound.joinedAt).toStrictEqual(new Date('1970-01-01T00:00:00.000Z')) + }) }) }) diff --git a/backend/src/services/activityService.ts b/backend/src/services/activityService.ts index 5dc30e944a..10b869daa5 100644 --- a/backend/src/services/activityService.ts +++ b/backend/src/services/activityService.ts @@ -400,7 +400,7 @@ export default class ActivityService extends LoggingBase { { ...data.member, platform: data.platform, - joinedAt: data.timestamp, + joinedAt: activityExists ? activityExists.timestamp : data.timestamp, }, existingMember, ) diff --git a/backend/src/services/memberService.ts b/backend/src/services/memberService.ts index 8d7576e8be..cca782c551 100644 --- a/backend/src/services/memberService.ts +++ b/backend/src/services/memberService.ts @@ -188,7 +188,7 @@ export default class MemberService extends LoggingBase { if (!('platform' in data)) { throw new Error400(this.options.language, 'activity.platformRequiredWhileUpsert') } - + console.log(data) if (!data.displayName) { if (typeof data.username === 'string') { data.displayName = data.username