From 7c084d7d14ab3d4b434c85d8323fb363267553bc Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Thu, 20 Jun 2024 08:20:23 +0200 Subject: [PATCH 01/12] Save last login in account --- apps/server/src/modules/account/domain/account.ts | 9 +++++++++ .../account/domain/entity/account.entity.ts | 4 ++++ .../account/domain/services/account-db.service.ts | 8 ++++++++ .../account/domain/services/account.service.ts | 15 +++++++++++++++ .../mapper/account-do-to-entity.mapper.ts | 1 + .../authentication/authentication-api.module.ts | 3 ++- .../src/modules/authentication/uc/login.uc.ts | 6 +++++- 7 files changed, 44 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/account/domain/account.ts b/apps/server/src/modules/account/domain/account.ts index 82153ffee4a..2b15037c12c 100644 --- a/apps/server/src/modules/account/domain/account.ts +++ b/apps/server/src/modules/account/domain/account.ts @@ -13,6 +13,7 @@ export interface AccountProps extends AuthorizableObject { password?: string; token?: string; credentialHash?: string; + lastLogin?: Date; lasttriedFailedLogin?: Date; expiresAt?: Date; activated?: boolean; @@ -73,6 +74,14 @@ export class Account extends DomainObject { return this.props.credentialHash; } + public get lastLogin(): Date | undefined { + return this.props.lastLogin; + } + + public set lastLogin(lastLogin: Date | undefined) { + this.props.lastLogin = lastLogin; + } + public get lasttriedFailedLogin(): Date | undefined { return this.props.lasttriedFailedLogin; } diff --git a/apps/server/src/modules/account/domain/entity/account.entity.ts b/apps/server/src/modules/account/domain/entity/account.entity.ts index 1c82e085054..ed7f7c4ccf4 100644 --- a/apps/server/src/modules/account/domain/entity/account.entity.ts +++ b/apps/server/src/modules/account/domain/entity/account.entity.ts @@ -26,6 +26,9 @@ export class AccountEntity extends BaseEntityWithTimestamps { @Property({ nullable: true }) systemId?: ObjectId; + @Property({ nullable: true }) + lastLogin?: Date; + @Property({ nullable: true }) lasttriedFailedLogin?: Date; @@ -47,6 +50,7 @@ export class AccountEntity extends BaseEntityWithTimestamps { this.userId = props.userId; this.systemId = props.systemId; this.lasttriedFailedLogin = props.lasttriedFailedLogin; + this.lastLogin = props.lastLogin; this.expiresAt = props.expiresAt; this.activated = props.activated; this.deactivatedAt = props.deactivatedAt; diff --git a/apps/server/src/modules/account/domain/services/account-db.service.ts b/apps/server/src/modules/account/domain/services/account-db.service.ts index 0a2d9b69de8..b528cfec08a 100644 --- a/apps/server/src/modules/account/domain/services/account-db.service.ts +++ b/apps/server/src/modules/account/domain/services/account-db.service.ts @@ -61,6 +61,14 @@ export class AccountServiceDb { return account; } + async updateLastLogin(accountId: EntityId, lastLogin: Date): Promise { + const internalId = await this.getInternalId(accountId); + const account = await this.accountRepo.findById(internalId); + account.lastLogin = lastLogin; + await this.accountRepo.save(account); + return account; + } + async updateLastTriedFailedLogin(accountId: EntityId, lastTriedFailedLogin: Date): Promise { const internalId = await this.getInternalId(accountId); const account = await this.accountRepo.findById(internalId); diff --git a/apps/server/src/modules/account/domain/services/account.service.ts b/apps/server/src/modules/account/domain/services/account.service.ts index 37e6a6c8a81..502cb0a5ac0 100644 --- a/apps/server/src/modules/account/domain/services/account.service.ts +++ b/apps/server/src/modules/account/domain/services/account.service.ts @@ -357,6 +357,21 @@ export class AccountService extends AbstractAccountService implements DeletionSe return new Account({ ...ret.getProps(), idmReferenceId: idmAccount?.idmReferenceId }); } + async updateLastLogin(accountId: string, lastLogin: Date): Promise { + const ret = await this.accountDb.updateLastLogin(accountId, lastLogin); + // const idmAccount = await this.executeIdmMethod(async () => { + // this.logger.debug(new UpdatingLastLoginLoggable(accountId)); + // const account = await this.accountIdm.updateLastLogin(accountId, lastLogin); + // this.logger.debug(new UpdatedLastLoginLoggable(accountId)); + // return account; + // }); + + return new Account({ + ...ret.getProps(), + // idmReferenceId: idmAccount?.idmReferenceId + }); + } + async updateLastTriedFailedLogin(accountId: string, lastTriedFailedLogin: Date): Promise { const ret = await this.accountDb.updateLastTriedFailedLogin(accountId, lastTriedFailedLogin); const idmAccount = await this.executeIdmMethod(async () => { diff --git a/apps/server/src/modules/account/repo/micro-orm/mapper/account-do-to-entity.mapper.ts b/apps/server/src/modules/account/repo/micro-orm/mapper/account-do-to-entity.mapper.ts index 173e7e98d72..bf2bd4f5b47 100644 --- a/apps/server/src/modules/account/repo/micro-orm/mapper/account-do-to-entity.mapper.ts +++ b/apps/server/src/modules/account/repo/micro-orm/mapper/account-do-to-entity.mapper.ts @@ -10,6 +10,7 @@ export class AccountDoToEntityMapper { activated: account.activated, credentialHash: account.credentialHash, expiresAt: account.expiresAt, + lastLogin: account.lastLogin, lasttriedFailedLogin: account.lasttriedFailedLogin, password: account.password, systemId: account.systemId ? new ObjectId(account.systemId) : undefined, diff --git a/apps/server/src/modules/authentication/authentication-api.module.ts b/apps/server/src/modules/authentication/authentication-api.module.ts index 6780e5fe11c..e2f7c9a44de 100644 --- a/apps/server/src/modules/authentication/authentication-api.module.ts +++ b/apps/server/src/modules/authentication/authentication-api.module.ts @@ -1,10 +1,11 @@ import { Module } from '@nestjs/common'; +import { AccountModule } from '../account'; import { AuthenticationModule } from './authentication.module'; import { LoginController } from './controllers/login.controller'; import { LoginUc } from './uc/login.uc'; @Module({ - imports: [AuthenticationModule], + imports: [AuthenticationModule, AccountModule], providers: [LoginUc], controllers: [LoginController], exports: [], diff --git a/apps/server/src/modules/authentication/uc/login.uc.ts b/apps/server/src/modules/authentication/uc/login.uc.ts index 80ab89ca49a..ed55ec5465f 100644 --- a/apps/server/src/modules/authentication/uc/login.uc.ts +++ b/apps/server/src/modules/authentication/uc/login.uc.ts @@ -1,4 +1,5 @@ import { Injectable } from '@nestjs/common'; +import { AccountService } from '@src/modules/account'; import { ICurrentUser } from '../interface'; import { CreateJwtPayload } from '../interface/jwt-payload'; import { CurrentUserMapper } from '../mapper'; @@ -7,13 +8,16 @@ import { LoginDto } from './dto'; @Injectable() export class LoginUc { - constructor(private readonly authService: AuthenticationService) {} + constructor(private readonly authService: AuthenticationService, private readonly accountService: AccountService) {} async getLoginData(userInfo: ICurrentUser): Promise { const createJwtPayload: CreateJwtPayload = CurrentUserMapper.mapCurrentUserToCreateJwtPayload(userInfo); const accessTokenDto: LoginDto = await this.authService.generateJwt(createJwtPayload); + const now = new Date(); + await this.accountService.updateLastLogin(userInfo.accountId, now); + const loginDto: LoginDto = new LoginDto({ accessToken: accessTokenDto.accessToken, }); From 7dec171d78222e69d3bdf074fbfb93ff9b81b712 Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Fri, 21 Jun 2024 14:35:26 +0200 Subject: [PATCH 02/12] Add some logs --- .../account/domain/services/account-db.service.ts | 5 ++++- .../src/modules/account/repo/micro-orm/account.repo.ts | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/server/src/modules/account/domain/services/account-db.service.ts b/apps/server/src/modules/account/domain/services/account-db.service.ts index b528cfec08a..8d9185cc337 100644 --- a/apps/server/src/modules/account/domain/services/account-db.service.ts +++ b/apps/server/src/modules/account/domain/services/account-db.service.ts @@ -4,6 +4,7 @@ import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config/dist/config.service'; import { EntityNotFoundError } from '@shared/common'; import { Counted, EntityId } from '@shared/domain/types'; +import { LegacyLogger } from '@src/core/logger'; import bcrypt from 'bcryptjs'; import { AccountConfig } from '../../account-config'; import { AccountRepo } from '../../repo/micro-orm/account.repo'; @@ -15,7 +16,8 @@ export class AccountServiceDb { constructor( private readonly accountRepo: AccountRepo, private readonly idmService: IdentityManagementService, - private readonly configService: ConfigService + private readonly configService: ConfigService, + private readonly logger: LegacyLogger ) {} async findById(id: EntityId): Promise { @@ -62,6 +64,7 @@ export class AccountServiceDb { } async updateLastLogin(accountId: EntityId, lastLogin: Date): Promise { + this.logger.debug(`Updating last login for ${accountId} to ${lastLogin.toISOString()}`); const internalId = await this.getInternalId(accountId); const account = await this.accountRepo.findById(internalId); account.lastLogin = lastLogin; diff --git a/apps/server/src/modules/account/repo/micro-orm/account.repo.ts b/apps/server/src/modules/account/repo/micro-orm/account.repo.ts index d6566afa1c0..298a671202f 100644 --- a/apps/server/src/modules/account/repo/micro-orm/account.repo.ts +++ b/apps/server/src/modules/account/repo/micro-orm/account.repo.ts @@ -3,15 +3,16 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { Injectable } from '@nestjs/common'; import { SortOrder } from '@shared/domain/interface'; import { Counted, EntityId } from '@shared/domain/types'; -import { AccountEntity } from '../../domain/entity/account.entity'; -import { AccountDoToEntityMapper } from './mapper/account-do-to-entity.mapper'; +import { LegacyLogger } from '@src/core/logger'; import { Account } from '../../domain/account'; +import { AccountEntity } from '../../domain/entity/account.entity'; import { AccountEntityToDoMapper } from './mapper'; +import { AccountDoToEntityMapper } from './mapper/account-do-to-entity.mapper'; import { AccountScope } from './scope/account-scope'; @Injectable() export class AccountRepo { - constructor(private readonly em: EntityManager) {} + constructor(private readonly em: EntityManager, private readonly logger: LegacyLogger) {} get entityName() { return AccountEntity; @@ -21,6 +22,9 @@ export class AccountRepo { const saveEntity = AccountDoToEntityMapper.mapToEntity(account); const existing = await this.em.findOne(AccountEntity, { id: account.id }); + this.logger.debug('existing', JSON.stringify(existing)); + this.logger.debug('Saving account', JSON.stringify(saveEntity)); + let saved: AccountEntity; if (existing) { saved = this.em.assign(existing, saveEntity); From ea7de6a8db936d63c7986e1cd01f699d2145983b Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Fri, 21 Jun 2024 16:05:45 +0200 Subject: [PATCH 03/12] Add last login to mapper --- .../account/repo/micro-orm/mapper/account-entity-to-do.mapper.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/modules/account/repo/micro-orm/mapper/account-entity-to-do.mapper.ts b/apps/server/src/modules/account/repo/micro-orm/mapper/account-entity-to-do.mapper.ts index 59b514840cf..000ece5001a 100644 --- a/apps/server/src/modules/account/repo/micro-orm/mapper/account-entity-to-do.mapper.ts +++ b/apps/server/src/modules/account/repo/micro-orm/mapper/account-entity-to-do.mapper.ts @@ -13,6 +13,7 @@ export class AccountEntityToDoMapper { activated: account.activated, credentialHash: account.credentialHash, expiresAt: account.expiresAt, + lastLogin: account.lastLogin, lasttriedFailedLogin: account.lasttriedFailedLogin, password: account.password, systemId: account.systemId?.toString(), From ff0baab24683cfd3fd0d6d62a7ad196a90a7e67e Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Fri, 21 Jun 2024 16:05:52 +0200 Subject: [PATCH 04/12] Remove logs --- .../modules/account/domain/services/account-db.service.ts | 5 +---- .../src/modules/account/repo/micro-orm/account.repo.ts | 6 +----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/apps/server/src/modules/account/domain/services/account-db.service.ts b/apps/server/src/modules/account/domain/services/account-db.service.ts index 8d9185cc337..b528cfec08a 100644 --- a/apps/server/src/modules/account/domain/services/account-db.service.ts +++ b/apps/server/src/modules/account/domain/services/account-db.service.ts @@ -4,7 +4,6 @@ import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config/dist/config.service'; import { EntityNotFoundError } from '@shared/common'; import { Counted, EntityId } from '@shared/domain/types'; -import { LegacyLogger } from '@src/core/logger'; import bcrypt from 'bcryptjs'; import { AccountConfig } from '../../account-config'; import { AccountRepo } from '../../repo/micro-orm/account.repo'; @@ -16,8 +15,7 @@ export class AccountServiceDb { constructor( private readonly accountRepo: AccountRepo, private readonly idmService: IdentityManagementService, - private readonly configService: ConfigService, - private readonly logger: LegacyLogger + private readonly configService: ConfigService ) {} async findById(id: EntityId): Promise { @@ -64,7 +62,6 @@ export class AccountServiceDb { } async updateLastLogin(accountId: EntityId, lastLogin: Date): Promise { - this.logger.debug(`Updating last login for ${accountId} to ${lastLogin.toISOString()}`); const internalId = await this.getInternalId(accountId); const account = await this.accountRepo.findById(internalId); account.lastLogin = lastLogin; diff --git a/apps/server/src/modules/account/repo/micro-orm/account.repo.ts b/apps/server/src/modules/account/repo/micro-orm/account.repo.ts index 298a671202f..8c158c552ea 100644 --- a/apps/server/src/modules/account/repo/micro-orm/account.repo.ts +++ b/apps/server/src/modules/account/repo/micro-orm/account.repo.ts @@ -3,7 +3,6 @@ import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; import { Injectable } from '@nestjs/common'; import { SortOrder } from '@shared/domain/interface'; import { Counted, EntityId } from '@shared/domain/types'; -import { LegacyLogger } from '@src/core/logger'; import { Account } from '../../domain/account'; import { AccountEntity } from '../../domain/entity/account.entity'; import { AccountEntityToDoMapper } from './mapper'; @@ -12,7 +11,7 @@ import { AccountScope } from './scope/account-scope'; @Injectable() export class AccountRepo { - constructor(private readonly em: EntityManager, private readonly logger: LegacyLogger) {} + constructor(private readonly em: EntityManager) {} get entityName() { return AccountEntity; @@ -22,9 +21,6 @@ export class AccountRepo { const saveEntity = AccountDoToEntityMapper.mapToEntity(account); const existing = await this.em.findOne(AccountEntity, { id: account.id }); - this.logger.debug('existing', JSON.stringify(existing)); - this.logger.debug('Saving account', JSON.stringify(saveEntity)); - let saved: AccountEntity; if (existing) { saved = this.em.assign(existing, saveEntity); From 73c38dc51effaa8bdcd4cec41ff231d0a63992f0 Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Wed, 26 Jun 2024 11:45:55 +0200 Subject: [PATCH 05/12] Add updating of last login for tsp login --- src/services/authentication/strategies/TSPStrategy.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/services/authentication/strategies/TSPStrategy.js b/src/services/authentication/strategies/TSPStrategy.js index e615aa56857..d856578df0f 100644 --- a/src/services/authentication/strategies/TSPStrategy.js +++ b/src/services/authentication/strategies/TSPStrategy.js @@ -177,6 +177,10 @@ class TSPStrategy extends AuthenticationBaseStrategy { // find account and generate JWT payload const account = await app.service('nest-account-service').findByUserId(user._id.toString()); account._id = account.id; + + const now = new Date(); + await app.service('nest-account-service').updateLastLogin(account.id, now); + const { entity } = this.configuration; return { authentication: { strategy: this.name }, From 137e373188a209cb68761f09af878bb2c350500a Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Wed, 26 Jun 2024 12:07:42 +0200 Subject: [PATCH 06/12] Update last login for idm login --- .../domain/services/account-idm.service.ts | 8 ++++++++ .../account/domain/services/account.service.ts | 15 +++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/server/src/modules/account/domain/services/account-idm.service.ts b/apps/server/src/modules/account/domain/services/account-idm.service.ts index 766a159b0cb..296518e4319 100644 --- a/apps/server/src/modules/account/domain/services/account-idm.service.ts +++ b/apps/server/src/modules/account/domain/services/account-idm.service.ts @@ -85,6 +85,14 @@ export class AccountServiceIdm extends AbstractAccountService { return [accounts, total]; } + async updateLastLogin(accountId: EntityId, lastLogin: Date): Promise { + const attributeName = 'lastLogin'; + const id = await this.getIdmAccountId(accountId); + await this.identityManager.setUserAttribute(id, attributeName, lastLogin.toISOString()); + const updatedAccount = await this.identityManager.findAccountById(id); + return this.accountIdmToDoMapper.mapToDo(updatedAccount); + } + async updateLastTriedFailedLogin(accountId: EntityId, lastTriedFailedLogin: Date): Promise { const attributeName = 'lastTriedFailedLogin'; const id = await this.getIdmAccountId(accountId); diff --git a/apps/server/src/modules/account/domain/services/account.service.ts b/apps/server/src/modules/account/domain/services/account.service.ts index 502cb0a5ac0..1ee784164df 100644 --- a/apps/server/src/modules/account/domain/services/account.service.ts +++ b/apps/server/src/modules/account/domain/services/account.service.ts @@ -359,17 +359,12 @@ export class AccountService extends AbstractAccountService implements DeletionSe async updateLastLogin(accountId: string, lastLogin: Date): Promise { const ret = await this.accountDb.updateLastLogin(accountId, lastLogin); - // const idmAccount = await this.executeIdmMethod(async () => { - // this.logger.debug(new UpdatingLastLoginLoggable(accountId)); - // const account = await this.accountIdm.updateLastLogin(accountId, lastLogin); - // this.logger.debug(new UpdatedLastLoginLoggable(accountId)); - // return account; - // }); - - return new Account({ - ...ret.getProps(), - // idmReferenceId: idmAccount?.idmReferenceId + const idmAccount = await this.executeIdmMethod(async () => { + const account = await this.accountIdm.updateLastLogin(accountId, lastLogin); + return account; }); + + return new Account({ ...ret.getProps(), idmReferenceId: idmAccount?.idmReferenceId }); } async updateLastTriedFailedLogin(accountId: string, lastTriedFailedLogin: Date): Promise { From b585e8dc8098c1d93ec61ab7ac981f168220ddfb Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Wed, 26 Jun 2024 14:06:09 +0200 Subject: [PATCH 07/12] Add index for last login --- apps/server/src/modules/account/domain/entity/account.entity.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/modules/account/domain/entity/account.entity.ts b/apps/server/src/modules/account/domain/entity/account.entity.ts index ed7f7c4ccf4..736e8897431 100644 --- a/apps/server/src/modules/account/domain/entity/account.entity.ts +++ b/apps/server/src/modules/account/domain/entity/account.entity.ts @@ -27,6 +27,7 @@ export class AccountEntity extends BaseEntityWithTimestamps { systemId?: ObjectId; @Property({ nullable: true }) + @Index() lastLogin?: Date; @Property({ nullable: true }) From 6ed6e67ee832c30ad38c811b0e6769dc8db64018 Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Wed, 26 Jun 2024 15:01:01 +0200 Subject: [PATCH 08/12] Add tests --- .../services/account-db.service.spec.ts | 49 ++++++++++++------- .../domain/services/account.service.spec.ts | 8 +++ .../authentication/uc/login.uc.spec.ts | 15 ++++++ 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/apps/server/src/modules/account/domain/services/account-db.service.spec.ts b/apps/server/src/modules/account/domain/services/account-db.service.spec.ts index e39962db20b..2cbeccc9991 100644 --- a/apps/server/src/modules/account/domain/services/account-db.service.spec.ts +++ b/apps/server/src/modules/account/domain/services/account-db.service.spec.ts @@ -10,12 +10,12 @@ import { setupEntities, userFactory } from '@shared/testing'; import { Logger } from '@src/core/logger'; import bcrypt from 'bcryptjs'; import { v1 } from 'uuid'; -import { Account } from '../account'; import { AccountConfig } from '../../account-config'; import { AccountRepo } from '../../repo/micro-orm/account.repo'; +import { accountDoFactory } from '../../testing'; +import { Account } from '../account'; import { AccountEntity } from '../entity/account.entity'; import { AccountServiceDb } from './account-db.service'; -import { accountDoFactory } from '../../testing'; describe('AccountDbService', () => { let module: TestingModule; @@ -713,27 +713,40 @@ describe('AccountDbService', () => { }); }); + describe('updateLastLogin', () => { + const setup = () => { + const mockTeacherAccount = accountDoFactory.build(); + const theNewDate = new Date(); + + accountRepo.findById.mockResolvedValue(mockTeacherAccount); + + return { mockTeacherAccount, theNewDate }; + }; + + it('should update last tried failed login', async () => { + const { mockTeacherAccount, theNewDate } = setup(); + + const ret = await accountService.updateLastLogin(mockTeacherAccount.id, theNewDate); + + expect(ret.lastLogin).toEqual(theNewDate); + }); + }); + describe('updateLastTriedFailedLogin', () => { - describe('when update last failed Login', () => { - const setup = () => { - const mockTeacherAccount = accountDoFactory.build(); - const theNewDate = new Date(); + const setup = () => { + const mockTeacherAccount = accountDoFactory.build(); + const theNewDate = new Date(); - accountRepo.findById.mockResolvedValue(mockTeacherAccount); + accountRepo.findById.mockResolvedValue(mockTeacherAccount); - return { mockTeacherAccount, theNewDate }; - }; + return { mockTeacherAccount, theNewDate }; + }; - it('should update last tried failed login', async () => { - const { mockTeacherAccount, theNewDate } = setup(); - const ret = await accountService.updateLastTriedFailedLogin(mockTeacherAccount.id, theNewDate); + it('should update last tried failed login', async () => { + const { mockTeacherAccount, theNewDate } = setup(); + const ret = await accountService.updateLastTriedFailedLogin(mockTeacherAccount.id, theNewDate); - expect(ret).toBeDefined(); - expect(ret).toMatchObject({ - ...mockTeacherAccount.getProps(), - lasttriedFailedLogin: theNewDate, - }); - }); + expect(ret.lasttriedFailedLogin).toEqual(theNewDate); }); }); diff --git a/apps/server/src/modules/account/domain/services/account.service.spec.ts b/apps/server/src/modules/account/domain/services/account.service.spec.ts index 4c4b4866776..e8cf43dbe1e 100644 --- a/apps/server/src/modules/account/domain/services/account.service.spec.ts +++ b/apps/server/src/modules/account/domain/services/account.service.spec.ts @@ -569,6 +569,14 @@ describe('AccountService', () => { }); }); + describe('updateFailedLogin', () => { + it('should call updateLastLogin in accountServiceDb', async () => { + await accountService.updateLastLogin('accountId', new Date()); + + expect(accountServiceDb.updateLastLogin).toHaveBeenCalledTimes(1); + }); + }); + describe('updateLastTriedFailedLogin', () => { describe('When calling updateLastTriedFailedLogin in accountService', () => { it('should call updateLastTriedFailedLogin in accountServiceDb', async () => { diff --git a/apps/server/src/modules/authentication/uc/login.uc.spec.ts b/apps/server/src/modules/authentication/uc/login.uc.spec.ts index c0f1d924876..378ee09e0a3 100644 --- a/apps/server/src/modules/authentication/uc/login.uc.spec.ts +++ b/apps/server/src/modules/authentication/uc/login.uc.spec.ts @@ -1,5 +1,6 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; +import { AccountService } from '@src/modules/account'; import { AuthenticationService } from '../services/authentication.service'; import { LoginDto } from './dto'; import { LoginUc } from './login.uc'; @@ -9,6 +10,7 @@ describe('LoginUc', () => { let loginUc: LoginUc; let authenticationService: DeepMocked; + let accountService: DeepMocked; beforeAll(async () => { module = await Test.createTestingModule({ @@ -18,11 +20,16 @@ describe('LoginUc', () => { provide: AuthenticationService, useValue: createMock(), }, + { + provide: AccountService, + useValue: createMock(), + }, ], }).compile(); loginUc = await module.get(LoginUc); authenticationService = await module.get(AuthenticationService); + accountService = await module.get(AccountService); }); describe('getLoginData', () => { @@ -63,6 +70,14 @@ describe('LoginUc', () => { }); }); + it('should call updateLastLogin', async () => { + const { userInfo } = setup(); + + await loginUc.getLoginData(userInfo); + + expect(accountService.updateLastLogin).toHaveBeenCalledWith(userInfo.accountId, expect.any(Date)); + }); + it('should return a loginDto', async () => { const { userInfo, loginDto } = setup(); From b41f2fec96b160bc9f3c434e2bda7a79ef4a08fb Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Thu, 27 Jun 2024 09:58:46 +0200 Subject: [PATCH 09/12] Remove setting of last login for idm --- .../account/domain/services/account-idm.service.ts | 8 -------- .../modules/account/domain/services/account.service.ts | 10 ++-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/apps/server/src/modules/account/domain/services/account-idm.service.ts b/apps/server/src/modules/account/domain/services/account-idm.service.ts index 296518e4319..766a159b0cb 100644 --- a/apps/server/src/modules/account/domain/services/account-idm.service.ts +++ b/apps/server/src/modules/account/domain/services/account-idm.service.ts @@ -85,14 +85,6 @@ export class AccountServiceIdm extends AbstractAccountService { return [accounts, total]; } - async updateLastLogin(accountId: EntityId, lastLogin: Date): Promise { - const attributeName = 'lastLogin'; - const id = await this.getIdmAccountId(accountId); - await this.identityManager.setUserAttribute(id, attributeName, lastLogin.toISOString()); - const updatedAccount = await this.identityManager.findAccountById(id); - return this.accountIdmToDoMapper.mapToDo(updatedAccount); - } - async updateLastTriedFailedLogin(accountId: EntityId, lastTriedFailedLogin: Date): Promise { const attributeName = 'lastTriedFailedLogin'; const id = await this.getIdmAccountId(accountId); diff --git a/apps/server/src/modules/account/domain/services/account.service.ts b/apps/server/src/modules/account/domain/services/account.service.ts index 1ee784164df..f1ecb8a7f96 100644 --- a/apps/server/src/modules/account/domain/services/account.service.ts +++ b/apps/server/src/modules/account/domain/services/account.service.ts @@ -357,14 +357,8 @@ export class AccountService extends AbstractAccountService implements DeletionSe return new Account({ ...ret.getProps(), idmReferenceId: idmAccount?.idmReferenceId }); } - async updateLastLogin(accountId: string, lastLogin: Date): Promise { - const ret = await this.accountDb.updateLastLogin(accountId, lastLogin); - const idmAccount = await this.executeIdmMethod(async () => { - const account = await this.accountIdm.updateLastLogin(accountId, lastLogin); - return account; - }); - - return new Account({ ...ret.getProps(), idmReferenceId: idmAccount?.idmReferenceId }); + async updateLastLogin(accountId: string, lastLogin: Date): Promise { + await this.accountDb.updateLastLogin(accountId, lastLogin); } async updateLastTriedFailedLogin(accountId: string, lastTriedFailedLogin: Date): Promise { From 78d0e8aba7db247b42a358414c86d1f2736a52be Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Thu, 27 Jun 2024 11:45:17 +0200 Subject: [PATCH 10/12] Call auth service instead of account service from uc --- .../modules/authentication/authentication-api.module.ts | 3 +-- .../services/authentication.service.spec.ts | 8 ++++++++ .../authentication/services/authentication.service.ts | 4 ++++ .../src/modules/authentication/uc/login.uc.spec.ts | 9 +-------- apps/server/src/modules/authentication/uc/login.uc.ts | 6 ++---- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/apps/server/src/modules/authentication/authentication-api.module.ts b/apps/server/src/modules/authentication/authentication-api.module.ts index e2f7c9a44de..6780e5fe11c 100644 --- a/apps/server/src/modules/authentication/authentication-api.module.ts +++ b/apps/server/src/modules/authentication/authentication-api.module.ts @@ -1,11 +1,10 @@ import { Module } from '@nestjs/common'; -import { AccountModule } from '../account'; import { AuthenticationModule } from './authentication.module'; import { LoginController } from './controllers/login.controller'; import { LoginUc } from './uc/login.uc'; @Module({ - imports: [AuthenticationModule, AccountModule], + imports: [AuthenticationModule], providers: [LoginUc], controllers: [LoginController], exports: [], diff --git a/apps/server/src/modules/authentication/services/authentication.service.spec.ts b/apps/server/src/modules/authentication/services/authentication.service.spec.ts index 51f10a7109a..32d6850f243 100644 --- a/apps/server/src/modules/authentication/services/authentication.service.spec.ts +++ b/apps/server/src/modules/authentication/services/authentication.service.spec.ts @@ -179,6 +179,14 @@ describe('AuthenticationService', () => { }); }); + describe('updateLastLogin', () => { + it('should call accountService to update last login', async () => { + await authenticationService.updateLastLogin('mockAccountId'); + + expect(accountService.updateLastLogin).toHaveBeenCalledWith('mockAccountId', expect.any(Date)); + }); + }); + describe('normalizeUsername', () => { describe('when a username is entered', () => { it('should trim username', () => { diff --git a/apps/server/src/modules/authentication/services/authentication.service.ts b/apps/server/src/modules/authentication/services/authentication.service.ts index 4a2b816b1e9..124a4c419b8 100644 --- a/apps/server/src/modules/authentication/services/authentication.service.ts +++ b/apps/server/src/modules/authentication/services/authentication.service.ts @@ -79,6 +79,10 @@ export class AuthenticationService { } } + async updateLastLogin(accountId: string): Promise { + await this.accountService.updateLastLogin(accountId, new Date()); + } + async updateLastTriedFailedLogin(id: string): Promise { await this.accountService.updateLastTriedFailedLogin(id, new Date()); } diff --git a/apps/server/src/modules/authentication/uc/login.uc.spec.ts b/apps/server/src/modules/authentication/uc/login.uc.spec.ts index 378ee09e0a3..4b0d356402a 100644 --- a/apps/server/src/modules/authentication/uc/login.uc.spec.ts +++ b/apps/server/src/modules/authentication/uc/login.uc.spec.ts @@ -1,6 +1,5 @@ import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; -import { AccountService } from '@src/modules/account'; import { AuthenticationService } from '../services/authentication.service'; import { LoginDto } from './dto'; import { LoginUc } from './login.uc'; @@ -10,7 +9,6 @@ describe('LoginUc', () => { let loginUc: LoginUc; let authenticationService: DeepMocked; - let accountService: DeepMocked; beforeAll(async () => { module = await Test.createTestingModule({ @@ -20,16 +18,11 @@ describe('LoginUc', () => { provide: AuthenticationService, useValue: createMock(), }, - { - provide: AccountService, - useValue: createMock(), - }, ], }).compile(); loginUc = await module.get(LoginUc); authenticationService = await module.get(AuthenticationService); - accountService = await module.get(AccountService); }); describe('getLoginData', () => { @@ -75,7 +68,7 @@ describe('LoginUc', () => { await loginUc.getLoginData(userInfo); - expect(accountService.updateLastLogin).toHaveBeenCalledWith(userInfo.accountId, expect.any(Date)); + expect(authenticationService.updateLastLogin).toHaveBeenCalledWith(userInfo.accountId); }); it('should return a loginDto', async () => { diff --git a/apps/server/src/modules/authentication/uc/login.uc.ts b/apps/server/src/modules/authentication/uc/login.uc.ts index ed55ec5465f..a676e0d79d3 100644 --- a/apps/server/src/modules/authentication/uc/login.uc.ts +++ b/apps/server/src/modules/authentication/uc/login.uc.ts @@ -1,5 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { AccountService } from '@src/modules/account'; import { ICurrentUser } from '../interface'; import { CreateJwtPayload } from '../interface/jwt-payload'; import { CurrentUserMapper } from '../mapper'; @@ -8,15 +7,14 @@ import { LoginDto } from './dto'; @Injectable() export class LoginUc { - constructor(private readonly authService: AuthenticationService, private readonly accountService: AccountService) {} + constructor(private readonly authService: AuthenticationService) {} async getLoginData(userInfo: ICurrentUser): Promise { const createJwtPayload: CreateJwtPayload = CurrentUserMapper.mapCurrentUserToCreateJwtPayload(userInfo); const accessTokenDto: LoginDto = await this.authService.generateJwt(createJwtPayload); - const now = new Date(); - await this.accountService.updateLastLogin(userInfo.accountId, now); + await this.authService.updateLastLogin(userInfo.accountId); const loginDto: LoginDto = new LoginDto({ accessToken: accessTokenDto.accessToken, From be1101f7efe6cb58b9a0dd7f14ed6b38244d9df7 Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Thu, 27 Jun 2024 11:50:01 +0200 Subject: [PATCH 11/12] Fix typo --- .../src/modules/account/domain/services/account.service.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/modules/account/domain/services/account.service.spec.ts b/apps/server/src/modules/account/domain/services/account.service.spec.ts index f30306c8061..739d2942931 100644 --- a/apps/server/src/modules/account/domain/services/account.service.spec.ts +++ b/apps/server/src/modules/account/domain/services/account.service.spec.ts @@ -579,7 +579,7 @@ describe('AccountService', () => { }); }); - describe('updateFailedLogin', () => { + describe('updateLastLogin', () => { it('should call updateLastLogin in accountServiceDb', async () => { await accountService.updateLastLogin('accountId', new Date()); From ec8255e2d8db5ce9ff6fb9e314f3855b225ec8d8 Mon Sep 17 00:00:00 2001 From: dyedwiper Date: Thu, 27 Jun 2024 12:16:02 +0200 Subject: [PATCH 12/12] Change param in test --- .../modules/account/domain/services/account.service.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/account/domain/services/account.service.spec.ts b/apps/server/src/modules/account/domain/services/account.service.spec.ts index 739d2942931..77d9d7ebf35 100644 --- a/apps/server/src/modules/account/domain/services/account.service.spec.ts +++ b/apps/server/src/modules/account/domain/services/account.service.spec.ts @@ -581,7 +581,9 @@ describe('AccountService', () => { describe('updateLastLogin', () => { it('should call updateLastLogin in accountServiceDb', async () => { - await accountService.updateLastLogin('accountId', new Date()); + const someId = new ObjectId().toHexString(); + + await accountService.updateLastLogin(someId, new Date()); expect(accountServiceDb.updateLastLogin).toHaveBeenCalledTimes(1); });