Create DTOs for user registration and complete user model

master
nicekid1 2 months ago
parent 894ab52709
commit 435083a682
  1. 62
      migrations/20250104074851-create-user.js
  2. 30
      models/user.js
  3. 4
      src/cart/entities/cart.entity.ts
  4. 6
      src/invoice/entities/invoice.entity.ts
  5. 2
      src/main.ts
  6. 29
      src/users/dto/create-user.dto.ts
  7. 22
      src/users/entities/user.entity.ts
  8. 8
      src/users/users.controller.ts
  9. 37
      src/users/users.service.ts
  10. 10
      src/wallet/entities/wallet.entity.ts

@ -0,0 +1,62 @@
'use strict';
/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
email: {
type: Sequelize.STRING,
unique: true,
allowNull: false
},
password: {
type: Sequelize.STRING,
allowNull: false
},
role: {
type: Sequelize.STRING,
defaultValue: 'user'
},
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING,
allowNull: false
},
username: {
type: Sequelize.STRING,
unique: true,
allowNull: false
},
phoneNumber: {
type: Sequelize.STRING,
unique: true,
allowNull: false
},
gender: {
type: Sequelize.ENUM("male", "female"),
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('Users');
}
};

@ -0,0 +1,30 @@
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
}
User.init({
email: DataTypes.STRING,
password: DataTypes.STRING,
role: DataTypes.STRING,
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
username: DataTypes.STRING,
phoneNumber: DataTypes.STRING,
gender: DataTypes.ENUM
}, {
sequelize,
modelName: 'User',
});
return User;
};

@ -8,14 +8,14 @@ export class Cart extends Model<Cart> {
@Column @Column
userId: number; userId: number;
@BelongsTo(() => User) @BelongsTo(() => User, { onDelete: 'CASCADE' })
user: User; user: User;
@ForeignKey(() => Product) @ForeignKey(() => Product)
@Column @Column
productId: number; productId: number;
@BelongsTo(() => Product) @BelongsTo(() => Product, { onDelete: 'CASCADE' })
product: Product; product: Product;
@Column({ @Column({

@ -1,14 +1,16 @@
import { Table, Model, Column, BelongsTo, ForeignKey } from "sequelize-typescript"; import { Table, Model, Column, BelongsTo, ForeignKey } from "sequelize-typescript";
import { User } from "../../users/entities/user.entity"; import { User } from "../../users/entities/user.entity";
import { Product } from "../../products/entities/product.entity"; import { Product } from "../../products/entities/product.entity";
@Table @Table
export class Invoice extends Model<Invoice> { export class Invoice extends Model<Invoice> {
@ForeignKey(() => User) @ForeignKey(() => User)
@Column @Column
userId: number; userId: number;
@BelongsTo(() => User)
@BelongsTo(() => User, { onDelete: 'CASCADE' })
user: User; user: User;
@Column @Column
totalAmount: number; totalAmount: number;
} }

@ -1,8 +1,10 @@
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(process.env.PORT ?? 3000); await app.listen(process.env.PORT ?? 3000);
} }
bootstrap(); bootstrap();

@ -0,0 +1,29 @@
import { IsString, IsEmail, IsEnum, IsNotEmpty, IsOptional, Matches } from "class-validator";
export class CreateUserDto {
@IsEmail({}, { message: "Invalid email format" })
email: string;
@IsString()
@IsNotEmpty({ message: "Password is required" })
password: string;
@IsString()
@IsNotEmpty({ message: "First name is required" })
firstName: string;
@IsString()
@IsNotEmpty({ message: "Last name is required" })
lastName: string;
@IsString()
@IsNotEmpty({ message: "Username is required" })
username: string;
@IsString()
@Matches(/^[0-9]{11}$/, { message: "Phone number must be 10 digits" })
phoneNumber: string;
@IsEnum(["male", "female"], { message: "Gender must be 'male' or 'female'" })
gender: string;
}

@ -1,11 +1,31 @@
import { Column, Table, Model } from "sequelize-typescript"; import { Column, Table, Model, DataType } from "sequelize-typescript";
@Table @Table
export class User extends Model<User> { export class User extends Model<User> {
@Column({ unique: true }) @Column({ unique: true })
email: string; email: string;
@Column @Column
password: string; password: string;
@Column({ defaultValue: "user" }) @Column({ defaultValue: "user" })
role: string; role: string;
@Column
firstName: string;
@Column
lastName: string;
@Column({ unique: true })
username: string;
@Column({ unique: true })
phoneNumber: string;
@Column({
type: DataType.ENUM("male", "female"),
allowNull: false,
})
gender: string;
} }

@ -1,15 +1,15 @@
import { Controller, Post, Body, Res, UseGuards, Get } from "@nestjs/common"; import { Controller, Post, Body} from "@nestjs/common";
import { UsersService } from "./users.service"; import { UsersService } from "./users.service";
import { User } from "./entities/user.entity"; import { User } from "./entities/user.entity";
import { CreateUserDto } from "./dto/create-user.dto";
@Controller("user") @Controller("user")
export class UsersController { export class UsersController {
constructor(private readonly usersService: UsersService) {} constructor(private readonly usersService: UsersService) {}
@Post("register") @Post("register")
async register(@Body() body: { email: string; password: string }):Promise<User> { async register(@Body() createUserDto: CreateUserDto):Promise<User> {
const { email, password } = body; return this.usersService.register(createUserDto);
return this.usersService.register(email, password);
} }
@Post("login") @Post("login")

@ -2,41 +2,44 @@ import { HttpException, HttpStatus, Injectable, UnauthorizedException, BadReques
import { InjectModel } from "@nestjs/sequelize"; import { InjectModel } from "@nestjs/sequelize";
import { User } from "./entities/user.entity"; import { User } from "./entities/user.entity";
import * as bcrypt from "bcrypt"; import * as bcrypt from "bcrypt";
import { JwtService } from '@nestjs/jwt'; import { JwtService } from "@nestjs/jwt";
import { ConfigService } from '@nestjs/config'; import { ConfigService } from "@nestjs/config";
import { CreateUserDto } from "./dto/create-user.dto";
@Injectable() @Injectable()
export class UsersService { export class UsersService {
constructor( constructor(
@InjectModel(User) private readonly userModel: typeof User, @InjectModel(User) private readonly userModel: typeof User,
private readonly jwtService: JwtService, private readonly jwtService: JwtService,
private readonly configService: ConfigService private readonly configService: ConfigService,
) {} ) {}
// Register method // Register method
async register(email: string, password: string): Promise<User> { async register(createUserDto: CreateUserDto): Promise<User> {
if (!email) throw new BadRequestException("Email should be entered");
if (!password) throw new BadRequestException("Password should be entered");
try { try {
const hashedPassword = await bcrypt.hash(password, 10); createUserDto.password = await bcrypt.hash(
createUserDto.password,
parseInt(process.env.BCRYPT_SALT_ROUNDS || "10", 10)
);
const userExists = await this.userModel.findOne({ where: { email } }); const userExists = await this.userModel.findOne({
where: { email: createUserDto.email },
});
if (userExists) { if (userExists) {
throw new BadRequestException('Email already exists'); throw new BadRequestException("Email already exists");
} }
const user = await this.userModel.create({ const user = await this.userModel.create(createUserDto);
email,
password: hashedPassword,
});
return user; return user;
} catch (error) { } catch (error) {
throw new HttpException(`An error occurred: ${error.message}`, HttpStatus.INTERNAL_SERVER_ERROR); throw new HttpException(
`An error occurred: ${error.message}`,
HttpStatus.INTERNAL_SERVER_ERROR
);
} }
} }
// Login method // Login method
async login(email: string, password: string): Promise<{ token: string }> { async login(email: string, password: string): Promise<{ token: string }> {
if (!email) throw new BadRequestException("Email should be entered"); if (!email) throw new BadRequestException("Email should be entered");

@ -1,4 +1,4 @@
import { Model, Table, Column, ForeignKey, BelongsTo } from 'sequelize-typescript'; import { Model, Table, Column, ForeignKey, BelongsTo, DataType } from 'sequelize-typescript';
import { User } from '../../users/entities/user.entity'; import { User } from '../../users/entities/user.entity';
@Table @Table
@ -7,9 +7,13 @@ export class Wallet extends Model<Wallet> {
@Column @Column
userId: number; userId: number;
@BelongsTo(() => User) @BelongsTo(() => User, { onDelete: 'CASCADE' })
user: User; user: User;
@Column @Column({
type: DataType.DECIMAL(10, 2),
allowNull: false,
defaultValue: 0,
})
balance: number; balance: number;
} }

Loading…
Cancel
Save