Skip to content

Commit

Permalink
feat: delete account - partial for review (#263)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrew Radulescu <[email protected]>
  • Loading branch information
radulescuandrew and Andrew Radulescu authored Dec 18, 2023
1 parent 7237710 commit bc7f35e
Show file tree
Hide file tree
Showing 28 changed files with 12,602 additions and 1,299 deletions.
13,572 changes: 12,275 additions & 1,297 deletions backend/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
},
"dependencies": {
"@anchan828/typeorm-history": "1.0.38",
"@aws-sdk/client-cognito-identity-provider": "^3.474.0",
"@aws-sdk/client-s3": "^3.325.0",
"@aws-sdk/s3-request-presigner": "^3.325.0",
"@bull-board/api": "^4.11.0",
Expand Down
10 changes: 10 additions & 0 deletions backend/src/api/_mobile/user/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
Body,
Controller,
Delete,
Get,
Patch,
Post,
Expand All @@ -22,6 +23,7 @@ import { UpdateRegularUserUsecase } from 'src/usecases/user/update-regular-user.
import { FileFieldsInterceptor } from '@nestjs/platform-express';
import { GetOneRegularUserProfileUseCase } from 'src/usecases/user/get-regule-user-profile.usecase';
import { UserProfilePresenter } from './presenters/user-profile.presenter';
import { DeleteAccountRegularUserUsecase } from 'src/usecases/user/delete-account.usecase';

@ApiBearerAuth()
@UseGuards(MobileJwtAuthGuard)
Expand All @@ -32,6 +34,7 @@ export class MobileRegularUserController {
private readonly getOneRegularUserProfileUseCase: GetOneRegularUserProfileUseCase,
private readonly updateUserPersonalData: UpdateUserPersonalDataUsecase,
private readonly updateRegularUserUsecase: UpdateRegularUserUsecase,
private readonly deleteAccountRegularUserUsecase: DeleteAccountRegularUserUsecase,
) {}

@ApiBody({ type: CreateRegularUserDto })
Expand Down Expand Up @@ -90,4 +93,11 @@ export class MobileRegularUserController {
);
return new UserPresenter(updatedUser);
}

@Delete()
async deleteUserData(
@ExtractUser() regularUser: IRegularUserModel,
): Promise<void> {
return this.deleteAccountRegularUserUsecase.execute(regularUser.id);
}
}
3 changes: 3 additions & 0 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { NotificationsModule } from './modules/notifications/notifications.modul
import { UserModule } from './modules/user/user.module';
import {
CacheProviderModule,
CognitoProviderModule,
DatabaseProviderModule,
QueueProviderModule,
ThrottleModule,
Expand All @@ -39,6 +40,8 @@ import { ExpoPushNotificationsProviderModule } from './infrastructure/providers/
ThrottleModule,
S3ProviderModule,
ExpoPushNotificationsProviderModule,
CognitoProviderModule,

// Modules
MailModule,
AuthenticationModule,
Expand Down
21 changes: 21 additions & 0 deletions backend/src/infrastructure/config/cognito.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as dotenv from 'dotenv';
import { CognitoModuleOptions } from '../providers/cognito/module/cognito.interfaces';

dotenv.config();

Expand Down Expand Up @@ -35,3 +38,21 @@ export function getCognitoProperty<Property extends keyof CognitoConfig>(
): CognitoConfig[Property] {
return ConfigEnvKeys[target][property];
}

// Service to configure the CognitoModule for Mobile
@Injectable()
export class CognitoConfigService {
constructor(private configService: ConfigService) {}

createCognitoConfigOptions(): CognitoModuleOptions {
return {
accessKeyId: this.configService.get('AWS_ACCESS_KEY_ID'),
secretAccessKey: this.configService.get('AWS_SECRET_ACCESS_KEY'),
region: this.configService.get('AWS_REGION'),
defaultUserPoolId: getCognitoProperty(
CognitoConfigType.MOBILE,
'userPoolId',
),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Global, Module } from '@nestjs/common';
import { CognitoModule } from './module/cognito.module';
import { CognitoConfigService } from 'src/infrastructure/config/cognito.config';

@Global()
@Module({
imports: [
CognitoModule.registerAsync({
useClass: CognitoConfigService,
}),
],
exports: [CognitoModule],
})
export class CognitoProviderModule {}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface CognitoModuleOptions {
accessKeyId: string;
secretAccessKey: string;
region: string;
defaultUserPoolId: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ConfigurableModuleBuilder } from '@nestjs/common';
import { CognitoModuleOptions } from './cognito.interfaces';

export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } =
new ConfigurableModuleBuilder<CognitoModuleOptions>()
.setExtras(
{
isGlobal: true,
},
(definition, extras) => ({
...definition,
global: extras.isGlobal,
}),
)
.setFactoryMethodName('createCognitoConfigOptions')
.build();
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { ConfigurableModuleClass } from './cognito.module-definition';
import { CognitoService } from './cognito.service';

@Module({
providers: [CognitoService],
exports: [CognitoService],
})
export class CognitoModule extends ConfigurableModuleClass {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Inject, Injectable, Logger } from '@nestjs/common';
import { MODULE_OPTIONS_TOKEN } from './cognito.module-definition';
import { CognitoModuleOptions } from './cognito.interfaces';
import {
AdminDeleteUserCommand,
AdminUserGlobalSignOutCommand,
CognitoIdentityProviderClient,
} from '@aws-sdk/client-cognito-identity-provider';

@Injectable()
export class CognitoService {
private readonly logger = new Logger(CognitoService.name);
private readonly cognitoProvider: CognitoIdentityProviderClient;

constructor(
@Inject(MODULE_OPTIONS_TOKEN) private options: CognitoModuleOptions,
) {
this.cognitoProvider = new CognitoIdentityProviderClient({
credentials: {
accessKeyId: this.options.accessKeyId,
secretAccessKey: this.options.secretAccessKey,
},
region: options.region,
});
}

async deleteUser(cognitoId: string): Promise<unknown> {
const deleteUserCommand = new AdminDeleteUserCommand({
UserPoolId: this.options.defaultUserPoolId,
Username: cognitoId,
});

return this.cognitoProvider.send(deleteUserCommand);
}

async globalSignOut(cognitoId: string): Promise<unknown> {
const revokeTokenCommand = new AdminUserGlobalSignOutCommand({
UserPoolId: this.options.defaultUserPoolId,
Username: cognitoId,
});

const data = await this.cognitoProvider.send(revokeTokenCommand);
return data;
}
}
1 change: 1 addition & 0 deletions backend/src/infrastructure/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './database/database-provider.module';
export * from './mail/mail-provider.module';
export * from './throttle/throttle.module';
export * from './queue/queue-provider.module';
export * from './cognito/cognito-provider.module';
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,8 @@ export class AccessRequestRepository

return null;
}

async deleteAllForUser(userId: string): Promise<void> {
await this.accessRequestRepository.delete({ requestedById: userId });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@ export class AccessRequestFacade {
async delete(id: string): Promise<string> {
return this.accessRequestRepository.delete(id);
}

async deleteAllForUser(userId: string): Promise<void> {
return this.accessRequestRepository.deleteAllForUser(userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,8 @@ export class ActivityLogRepositoryService

return null;
}

async deleteMany(ids: string[]): Promise<void> {
await this.activityLogRepo.delete(ids);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,8 @@ export class ActivityLogFacade {
async delete(id: string): Promise<string> {
return this.activityLogRepository.delete(id);
}

async deleteMany(ids: string[]): Promise<void> {
return this.activityLogRepository.deleteMany(ids);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export class EventRSVPRepository
return null;
}

async deleteAllRSVPsForUser(userId: string): Promise<void> {
await this.rsvpRepository.delete({ userId });
}

async findMany(
findOptions: FindManyEventRSVPOptions,
): Promise<Pagination<IEventRSVPModel>> {
Expand Down
4 changes: 4 additions & 0 deletions backend/src/modules/event/services/event.facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export class EventFacade {
return this.rsvpRepository.delete(id);
}

async deleteAllRSVPsForUser(userId: string): Promise<void> {
return this.rsvpRepository.deleteAllRSVPsForUser(userId);
}

async findManyRSVP(
findOptions: FindManyEventRSVPOptions,
): Promise<Pagination<IEventRSVPModel>> {
Expand Down
4 changes: 4 additions & 0 deletions backend/src/modules/notifications/notifications.facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,8 @@ export class PushNotificationsFacade {
async delete(options: DeletePushTokenOptions): Promise<string> {
return this.pushTokensRepository.delete(options);
}

async deleteMany(options: DeletePushTokenOptions): Promise<void> {
return this.pushTokensRepository.deleteMany(options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,8 @@ export class PushTokensRepository implements IPushTokensRepository {

return null;
}

async deleteMany(options: DeletePushTokenOptions): Promise<void> {
await this.pushTokensRepository.delete(options);
}
}
14 changes: 14 additions & 0 deletions backend/src/modules/user/repositories/regular-user.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,18 @@ export class RegularUserRepositoryService implements IRegularUserRepository {

return userEntity ? RegularUserTransformer.fromEntity(userEntity) : null;
}

async softDeleteAndAnonimize(id: string): Promise<IRegularUserModel> {
const userToUpdate = await this.regularUserRepository.preload({
id,
firstName: 'Deleted',
lastName: 'Deleted',
email: `account-deleted@${new Date().getTime()}.ro`,
phone: 'Deleted',
});

await this.regularUserRepository.save(userToUpdate);

return this.find({ id });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,17 @@ export class UserPersonalDataRepository implements IUserPersonalDataRepository {

return UserPersonalDataTransformer.fromEntity(userPersonalDataEntity);
}

public async delete(id: string): Promise<string> {
const data = await this.userPersonalDataRepository.findOne({
where: { id },
});

if (data) {
await this.userPersonalDataRepository.remove(data);
return data.id;
}

return null;
}
}
10 changes: 10 additions & 0 deletions backend/src/modules/user/services/user-facade.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ export class UserFacadeService {
return this.regularUserRepository.find(options);
}

public async softDeleteAndAnonimizeRegularUser(
id: string,
): Promise<IRegularUserModel> {
return this.regularUserRepository.softDeleteAndAnonimize(id);
}

public async createUserPersonalData(
userPersonalDataModel: CreateUserPersonalDataOptions,
): Promise<IUserPersonalDataModel> {
Expand All @@ -79,6 +85,10 @@ export class UserFacadeService {
return this.userPersonalDataRepository.update(id, updates);
}

public async deleteUserPersonalData(id: string): Promise<string> {
return this.userPersonalDataRepository.delete(id);
}

public async findUserPersonalData(
findOptions: FindUserPersonalDataOptions,
): Promise<IUserPersonalDataModel> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ export class VolunteerProfileRepositoryService
constructor(
@InjectRepository(VolunteerProfileEntity)
private readonly volunteerProfileRepository: Repository<VolunteerProfileEntity>,
@InjectRepository(VolunteerEntity)
private readonly volunteerRepository: Repository<VolunteerEntity>,
private readonly volunteerRepositoryService: VolunteerRepositoryService,
) {}

Expand Down Expand Up @@ -59,4 +57,8 @@ export class VolunteerProfileRepositoryService

return VolunteerProfileModelTransformer.fromEntity(profile);
}

async delete(id: string): Promise<void> {
await this.volunteerProfileRepository.delete(id);
}
}
Loading

0 comments on commit bc7f35e

Please sign in to comment.