diff --git a/src/database/migrations/1715028537217-CreateUser.ts b/src/database/migrations/1715028537217-CreateUser.ts index 4cf6a264a..ec4cd46e5 100644 --- a/src/database/migrations/1715028537217-CreateUser.ts +++ b/src/database/migrations/1715028537217-CreateUser.ts @@ -41,7 +41,7 @@ export class CreateUser1715028537217 implements MigrationInterface { `ALTER TABLE "user" ADD CONSTRAINT "FK_dc18daa696860586ba4667a9d31" FOREIGN KEY ("statusId") REFERENCES "status"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, ); await queryRunner.query( - `ALTER TABLE "session" ADD CONSTRAINT "FK_3d2f174ef04fb312fdebd0ddc53" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + `ALTER TABLE "session" ADD CONSTRAINT "FK_3d2f174ef04fb312fdebd0ddc53" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, ); } diff --git a/src/session/infrastructure/persistence/relational/entities/session.entity.ts b/src/session/infrastructure/persistence/relational/entities/session.entity.ts index 15927a549..8127d8792 100644 --- a/src/session/infrastructure/persistence/relational/entities/session.entity.ts +++ b/src/session/infrastructure/persistence/relational/entities/session.entity.ts @@ -21,6 +21,7 @@ export class SessionEntity extends EntityRelationalHelper { @ManyToOne(() => UserEntity, { eager: true, + onDelete: 'CASCADE', }) @Index() user: UserEntity; diff --git a/src/users/infrastructure/persistence/relational/repositories/user.repository.ts b/src/users/infrastructure/persistence/relational/repositories/user.repository.ts index 7bba7e3ef..9c331a4ad 100644 --- a/src/users/infrastructure/persistence/relational/repositories/user.repository.ts +++ b/src/users/infrastructure/persistence/relational/repositories/user.repository.ts @@ -82,6 +82,17 @@ export class UsersRelationalRepository implements UserRepository { return entity ? UserMapper.toDomain(entity) : null; } + + async findByEmailIncludingDeleted(email: User['email']): Promise> { + if (!email) return null; + + const entity = await this.usersRepository.findOne({ + withDeleted: true, + where: { email }, + }); + + return entity ? UserMapper.toDomain(entity) : null; + } async findBySocialIdAndProvider({ socialId, @@ -123,4 +134,12 @@ export class UsersRelationalRepository implements UserRepository { async remove(id: User['id']): Promise { await this.usersRepository.softDelete(id); } + + async removePermanently(id: User['id']): Promise { + await this.usersRepository.delete(id); + } + + async restore(id: User['id']): Promise { + await this.usersRepository.restore(id); + } } diff --git a/src/users/infrastructure/persistence/user.repository.ts b/src/users/infrastructure/persistence/user.repository.ts index 956dbca7a..a47866f9b 100644 --- a/src/users/infrastructure/persistence/user.repository.ts +++ b/src/users/infrastructure/persistence/user.repository.ts @@ -23,6 +23,7 @@ export abstract class UserRepository { abstract findById(id: User['id']): Promise>; abstract findByIds(ids: User['id'][]): Promise; abstract findByEmail(email: User['email']): Promise>; + abstract findByEmailIncludingDeleted(email: User['email']): Promise>; abstract findBySocialIdAndProvider({ socialId, provider, @@ -37,4 +38,6 @@ export abstract class UserRepository { ): Promise; abstract remove(id: User['id']): Promise; + abstract removePermanently(id: User['id']): Promise; + abstract restore(id: User['id']): Promise; } diff --git a/src/users/users.service.ts b/src/users/users.service.ts index b8328569d..46c5345ca 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -40,16 +40,20 @@ export class UsersService { let email: string | null = null; if (createUserDto.email) { - const userObject = await this.usersRepository.findByEmail( + const userObject = await this.usersRepository.findByEmailIncludingDeleted( createUserDto.email, ); if (userObject) { - throw new UnprocessableEntityException({ - status: HttpStatus.UNPROCESSABLE_ENTITY, - errors: { - email: 'emailAlreadyExists', - }, - }); + if (userObject.deletedAt) { + await this.usersRepository.removePermanently(userObject.id); + } else { + throw new UnprocessableEntityException({ + status: HttpStatus.UNPROCESSABLE_ENTITY, + errors: { + email: 'emailAlreadyExists', + }, + }); + } } email = createUserDto.email; }