Skip to content

Commit

Permalink
feat: delete-account - done
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Radulescu committed Dec 19, 2023
1 parent a6e26eb commit 71cd9fc
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ export class ActivityLogRepositoryService
return null;
}

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

async deleteMany(ids: string[]): Promise<void> {
return this.activityLogRepository.deleteMany(ids);
async deleteManyByVolunteerId(volunteerId: string): Promise<void> {
return this.activityLogRepository.deleteManyByVolunteerId(volunteerId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class ContractRepositoryService

const query = this.contractRepository
.createQueryBuilder('contract')
.withDeleted()
.leftJoinAndMapOne(
'contract.organization',
'contract.organization',
Expand Down Expand Up @@ -187,6 +188,7 @@ export class ContractRepositoryService
template: true,
createdByAdmin: true,
},
withDeleted: true,
});

return ContractTransformer.fromEntity(contract);
Expand Down
5 changes: 5 additions & 0 deletions backend/src/modules/user/exceptions/exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum UserExceptionCodes {
USER_004 = 'USER_004',
USER_005 = 'USER_005',
USER_006 = 'USER_006',
USER_007 = 'USER_007',
}

type UserExceptionCodeType = keyof typeof UserExceptionCodes;
Expand Down Expand Up @@ -40,4 +41,8 @@ export const UserExceptionMessages: Record<
code_error: UserExceptionCodes.USER_006,
message: 'Error while uploading profile picture in s3',
},
[UserExceptionCodes.USER_007]: {
code_error: UserExceptionCodes.USER_007,
message: 'Error while trying to delete user account',
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,15 @@ export class RegularUserRepositoryService implements IRegularUserRepository {
lastName: 'Deleted',
email: `account-deleted@${new Date().getTime()}.ro`,
phone: 'Deleted',
name: 'Deleted',
birthday: new Date(),
userPersonalDataId: null,
});

await this.regularUserRepository.save(userToUpdate);
const updated = await this.regularUserRepository.save(userToUpdate);

return this.find({ id });
await this.regularUserRepository.softDelete({ id: userToUpdate.id });

return updated ? RegularUserTransformer.fromEntity(updated) : null;
}
}
29 changes: 18 additions & 11 deletions backend/src/modules/volunteer/repositories/volunteer.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,26 +311,33 @@ export class VolunteerRepositoryService
relations: { volunteerProfile: true },
});

let deletedProfiles;
// Anonimize emails before soft delete
await this.volunteerProfileRepository.update(
volunteerRecords.map((v) => v.volunteerProfile.id),
{
email: `account-deleted@${new Date().getTime()}.ro`,
},
const volunteerRecordsToDelete = volunteerRecords.filter(
(v) => v.volunteerProfile?.id,
);

// Soft Delete all associated profiles
const deletedProfiles = await this.volunteerProfileRepository.softRemove(
volunteerRecords.map((v) => v.volunteerProfile),
);
if (volunteerRecordsToDelete.length) {
await this.volunteerProfileRepository.update(
volunteerRecordsToDelete.map((v) => v.volunteerProfile.id),
{
email: `account-deleted@${new Date().getTime()}.ro`,
},
);

// Soft Delete all associated profiles
deletedProfiles = await this.volunteerProfileRepository.softRemove(
volunteerRecordsToDelete,
);
}

const deletedVolunteerRecords = await this.volunteerRepository.softRemove(
volunteerRecords,
);

return {
deletedProfiles: deletedProfiles.map((dp) => dp.id),
deletedVolunteers: deletedVolunteerRecords.map((dvr) => dvr.id),
deletedProfiles: deletedProfiles?.map((dp) => dp.id) || [],
deletedVolunteers: deletedVolunteerRecords?.map((dvr) => dvr.id) || [],
};
}

Expand Down
64 changes: 36 additions & 28 deletions backend/src/usecases/user/delete-account.usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IVolunteerModel } from 'src/modules/volunteer/model/volunteer.model';
import { ActivityLogFacade } from 'src/modules/activity-log/services/activity-log.facade';
import { AccessRequestFacade } from 'src/modules/access-request/services/access-request.facade';
import { EventFacade } from 'src/modules/event/services/event.facade';
import { JSONStringifyError } from 'src/common/helpers/utils';

@Injectable()
export class DeleteAccountRegularUserUsecase implements IUseCaseService<void> {
Expand Down Expand Up @@ -39,41 +40,48 @@ export class DeleteAccountRegularUserUsecase implements IUseCaseService<void> {
this.exceptionService.notFoundException(UserExceptionMessages.USER_001);
}

// // 1. Delete cognito user
await this.cognitoService.globalSignOut(user.cognitoId);
await this.cognitoService.deleteUser(user.cognitoId);
try {
// 1. Delete cognito user
await this.cognitoService.globalSignOut(user.cognitoId);
await this.cognitoService.deleteUser(user.cognitoId);

/* ======================================================= */
/* =========FULL IMPLEMENTATION UNTESTED ================= */
/* ======================================================= */
// 2. Hard delete all "PushTokens"
await this.pushNotificationService.deleteMany({ userId });

// 2. Hard delete all "PushTokens"
await this.pushNotificationService.deleteMany({ userId });
// 3. Hard delete "UserPersonalData"
if (user.userPersonalData?.id) {
await this.userService.deleteUserPersonalData(user.userPersonalData.id);
}
// 3. Soft delete all Volunteers Records and the associated Profiles for the given UserId
const deletedVolunteersAndProfiles =
await this.volunteerFacade.softDeleteManyAndProfiles(userId);

// 4. Hard delete all Volunteers Records and the associated Profiles for the given UserId
const deletedVolunteersAndProfiles =
await this.volunteerFacade.softDeleteManyAndProfiles(userId);
// 4. Delete activity logs related to this user (linked with his Volunteer Records)
for (const volunteerId of deletedVolunteersAndProfiles.deletedVolunteers) {
await this.activityLogFacade.deleteManyByVolunteerId(volunteerId);
}

// Delete activity logs related to this user
await this.activityLogFacade.deleteMany(
deletedVolunteersAndProfiles.deletedVolunteers,
);
// 5. Delete all access requests made by the user
await this.accessRequestFacade.deleteAllForUser(userId);

// Delete all access requests made by the user
await this.accessRequestFacade.deleteAllForUser(userId);
// 6. Delete all RSVPs to events for the user
await this.eventFacade.deleteAllRSVPsForUser(userId);

// Delete all RSVPs to events for the user
await this.eventFacade.deleteAllRSVPsForUser(userId);
// 7. "User" - Anonimize + Soft delete + Delete profile picture
const deletedUser =
await this.userService.softDeleteAndAnonimizeRegularUser(userId);
if (deletedUser.profilePicture) {
await this.s3Service.deleteFile(deletedUser.profilePicture);
}

// 4. "User" - Anonimize + Soft delete + Delete profile picture
const deletedUser =
await this.userService.softDeleteAndAnonimizeRegularUser(userId);
if (deletedUser.profilePicture) {
await this.s3Service.deleteFile(deletedUser.profilePicture);
// 8. Hard delete "UserPersonalData"
if (user.userPersonalData?.id) {
await this.userService.deleteUserPersonalData(user.userPersonalData.id);
}
} catch (error) {
this.logger.error({
...UserExceptionMessages.USER_007,
error: JSONStringifyError(error),
});
this.exceptionService.internalServerErrorException(
UserExceptionMessages.USER_007,
);
}

return;
Expand Down
1 change: 1 addition & 0 deletions mobile/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const expoConfig: ExpoConfig = {
policyLink: process.env.EXPO_PUBLIC_PRIVACY_POLICY_LINK,
termsLink: process.env.EXPO_PUBLIC_TERMS_AND_CONDITIONS_LINK,
infoLink: process.env.EXPO_PUBLIC_INFORMATION_LINK,
contactEmail: process.env.EXPO_PUBLIC_CONTACT_EMAIL,
},
updates: {
url: 'https://u.expo.dev/6aaad982-5a5c-4af8-b66c-7689afe74e1f',
Expand Down
2 changes: 1 addition & 1 deletion mobile/src/assets/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,6 @@
"title": "Confirm account deletion",
"paragraph": "To delete your account on the VIC application, please confirm your decision below. Deleting your account will result in the permanent loss of your data and access to the application. If you are certain about this action, click the 'Confirm Deletion' button. Keep in mind that this process is irreversible, and you will need to create a new account if you wish to use VIC in the future.",
"confirm": "Confirm Deletion",
"error": "Error on account deletion."
"error": "There was an error trying to delete your account. Please contact us at {{value}} to finalize the process."
}
}
2 changes: 1 addition & 1 deletion mobile/src/assets/locales/ro/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,6 @@
"title": "Confirma ștergerea contului",
"paragraph": "Pentru a șterge contul tău în aplicația VIC, te rugăm să confirmi decizia mai jos. Ștergerea contului va duce la pierderea permanentă a datelor tale și a accesului la aplicație. Dacă ești sigur în privința acestei acțiuni, apasă butonul 'Confirmă Ștergerea'. Menționează că acest proces este ireversibil și va trebui să creezi un cont nou dacă dorești să utilizezi VIC în viitor.",
"confirm": "Confirmă Ștergerea",
"error": "Eroare la stergerea contului"
"error": "A aparut o eroare la stergerea contului. Contacteaza-ne la adresa de e-mail {{value}}, si te vom ajuta sa finalizezi procesul."
}
}
3 changes: 2 additions & 1 deletion mobile/src/screens/DeleteAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next';
import FormLayout from '../layouts/FormLayout';
import { useDeleteAccountMutation } from '../services/user/user.service';
import { useAuth } from '../hooks/useAuth';
import Constants from 'expo-constants';

const DeleteAccount = ({ navigation }: any) => {
const { t } = useTranslation('delete_account');
Expand Down Expand Up @@ -48,7 +49,7 @@ const DeleteAccount = ({ navigation }: any) => {
style={{ color: theme['color-danger-500'] }}
category="p1"
>
{`${t('error')}`}
{`${t('error', { value: Constants.expoConfig?.extra?.contactEmail })}`}
</Text>
)}
</FormLayout>
Expand Down

0 comments on commit 71cd9fc

Please sign in to comment.