Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,24 @@ export class AuthService {
}

async signUp(signUpDTO: UserDTO) {
const existingUser = await this.userService.findByEmail(signUpDTO.email);
if (existingUser) {
const emailUsed = await this.userService.userExists({
email: signUpDTO.email,
});
if (emailUsed) {
throw new BadRequestException('The email is already in use');
}

const documentUsed = await this.userService.userExists({
documentId: signUpDTO.documentId,
});
if (documentUsed) {
throw new BadRequestException('The document is already in use');
}
const hashedPassword = await this.encryptPassword(signUpDTO.password);

const newUserData = {
...signUpDTO,
password: hashedPassword,
};

const newUser = await this.userService.create(newUserData);

return plainToInstance(User, newUser);
}

Expand Down
26 changes: 25 additions & 1 deletion src/user/dto/user.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsEmail, IsNotEmpty, MinLength } from 'class-validator';
import {
IsDateString,
IsEmail,
IsEnum,
IsNotEmpty,
MinLength,
} from 'class-validator';
import { UserGender } from '../entities/profile.entity';

export class UserDTO {
@ApiProperty({ description: 'The name of the user' })
Expand Down Expand Up @@ -30,4 +37,21 @@ export class UserDTO {
@ApiProperty({ description: 'the phone number of the user' })
@IsNotEmpty()
phoneNumber: string;

@ApiProperty({ description: 'the birth date of the user' })
@Transform(
({ value }: { value: string }) =>
new Date(value).toISOString().split('T')[0],
)
@IsNotEmpty()
@IsDateString(
{ strict: true },
{ message: 'birthDate must be a valid date in YYYY-MM-DD format' },
)
birthDate: string;

@ApiProperty({ description: 'the gender of the user' })
@IsNotEmpty()
@IsEnum(UserGender)
gender: UserGender;
}
24 changes: 24 additions & 0 deletions src/user/entities/profile.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Entity, Column, OneToOne, JoinColumn } from 'typeorm';
import { UUIDModel } from 'src/utils/entity';
import { User } from './user.entity';

export enum UserGender {
MALE = 'm',
FEMALE = 'f',
}

@Entity()
export class Profile extends UUIDModel {
@OneToOne(() => User, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'user_id' })
user: User;

@Column({ type: 'text', name: 'profile_picture', nullable: true })
profilePicture: string;

@Column({ type: 'date', name: 'birth_date' })
birthDate: Date;

@Column({ type: 'enum', enum: UserGender })
gender: UserGender;
}
25 changes: 25 additions & 0 deletions src/user/migrations/1742151949567-create-profile-migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class CreateProfileMigration1742151949567 implements MigrationInterface {
name = 'CreateProfileMigration1742151949567';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TYPE "public"."profile_gender_enum" AS ENUM('m', 'f')`,
);
await queryRunner.query(
`CREATE TABLE "profile" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "profile_picture" text NOT NULL, "birth_date" date NOT NULL, "gender" "public"."profile_gender_enum" NOT NULL, "user_id" uuid, CONSTRAINT "REL_d752442f45f258a8bdefeebb2f" UNIQUE ("user_id"), CONSTRAINT "PK_3dd8bfc97e4a77c70971591bdcb" PRIMARY KEY ("id"))`,
);
await queryRunner.query(
`ALTER TABLE "profile" ADD CONSTRAINT "FK_d752442f45f258a8bdefeebb2f2" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "profile" DROP CONSTRAINT "FK_d752442f45f258a8bdefeebb2f2"`,
);
await queryRunner.query(`DROP TABLE "profile"`);
await queryRunner.query(`DROP TYPE "public"."profile_gender_enum"`);
}
}
223 changes: 223 additions & 0 deletions src/user/migrations/1742153044149-fix-base-columns-migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class FixBaseColumnsMigration1742153044149
implements MigrationInterface
{
name = 'FixBaseColumnsMigration1742153044149';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "created_at"`);
await queryRunner.query(
`ALTER TABLE "user" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "updated_at"`);
await queryRunner.query(
`ALTER TABLE "user" ADD "updated_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "deleted_at"`);
await queryRunner.query(`ALTER TABLE "user" ADD "deleted_at" TIMESTAMP`);
await queryRunner.query(
`ALTER TABLE "manufacturer" DROP COLUMN "created_at"`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" DROP COLUMN "updated_at"`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" ADD "updated_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" DROP COLUMN "deleted_at"`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" ADD "deleted_at" TIMESTAMP`,
);
await queryRunner.query(
`ALTER TABLE "product_image" DROP COLUMN "created_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_image" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "product_image" DROP COLUMN "updated_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_image" ADD "updated_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "product_image" DROP COLUMN "deleted_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_image" ADD "deleted_at" TIMESTAMP`,
);
await queryRunner.query(
`ALTER TABLE "presentation" DROP COLUMN "created_at"`,
);
await queryRunner.query(
`ALTER TABLE "presentation" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "presentation" DROP COLUMN "updated_at"`,
);
await queryRunner.query(
`ALTER TABLE "presentation" ADD "updated_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "presentation" DROP COLUMN "deleted_at"`,
);
await queryRunner.query(
`ALTER TABLE "presentation" ADD "deleted_at" TIMESTAMP`,
);
await queryRunner.query(`ALTER TABLE "lot" DROP COLUMN "created_at"`);
await queryRunner.query(
`ALTER TABLE "lot" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "lot" DROP COLUMN "updated_at"`);
await queryRunner.query(
`ALTER TABLE "lot" ADD "updated_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "lot" DROP COLUMN "deleted_at"`);
await queryRunner.query(`ALTER TABLE "lot" ADD "deleted_at" TIMESTAMP`);
await queryRunner.query(
`ALTER TABLE "product_presentation" DROP COLUMN "created_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" DROP COLUMN "updated_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" ADD "updated_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" DROP COLUMN "deleted_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" ADD "deleted_at" TIMESTAMP`,
);
await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "created_at"`);
await queryRunner.query(
`ALTER TABLE "product" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "updated_at"`);
await queryRunner.query(
`ALTER TABLE "product" ADD "updated_at" TIMESTAMP NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "deleted_at"`);
await queryRunner.query(`ALTER TABLE "product" ADD "deleted_at" TIMESTAMP`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "deleted_at"`);
await queryRunner.query(
`ALTER TABLE "product" ADD "deleted_at" TIME WITH TIME ZONE`,
);
await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "updated_at"`);
await queryRunner.query(
`ALTER TABLE "product" ADD "updated_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "product" DROP COLUMN "created_at"`);
await queryRunner.query(
`ALTER TABLE "product" ADD "created_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" DROP COLUMN "deleted_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" ADD "deleted_at" TIME WITH TIME ZONE`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" DROP COLUMN "updated_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" ADD "updated_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" DROP COLUMN "created_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_presentation" ADD "created_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "lot" DROP COLUMN "deleted_at"`);
await queryRunner.query(
`ALTER TABLE "lot" ADD "deleted_at" TIME WITH TIME ZONE`,
);
await queryRunner.query(`ALTER TABLE "lot" DROP COLUMN "updated_at"`);
await queryRunner.query(
`ALTER TABLE "lot" ADD "updated_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "lot" DROP COLUMN "created_at"`);
await queryRunner.query(
`ALTER TABLE "lot" ADD "created_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "presentation" DROP COLUMN "deleted_at"`,
);
await queryRunner.query(
`ALTER TABLE "presentation" ADD "deleted_at" TIME WITH TIME ZONE`,
);
await queryRunner.query(
`ALTER TABLE "presentation" DROP COLUMN "updated_at"`,
);
await queryRunner.query(
`ALTER TABLE "presentation" ADD "updated_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "presentation" DROP COLUMN "created_at"`,
);
await queryRunner.query(
`ALTER TABLE "presentation" ADD "created_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "product_image" DROP COLUMN "deleted_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_image" ADD "deleted_at" TIME WITH TIME ZONE`,
);
await queryRunner.query(
`ALTER TABLE "product_image" DROP COLUMN "updated_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_image" ADD "updated_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "product_image" DROP COLUMN "created_at"`,
);
await queryRunner.query(
`ALTER TABLE "product_image" ADD "created_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" DROP COLUMN "deleted_at"`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" ADD "deleted_at" TIME WITH TIME ZONE`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" DROP COLUMN "updated_at"`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" ADD "updated_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" DROP COLUMN "created_at"`,
);
await queryRunner.query(
`ALTER TABLE "manufacturer" ADD "created_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "deleted_at"`);
await queryRunner.query(
`ALTER TABLE "user" ADD "deleted_at" TIME WITH TIME ZONE`,
);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "updated_at"`);
await queryRunner.query(
`ALTER TABLE "user" ADD "updated_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "created_at"`);
await queryRunner.query(
`ALTER TABLE "user" ADD "created_at" TIME WITH TIME ZONE NOT NULL DEFAULT now()`,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class FixProfilePictureNullableMigration1742153138409
implements MigrationInterface
{
name = 'FixProfilePictureNullableMigration1742153138409';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "profile" ALTER COLUMN "profile_picture" DROP NOT NULL`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "profile" ALTER COLUMN "profile_picture" SET NOT NULL`,
);
}
}
3 changes: 2 additions & 1 deletion src/user/user.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { UserController } from './user.controller';
import { UserOTP } from './entities/user-otp.entity';
import { Profile } from './entities/profile.entity';

@Module({
imports: [TypeOrmModule.forFeature([User, UserOTP])],
imports: [TypeOrmModule.forFeature([User, UserOTP, Profile])],
providers: [UserService],
exports: [UserService, TypeOrmModule],
controllers: [UserController],
Expand Down
Loading