Compare commits
11 Commits
69c0a65ad5
...
6945420e27
Author | SHA1 | Date |
---|---|---|
|
6945420e27 | 2 months ago |
|
4506469b9b | 2 months ago |
|
7240744076 | 2 months ago |
|
8411c2a28b | 2 months ago |
|
5e1fe81273 | 2 months ago |
|
a44695e5fd | 2 months ago |
|
54531c1c63 | 2 months ago |
|
fa026ac2f3 | 2 months ago |
|
86ce21487a | 2 months ago |
|
435083a682 | 2 months ago |
|
894ab52709 | 2 months ago |
28 changed files with 1410 additions and 119 deletions
@ -0,0 +1,3 @@ |
||||
{ |
||||
"cSpell.words": ["zarinpal"] |
||||
} |
@ -0,0 +1,23 @@ |
||||
{ |
||||
"development": { |
||||
"username": "postgres", |
||||
"password": "1234", |
||||
"database": "ecommerce", |
||||
"host": "127.0.0.1", |
||||
"dialect": "postgres" |
||||
}, |
||||
"test": { |
||||
"username": "root", |
||||
"password": null, |
||||
"database": "database_test", |
||||
"host": "127.0.0.1", |
||||
"dialect": "mysql" |
||||
}, |
||||
"production": { |
||||
"username": "root", |
||||
"password": null, |
||||
"database": "database_production", |
||||
"host": "127.0.0.1", |
||||
"dialect": "mysql" |
||||
} |
||||
} |
@ -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,63 @@ |
||||
'use strict'; |
||||
|
||||
module.exports = { |
||||
up: async (queryInterface, Sequelize) => { |
||||
await queryInterface.createTable('Admins', { |
||||
id: { |
||||
allowNull: false, |
||||
autoIncrement: true, |
||||
primaryKey: true, |
||||
type: Sequelize.INTEGER |
||||
}, |
||||
email: { |
||||
type: Sequelize.STRING, |
||||
allowNull: false, |
||||
unique: true, |
||||
}, |
||||
password: { |
||||
type: Sequelize.STRING, |
||||
allowNull: false, |
||||
}, |
||||
role: { |
||||
type: Sequelize.STRING, |
||||
defaultValue: 'admin', |
||||
}, |
||||
firstName: { |
||||
type: Sequelize.STRING, |
||||
allowNull: false, |
||||
}, |
||||
lastName: { |
||||
type: Sequelize.STRING, |
||||
allowNull: false, |
||||
}, |
||||
username: { |
||||
type: Sequelize.STRING, |
||||
allowNull: false, |
||||
unique: true, |
||||
}, |
||||
phoneNumber: { |
||||
type: Sequelize.STRING, |
||||
allowNull: false, |
||||
unique: true, |
||||
}, |
||||
gender: { |
||||
type: Sequelize.ENUM('male', 'female'), |
||||
allowNull: false, |
||||
}, |
||||
createdAt: { |
||||
type: Sequelize.DATE, |
||||
allowNull: false, |
||||
defaultValue: Sequelize.NOW, |
||||
}, |
||||
updatedAt: { |
||||
type: Sequelize.DATE, |
||||
allowNull: false, |
||||
defaultValue: Sequelize.NOW, |
||||
}, |
||||
}); |
||||
}, |
||||
|
||||
down: async (queryInterface, Sequelize) => { |
||||
await queryInterface.dropTable('Admins'); |
||||
}, |
||||
}; |
@ -0,0 +1,43 @@ |
||||
'use strict'; |
||||
|
||||
const fs = require('fs'); |
||||
const path = require('path'); |
||||
const Sequelize = require('sequelize'); |
||||
const process = require('process'); |
||||
const basename = path.basename(__filename); |
||||
const env = process.env.NODE_ENV || 'development'; |
||||
const config = require(__dirname + '/../config/config.json')[env]; |
||||
const db = {}; |
||||
|
||||
let sequelize; |
||||
if (config.use_env_variable) { |
||||
sequelize = new Sequelize(process.env[config.use_env_variable], config); |
||||
} else { |
||||
sequelize = new Sequelize(config.database, config.username, config.password, config); |
||||
} |
||||
|
||||
fs |
||||
.readdirSync(__dirname) |
||||
.filter(file => { |
||||
return ( |
||||
file.indexOf('.') !== 0 && |
||||
file !== basename && |
||||
file.slice(-3) === '.js' && |
||||
file.indexOf('.test.js') === -1 |
||||
); |
||||
}) |
||||
.forEach(file => { |
||||
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); |
||||
db[model.name] = model; |
||||
}); |
||||
|
||||
Object.keys(db).forEach(modelName => { |
||||
if (db[modelName].associate) { |
||||
db[modelName].associate(db); |
||||
} |
||||
}); |
||||
|
||||
db.sequelize = sequelize; |
||||
db.Sequelize = Sequelize; |
||||
|
||||
module.exports = db; |
@ -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; |
||||
}; |
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,26 @@ |
||||
import { Controller, Get, Post, Body, Patch, Param, Delete } from "@nestjs/common"; |
||||
import { Controller, Get, Post, Body, Request, Put, UseGuards } from "@nestjs/common"; |
||||
import { AdminService } from "./admin.service"; |
||||
import { Admin } from "./entities/admin.entity"; |
||||
import { CreateAdminDto } from "./dto/create-Admin.dto"; |
||||
import { LoginAdminDto } from "./dto/login-Admin.dto"; |
||||
import { JwtAuthGuard } from "src/guard/auth.guard"; |
||||
import { UpdateUserDto } from "./dto/update-user.dto"; |
||||
|
||||
@Controller("admin") |
||||
export class AdminController { |
||||
constructor(private readonly adminService: AdminService) {} |
||||
@Post("register") |
||||
async register(@Body() body: { email: string; password: string }): Promise<Admin> { |
||||
const { email, password } = body; |
||||
return this.adminService.register(email, password); |
||||
async register(@Body() createAdminDto: CreateAdminDto): Promise<Admin> { |
||||
return this.adminService.register(createAdminDto); |
||||
} |
||||
@Post("login") |
||||
async login(@Body() body: { email: string; password: string }): Promise<{ token: string }> { |
||||
const { email, password } = body; |
||||
return this.adminService.login(email, password); |
||||
async login(@Body() loginAdminDto: LoginAdminDto): Promise<{ token: string }> { |
||||
return this.adminService.login(loginAdminDto); |
||||
} |
||||
@UseGuards(JwtAuthGuard) |
||||
@Put() |
||||
async editAdminProfile(@Request() req, @Body() updateAdminDto: UpdateUserDto): Promise<Admin> { |
||||
const userId = req.user.id; |
||||
return this.adminService.editAdminProfile(userId, updateAdminDto); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,29 @@ |
||||
import { IsString, IsEmail, IsEnum, IsNotEmpty, IsOptional, Matches } from "class-validator"; |
||||
|
||||
export class CreateAdminDto { |
||||
@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; |
||||
} |
@ -0,0 +1,15 @@ |
||||
import { IsString, IsEmail,IsNotEmpty} from "class-validator"; |
||||
|
||||
export class LoginAdminDto { |
||||
@IsEmail({}, { message: "Invalid email format" }) |
||||
email: string; |
||||
|
||||
@IsString() |
||||
@IsNotEmpty({ message: "Password is required" }) |
||||
password: string; |
||||
|
||||
@IsString() |
||||
@IsNotEmpty({ message: "Username is required" }) |
||||
username: string; |
||||
|
||||
} |
@ -0,0 +1,33 @@ |
||||
|
||||
import { IsOptional, IsString, IsEmail, IsEnum } from 'class-validator'; |
||||
import {Gender } from '../entities/admin.entity';
|
||||
|
||||
export class UpdateUserDto { |
||||
@IsOptional()
|
||||
@IsString() |
||||
username?: string; |
||||
|
||||
@IsOptional() |
||||
@IsEmail() |
||||
email?: string; |
||||
|
||||
@IsOptional() |
||||
@IsString() |
||||
password?: string; |
||||
|
||||
@IsOptional() |
||||
@IsString() |
||||
firstName?: string; |
||||
|
||||
@IsOptional() |
||||
@IsString() |
||||
lastName?: string; |
||||
|
||||
@IsOptional() |
||||
@IsString() |
||||
phoneNumber?: string; |
||||
|
||||
@IsOptional() |
||||
@IsEnum(Gender) |
||||
gender?: Gender;
|
||||
} |
@ -1,12 +1,35 @@ |
||||
import { Model, Table, Column } from "sequelize-typescript"; |
||||
import { Column, Table, Model, DataType } from "sequelize-typescript"; |
||||
|
||||
@Table |
||||
export class Admin extends Model<Admin> { |
||||
@Column |
||||
@Column({ unique: true }) |
||||
email: string; |
||||
|
||||
@Column |
||||
password: string; |
||||
|
||||
@Column |
||||
@Column({ defaultValue: "admin" }) |
||||
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; |
||||
} |
||||
export enum Gender { |
||||
Male = "male", |
||||
Female = "female", |
||||
} |
||||
|
@ -1,14 +1,17 @@ |
||||
import { SequelizeModuleOptions } from '@nestjs/sequelize'; |
||||
import { SequelizeModuleOptions } from "@nestjs/sequelize"; |
||||
import * as dotenv from "dotenv"; |
||||
import * as path from "path"; |
||||
|
||||
dotenv.config(); |
||||
|
||||
export const databaseConfig: SequelizeModuleOptions = { |
||||
dialect: 'postgres', |
||||
host: process.env.DATABASE_HOST || 'localhost', |
||||
dialect: "postgres", |
||||
host: process.env.DATABASE_HOST || "localhost", |
||||
port: +process.env.DATABASE_PORT || 5432, |
||||
username: process.env.DATABASE_USER || 'postgres', |
||||
password: process.env.DATABASE_PASSWORD || 'password', |
||||
database: process.env.DATABASE_NAME || 'ecommerce', |
||||
username: process.env.DATABASE_USER || "postgres", |
||||
password: process.env.DATABASE_PASSWORD || "password", |
||||
database: process.env.DATABASE_NAME || "ecommerce", |
||||
models: [path.join(__dirname, "../**/entities/*.entity.ts")], |
||||
autoLoadModels: true, |
||||
synchronize: true,
|
||||
synchronize: true, |
||||
}; |
||||
|
@ -0,0 +1,17 @@ |
||||
import { SequelizeModuleOptions } from "@nestjs/sequelize"; |
||||
import * as dotenv from "dotenv"; |
||||
import * as path from "path"; |
||||
|
||||
dotenv.config(); |
||||
|
||||
export const databaseConfig: SequelizeModuleOptions = { |
||||
dialect: "postgres", |
||||
host: process.env.DATABASE_HOST || "localhost", |
||||
port: +process.env.DATABASE_PORT || 5432, |
||||
username: process.env.DATABASE_USER || "postgres", |
||||
password: process.env.DATABASE_PASSWORD || "password", |
||||
database: process.env.DATABASE_NAME || "ecommerce", |
||||
models: [path.join(__dirname, "../**/entities/*.entity.ts")], |
||||
autoLoadModels: true, |
||||
synchronize: true, |
||||
}; |
@ -1,14 +1,16 @@ |
||||
import { Table, Model, Column, BelongsTo, ForeignKey } from "sequelize-typescript"; |
||||
import { User } from "../../users/entities/user.entity"; |
||||
import { Product } from "../../products/entities/product.entity"; |
||||
import { Product } from "../../products/entities/product.entity";
|
||||
|
||||
@Table |
||||
export class Invoice extends Model<Invoice> { |
||||
@ForeignKey(() => User) |
||||
@Column |
||||
userId: number; |
||||
@BelongsTo(() => User) |
||||
|
||||
@BelongsTo(() => User, { onDelete: 'CASCADE' })
|
||||
user: User; |
||||
|
||||
@Column |
||||
totalAmount: number; |
||||
} |
||||
|
@ -1,8 +1,10 @@ |
||||
import { NestFactory } from '@nestjs/core'; |
||||
import { AppModule } from './app.module'; |
||||
import { ValidationPipe } from '@nestjs/common'; |
||||
|
||||
async function bootstrap() { |
||||
const app = await NestFactory.create(AppModule); |
||||
app.useGlobalPipes(new ValidationPipe()); |
||||
await app.listen(process.env.PORT ?? 3000); |
||||
} |
||||
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; |
||||
} |
@ -0,0 +1,15 @@ |
||||
import { IsString, IsEmail, IsEnum, IsNotEmpty, IsOptional, Matches } from "class-validator"; |
||||
|
||||
export class LoginUserDto { |
||||
@IsEmail({}, { message: "Invalid email format" }) |
||||
email: string; |
||||
|
||||
@IsString() |
||||
@IsNotEmpty({ message: "Password is required" }) |
||||
password: string; |
||||
|
||||
@IsString() |
||||
@IsNotEmpty({ message: "Username is required" }) |
||||
username: string; |
||||
|
||||
} |
@ -0,0 +1,33 @@ |
||||
|
||||
import { IsOptional, IsString, IsEmail, IsEnum } from 'class-validator'; |
||||
import {Gender } from '../entities/user.entity';
|
||||
|
||||
export class UpdateUserDto { |
||||
@IsOptional()
|
||||
@IsString() |
||||
username?: string; |
||||
|
||||
@IsOptional() |
||||
@IsEmail() |
||||
email?: string; |
||||
|
||||
@IsOptional() |
||||
@IsString() |
||||
password?: string; |
||||
|
||||
@IsOptional() |
||||
@IsString() |
||||
firstName?: string; |
||||
|
||||
@IsOptional() |
||||
@IsString() |
||||
lastName?: string; |
||||
|
||||
@IsOptional() |
||||
@IsString() |
||||
phoneNumber?: string; |
||||
|
||||
@IsOptional() |
||||
@IsEnum(Gender) |
||||
gender?: Gender;
|
||||
} |
@ -1,11 +1,35 @@ |
||||
import { Column, Table, Model } from "sequelize-typescript"; |
||||
import { Column, Table, Model, DataType } from "sequelize-typescript"; |
||||
|
||||
@Table |
||||
export class User extends Model<User> { |
||||
@Column({ unique: true }) |
||||
email: string; |
||||
|
||||
@Column |
||||
password: string; |
||||
|
||||
@Column({ defaultValue: "user" }) |
||||
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; |
||||
} |
||||
export enum Gender { |
||||
Male = 'male', |
||||
Female = 'female', |
||||
} |
||||
|
@ -1,20 +1,44 @@ |
||||
import { Controller, Post, Body, Res, UseGuards, Get } from "@nestjs/common"; |
||||
import { Controller, Post, Body, UseGuards, Get, Request, Put } from "@nestjs/common"; |
||||
import { UsersService } from "./users.service"; |
||||
import { User } from "./entities/user.entity"; |
||||
import { CreateUserDto } from "./dto/create-user.dto"; |
||||
import { LoginUserDto } from "./dto/login-user.dto"; |
||||
import { JwtAuthGuard } from "src/guard/auth.guard"; |
||||
import { UpdateUserDto } from "./dto/update-user.dto"; |
||||
import { RoleGuard } from "src/guard/role.guard"; |
||||
|
||||
@Controller("user") |
||||
export class UsersController { |
||||
constructor(private readonly usersService: UsersService) {} |
||||
|
||||
//register as user
|
||||
@Post("register") |
||||
async register(@Body() body: { email: string; password: string }):Promise<User> { |
||||
const { email, password } = body; |
||||
return this.usersService.register(email, password); |
||||
async register(@Body() createUserDto: CreateUserDto): Promise<User> { |
||||
return this.usersService.register(createUserDto); |
||||
} |
||||
|
||||
//login as user
|
||||
@Post("login") |
||||
async login(@Body() body: { email: string; password: string }):Promise<{token}> { |
||||
const { email, password } = body; |
||||
return this.usersService.login(email, password); |
||||
async login(@Body() loginUserDto: LoginUserDto): Promise<{ token }> { |
||||
return this.usersService.login(loginUserDto); |
||||
} |
||||
|
||||
//retrieve a user information
|
||||
@UseGuards(JwtAuthGuard) |
||||
@Get() |
||||
async getProfile(@Request() req): Promise<User> { |
||||
const userId = req.user.id; |
||||
return this.usersService.getProfile(userId); |
||||
} |
||||
//edit user profile
|
||||
@UseGuards(JwtAuthGuard) |
||||
@Put() |
||||
async editProfile(@Request() req, @Body() updateUserDto: UpdateUserDto): Promise<User> { |
||||
const userId = req.user.id;
|
||||
return this.usersService.editProfile(userId, updateUserDto); |
||||
} |
||||
//get users list (admin)
|
||||
@UseGuards(RoleGuard)
|
||||
@Get("users") |
||||
async findAll(): Promise<User[]> { |
||||
return this.usersService.findAll();
|
||||
} |
||||
} |
||||
|
Loading…
Reference in new issue