From 4578ec27e1115125e163fbe8e458451d29910fb1 Mon Sep 17 00:00:00 2001 From: Abraham <1001.28021547.ucla@gmail.com> Date: Tue, 13 May 2025 15:54:51 -0400 Subject: [PATCH 1/5] add flags to user entity --- src/user/entities/user.entity.ts | 6 +++++ ...47165866071-add-flags-to-user-migration.ts | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/user/migrations/1747165866071-add-flags-to-user-migration.ts diff --git a/src/user/entities/user.entity.ts b/src/user/entities/user.entity.ts index 86cadb6..d9fdf18 100644 --- a/src/user/entities/user.entity.ts +++ b/src/user/entities/user.entity.ts @@ -96,4 +96,10 @@ export class User extends BaseModel { @Column({ type: 'character varying', name: 'ws_id', nullable: true }) wsId: string | undefined; + + @Column({ type: 'boolean', default: false, name: 'is_mobile_customer' }) + isMobileCustomer: boolean; + + @Column({ type: 'boolean', default: true, name: 'is_generic_password' }) + isGenericPassword: boolean; } diff --git a/src/user/migrations/1747165866071-add-flags-to-user-migration.ts b/src/user/migrations/1747165866071-add-flags-to-user-migration.ts new file mode 100644 index 0000000..c93d41a --- /dev/null +++ b/src/user/migrations/1747165866071-add-flags-to-user-migration.ts @@ -0,0 +1,25 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddFlagsToUserMigration1747165866071 + implements MigrationInterface +{ + name = 'AddFlagsToUserMigration1747165866071'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "user" ADD "is_mobile_customer" boolean NOT NULL DEFAULT false`, + ); + await queryRunner.query( + `ALTER TABLE "user" ADD "is_generic_password" boolean NOT NULL DEFAULT true`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "user" DROP COLUMN "is_generic_password"`, + ); + await queryRunner.query( + `ALTER TABLE "user" DROP COLUMN "is_mobile_customer"`, + ); + } +} From e6f5cf9c18ba9a47cc718d8363e86937914b22ff Mon Sep 17 00:00:00 2001 From: Abraham <1001.28021547.ucla@gmail.com> Date: Wed, 14 May 2025 15:26:13 -0400 Subject: [PATCH 2/5] imports AuthModule, UserModule and BranchModule --- src/auth/auth.module.ts | 2 ++ src/branch/branch.module.ts | 5 +++-- src/user/dto/user.dto.ts | 10 ++++++++++ src/user/user.module.ts | 2 ++ src/user/user.service.ts | 15 +++++++++++++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index f24662b..f7e9789 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -7,10 +7,12 @@ import { ConfigModule, ConfigService } from '@nestjs/config'; import { UserService } from 'src/user/user.service'; import { EmailModule } from 'src/email/email.module'; import { AuthGuard } from './auth.guard'; +import { BranchModule } from 'src/branch/branch.module'; @Module({ imports: [ forwardRef(() => UserModule), + forwardRef(() => BranchModule), ConfigModule, JwtModule.registerAsync({ useFactory: (configService: ConfigService) => ({ diff --git a/src/branch/branch.module.ts b/src/branch/branch.module.ts index 09693be..46e7bd2 100644 --- a/src/branch/branch.module.ts +++ b/src/branch/branch.module.ts @@ -1,4 +1,4 @@ -import { Module } from '@nestjs/common'; +import { forwardRef, Module } from '@nestjs/common'; import { BranchService } from './branch.service'; import { BranchController } from './branch.controller'; import { TypeOrmModule } from '@nestjs/typeorm'; @@ -14,9 +14,10 @@ import { State } from 'src/state/entities/state.entity'; @Module({ imports: [ TypeOrmModule.forFeature([Branch, City, State, Country]), - AuthModule, + forwardRef(() => AuthModule), ], controllers: [BranchController], providers: [BranchService, CityService, StateService, CountryService], + exports: [BranchService], }) export class BranchModule {} diff --git a/src/user/dto/user.dto.ts b/src/user/dto/user.dto.ts index 912d564..a9eab9d 100644 --- a/src/user/dto/user.dto.ts +++ b/src/user/dto/user.dto.ts @@ -16,6 +16,7 @@ import { MaxLength, MinLength, IsString, + IsUUID, } from 'class-validator'; import { UserGender } from '../entities/profile.entity'; import { IsOlderThan } from 'src/utils/is-older-than-validator'; @@ -98,6 +99,15 @@ export class UserAdminDTO extends BaseUserDTO { @Expose() role: UserRole; + @ApiProperty({ + description: 'branchId of the user (branch_admin or delivery)', + required: false, + }) + @IsOptional() + @IsUUID() + @Expose() + branchId?: string; + // Data use if it is a delivery @ApiProperty({ description: 'Motorcycle brand', required: false }) diff --git a/src/user/user.module.ts b/src/user/user.module.ts index 8e858e4..ebfd96f 100644 --- a/src/user/user.module.ts +++ b/src/user/user.module.ts @@ -9,6 +9,7 @@ import { AuthModule } from 'src/auth/auth.module'; import { Branch } from 'src/branch/entities/branch.entity'; import { UserAddress } from './entities/user-address.entity'; import { UserMoto } from './entities/user-moto.entity'; +import { BranchModule } from 'src/branch/branch.module'; @Module({ imports: [ @@ -21,6 +22,7 @@ import { UserMoto } from './entities/user-moto.entity'; UserMoto, ]), forwardRef(() => AuthModule), + forwardRef(() => BranchModule), ], providers: [UserService], exports: [UserService, TypeOrmModule], diff --git a/src/user/user.service.ts b/src/user/user.service.ts index d43d58c..6976033 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -16,6 +16,7 @@ import { CreateUserAddressDTO } from './dto/user-address.dto'; import { ConfigService } from '@nestjs/config'; import { UserMoto } from './entities/user-moto.entity'; import { UpdateUserMotoDTO } from './dto/user-moto.dto'; +import { BranchService } from 'src/branch/branch.service'; @Injectable() export class UserService { @@ -31,6 +32,8 @@ export class UserService { @InjectRepository(UserMoto) private UserMotoRepository: Repository, private configService: ConfigService, + + private readonly branchService: BranchService, ) {} async userExists(options: Partial): Promise { @@ -126,6 +129,18 @@ export class UserService { const hashedPassword = await bcrypt.hash(password, 10); const newUser = this.userRepository.create(user); newUser.password = hashedPassword; + if ( + user.role === UserRole.BRANCH_ADMIN || + user.role === UserRole.DELIVERY + ) { + if (!user.branchId) { + throw new BadRequestException('branchId is required for this role'); + } + + const branch = await this.branchService.findOne(user.branchId); + + newUser.branch = branch; + } const userCreated = await this.userRepository.save(newUser); const profile = new Profile(); profile.user = userCreated; From 3dd7df55dcc98a9c73ecad5e858c31e582e3fb84 Mon Sep 17 00:00:00 2001 From: Abraham <1001.28021547.ucla@gmail.com> Date: Wed, 14 May 2025 16:05:40 -0400 Subject: [PATCH 3/5] add send email to the created account --- src/user/user.module.ts | 2 ++ src/user/user.service.ts | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/user/user.module.ts b/src/user/user.module.ts index ebfd96f..cc33946 100644 --- a/src/user/user.module.ts +++ b/src/user/user.module.ts @@ -10,6 +10,7 @@ import { Branch } from 'src/branch/entities/branch.entity'; import { UserAddress } from './entities/user-address.entity'; import { UserMoto } from './entities/user-moto.entity'; import { BranchModule } from 'src/branch/branch.module'; +import { EmailModule } from 'src/email/email.module'; @Module({ imports: [ @@ -23,6 +24,7 @@ import { BranchModule } from 'src/branch/branch.module'; ]), forwardRef(() => AuthModule), forwardRef(() => BranchModule), + EmailModule, ], providers: [UserService], exports: [UserService, TypeOrmModule], diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 6976033..4e2d8b5 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -17,6 +17,7 @@ import { ConfigService } from '@nestjs/config'; import { UserMoto } from './entities/user-moto.entity'; import { UpdateUserMotoDTO } from './dto/user-moto.dto'; import { BranchService } from 'src/branch/branch.service'; +import { EmailService } from 'src/email/email.service'; @Injectable() export class UserService { @@ -34,6 +35,7 @@ export class UserService { private configService: ConfigService, private readonly branchService: BranchService, + private emailService: EmailService, ) {} async userExists(options: Partial): Promise { @@ -142,6 +144,14 @@ export class UserService { newUser.branch = branch; } const userCreated = await this.userRepository.save(newUser); + + await this.emailService.sendEmail({ + recipients: [{ email: user.email, name: user.firstName }], + subject: 'Welcome to Pharmatech', + html: `

Hi, your account has been created. Your password is: ${password}

`, + text: `Hi, your account has been created. Your password is: ${password}`, + }); + const profile = new Profile(); profile.user = userCreated; if (user.gender) { From 64065a098522e54e9540839a1dee25c191742116 Mon Sep 17 00:00:00 2001 From: Abraham <1001.28021547.ucla@gmail.com> Date: Wed, 14 May 2025 17:58:28 -0400 Subject: [PATCH 4/5] fix column isGenericPassword default false --- src/user/entities/user.entity.ts | 2 +- ...tion.ts => 1747259587010-add-flags-to-user-migration.ts} | 6 +++--- src/user/user.service.ts | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) rename src/user/migrations/{1747165866071-add-flags-to-user-migration.ts => 1747259587010-add-flags-to-user-migration.ts} (84%) diff --git a/src/user/entities/user.entity.ts b/src/user/entities/user.entity.ts index d9fdf18..da83a58 100644 --- a/src/user/entities/user.entity.ts +++ b/src/user/entities/user.entity.ts @@ -100,6 +100,6 @@ export class User extends BaseModel { @Column({ type: 'boolean', default: false, name: 'is_mobile_customer' }) isMobileCustomer: boolean; - @Column({ type: 'boolean', default: true, name: 'is_generic_password' }) + @Column({ type: 'boolean', default: false, name: 'is_generic_password' }) isGenericPassword: boolean; } diff --git a/src/user/migrations/1747165866071-add-flags-to-user-migration.ts b/src/user/migrations/1747259587010-add-flags-to-user-migration.ts similarity index 84% rename from src/user/migrations/1747165866071-add-flags-to-user-migration.ts rename to src/user/migrations/1747259587010-add-flags-to-user-migration.ts index c93d41a..b9387c9 100644 --- a/src/user/migrations/1747165866071-add-flags-to-user-migration.ts +++ b/src/user/migrations/1747259587010-add-flags-to-user-migration.ts @@ -1,16 +1,16 @@ import { MigrationInterface, QueryRunner } from 'typeorm'; -export class AddFlagsToUserMigration1747165866071 +export class AddFlagsToUserMigration1747259587010 implements MigrationInterface { - name = 'AddFlagsToUserMigration1747165866071'; + name = 'AddFlagsToUserMigration1747259587010'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query( `ALTER TABLE "user" ADD "is_mobile_customer" boolean NOT NULL DEFAULT false`, ); await queryRunner.query( - `ALTER TABLE "user" ADD "is_generic_password" boolean NOT NULL DEFAULT true`, + `ALTER TABLE "user" ADD "is_generic_password" boolean NOT NULL DEFAULT false`, ); } diff --git a/src/user/user.service.ts b/src/user/user.service.ts index b5ab4b0..a2849ed 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -131,6 +131,7 @@ export class UserService { const hashedPassword = await bcrypt.hash(password, 10); const newUser = this.userRepository.create(user); newUser.password = hashedPassword; + newUser.isGenericPassword = true; if ( user.role === UserRole.BRANCH_ADMIN || user.role === UserRole.DELIVERY From 8a26c90ef882eb1c8a4736c3255754f638e6b52c Mon Sep 17 00:00:00 2001 From: Abraham <1001.28021547.ucla@gmail.com> Date: Wed, 14 May 2025 19:08:23 -0400 Subject: [PATCH 5/5] add isGenericPassword to false when changing password --- src/auth/auth.service.ts | 5 ++++- src/user/dto/user.dto.ts | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 361f257..54ec600 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -92,7 +92,10 @@ export class AuthService { async updatePassword(user: User, newPasswod: string): Promise { const password = await this.encryptPassword(newPasswod); - await this.userService.update(user, { password }); + await this.userService.update(user, { + password, + isGenericPassword: false, + }); return true; } diff --git a/src/user/dto/user.dto.ts b/src/user/dto/user.dto.ts index a9eab9d..fbf5c83 100644 --- a/src/user/dto/user.dto.ts +++ b/src/user/dto/user.dto.ts @@ -17,6 +17,7 @@ import { MinLength, IsString, IsUUID, + IsBoolean, } from 'class-validator'; import { UserGender } from '../entities/profile.entity'; import { IsOlderThan } from 'src/utils/is-older-than-validator'; @@ -89,6 +90,14 @@ export class BaseUserDTO { @IsOptional() @IsEnum(UserGender) gender?: UserGender; + + @IsOptional() + @IsBoolean() + @Expose() + @ApiProperty({ + description: 'Indicates whether the user has a generic password', + }) + isGenericPassword?: boolean; } export class UserDTO extends IntersectionType(BaseUserDTO, PasswordDTO) {}