Skip to content

Commit

Permalink
Merge pull request #98 from bakaqc/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
theqi106 authored Jan 8, 2025
2 parents 11ecc1d + e497ef5 commit e635cd7
Show file tree
Hide file tree
Showing 45 changed files with 288 additions and 80 deletions.
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "evora-backend",
"version": "1.4.5",
"version": "1.5.4",
"description": "Evora connects customers with event organizers quickly through detailed online booking.",
"repository": "https://github.com/bakaqc/evora-17c",
"author": "Quốc Chương",
Expand Down
7 changes: 7 additions & 0 deletions backend/src/domains/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ export class AuthController {
return await this.authService.login(user);
}

@Public()
@HttpCode(HttpStatus.OK)
@Post('forgot-password')
async forgotPassword(@Body() loginDto: LoginDto) {
return this.authService.forgotPassword(loginDto);
}

@Public()
@HttpCode(HttpStatus.OK)
@ApiOperation({
Expand Down
18 changes: 18 additions & 0 deletions backend/src/domains/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Model } from 'mongoose';

import { LoginDto } from '@/domains/auth/dto/login.dto';
import { User } from '@/schemas/user.schema';
import { hash } from '@/utils/hash.util';
import { verify } from '@/utils/verify.util';

@Injectable()
Expand Down Expand Up @@ -70,6 +71,23 @@ export class AuthService {
};
}

async forgotPassword(loginDto: LoginDto) {
const user = await this.userModel.findOne({ email: loginDto.email });

if (!user) {
throw new NotFoundException(
`Account with email: ${loginDto.email} does not exist`,
);
}

user.hashedPassword = await hash(loginDto.password);
await user.save();

return {
message: 'Password has been reset',
};
}

async verifyJwt(token: string) {
try {
return this.jwtService.verify(token);
Expand Down
21 changes: 21 additions & 0 deletions backend/src/domains/auth/decorators/pagination.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { applyDecorators } from '@nestjs/common';
import { ApiQuery } from '@nestjs/swagger';

export function ApiPagination() {
return applyDecorators(
ApiQuery({
name: 'page',
required: false,
type: Number,
example: 1,
description: 'Page number, starts from 1',
}),
ApiQuery({
name: 'limit',
required: false,
type: Number,
example: 10,
description: 'Number of items per page',
}),
);
}
14 changes: 11 additions & 3 deletions backend/src/domains/bookings/bookings.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Param,
Post,
Put,
Query,
} from '@nestjs/common';
import {
ApiBearerAuth,
Expand All @@ -14,6 +15,7 @@ import {
ApiTags,
} from '@nestjs/swagger';

import { ApiPagination } from '@/domains/auth/decorators/pagination.decorator';
import { Roles } from '@/domains/auth/decorators/roles.decorator';
import { Role } from '@/domains/auth/enums/role.enum';
import { BookingsService } from '@/domains/bookings/bookings.service';
Expand All @@ -33,10 +35,16 @@ export class BookingsController {
}

@Roles(Role.SUPER_ADMIN)
@ApiOperation({ summary: 'Fetch all bookings - Super Amin only' })
@ApiOperation({
summary: 'Fetch all bookings with pagination - Super Admin only',
})
@ApiPagination()
@Get()
async getAll() {
return this.bookingsService.getAll();
async getAll(
@Query('page') page: number = 1,
@Query('limit') limit: number = 10,
) {
return this.bookingsService.getAllWithPagination(page, limit);
}

@ApiOperation({ summary: 'Fetch a booking by ID' })
Expand Down
32 changes: 32 additions & 0 deletions backend/src/domains/bookings/bookings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,38 @@ export class BookingsService {
};
}

async getAllWithPagination(page: number, limit: number) {
if (page < 1) page = 1;
if (limit < 1) limit = 10;

const skip = (page - 1) * limit;

const [bookings, total] = await Promise.all([
this.bookingModel.find().skip(skip).limit(limit).exec(),
this.bookingModel.countDocuments().exec(),
]);

const totalPages = Math.ceil(total / limit);

this.logger.debug(
`Fetched bookings with pagination: page ${page}, limit ${limit}`,
);

return {
success: true,
message: 'Bookings fetched successfully.',
data: {
bookings,
pagination: {
total,
page,
limit,
totalPages,
},
},
};
}

async getById(id: string) {
const booking = await this.bookingModel.findById(id).select('-__v');

Expand Down
12 changes: 9 additions & 3 deletions backend/src/domains/parties/parties.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
Param,
Post,
Put,
Query,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';

import { ApiPagination } from '@/domains/auth/decorators/pagination.decorator';
import { Public } from '@/domains/auth/decorators/public.decorator';
import { Roles } from '@/domains/auth/decorators/roles.decorator';
import { Role } from '@/domains/auth/enums/role.enum';
Expand All @@ -30,10 +32,14 @@ export class PartiesController {
}

@Public()
@ApiOperation({ summary: 'Fetch all parties' })
@ApiOperation({ summary: 'Fetch all parties with pagination' })
@ApiPagination()
@Get()
async getAll() {
return await this.partiesService.getAll();
async getAll(
@Query('page') page: number = 1,
@Query('limit') limit: number = 10,
) {
return await this.partiesService.getAllWithPagination(page, limit);
}

@Public()
Expand Down
30 changes: 30 additions & 0 deletions backend/src/domains/parties/parties.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,36 @@ export class PartiesService {
};
}

async getAllWithPagination(page: number, limit: number) {
if (page < 1) page = 1;
if (limit < 1) limit = 10;

const skip = (page - 1) * limit;

const [parties, total] = await Promise.all([
this.partyModel.find().skip(skip).limit(limit).exec(),
this.partyModel.countDocuments().exec(),
]);

this.logger.debug('Fetching all parties with pagination', parties);

const totalPages = Math.ceil(total / limit);

return {
success: true,
message: 'Parties fetched successfully.',
data: {
parties,
pagination: {
total,
page,
limit,
totalPages,
},
},
};
}

async getOne(identifier: string) {
const party = await this.findPartyByIdentifier(identifier);

Expand Down
25 changes: 20 additions & 5 deletions backend/src/domains/users/users.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { Body, Controller, Delete, Get, Param, Put } from '@nestjs/common';
import {
Body,
Controller,
Delete,
Get,
Param,
Put,
Query,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';

import { ApiPagination } from '@/domains/auth/decorators/pagination.decorator';
import { Public } from '@/domains/auth/decorators/public.decorator';
import { Roles } from '@/domains/auth/decorators/roles.decorator';
import { Role } from '@/domains/auth/enums/role.enum';
Expand All @@ -14,11 +23,17 @@ import { UsersService } from '@/domains/users/users.service';
export class UsersController {
constructor(private readonly usersService: UsersService) {}

@Roles(Role.SUPER_ADMIN, Role.ADMIN)
@ApiOperation({ summary: 'Fetch all users - Super Admin & Admin only' })
@Roles(Role.SUPER_ADMIN)
@ApiOperation({
summary: 'Fetch all users with pagination - Super Admin only',
})
@ApiPagination()
@Get()
async getAll() {
return await this.usersService.getAll();
async getAll(
@Query('page') page: number = 1,
@Query('limit') limit: number = 10,
) {
return await this.usersService.getAllWithPagination(page, limit);
}

@Public()
Expand Down
32 changes: 32 additions & 0 deletions backend/src/domains/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,38 @@ export class UsersService {
};
}

async getAllWithPagination(page: number, limit: number) {
if (page < 1) page = 1;
if (limit < 1) limit = 10;

const skip = (page - 1) * limit;

const [users, total] = await Promise.all([
this.userModel.find().skip(skip).limit(limit).exec(),
this.userModel.countDocuments().exec(),
]);

const totalPages = Math.ceil(total / limit);

this.logger.debug(
`Fetched users with pagination: page ${page}, limit ${limit}`,
);

return {
success: true,
message: 'Users fetched successfully.',
data: {
users,
pagination: {
total,
page,
limit,
totalPages,
},
},
};
}

async getOne(identifier: string, isEmail = false) {
const user = await this.findUser(identifier, isEmail);

Expand Down
12 changes: 9 additions & 3 deletions backend/src/domains/vouchers/vouchers.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import {
Param,
Post,
Put,
Query,
} from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';

import { ApiPagination } from '@/domains/auth/decorators/pagination.decorator';
import { Public } from '@/domains/auth/decorators/public.decorator';
import { Roles } from '@/domains/auth/decorators/roles.decorator';
import { Role } from '@/domains/auth/enums/role.enum';
Expand All @@ -30,10 +32,14 @@ export class VouchersController {
}

@Public()
@ApiOperation({ summary: 'Fetch all vouchers' })
@ApiOperation({ summary: 'Fetch all vouchers with pagination' })
@ApiPagination()
@Get()
async getAll() {
return await this.vouchersService.getAll();
async getAll(
@Query('page') page: number = 1,
@Query('limit') limit: number = 10,
) {
return await this.vouchersService.getAllWithPagination(page, limit);
}

@Public()
Expand Down
32 changes: 32 additions & 0 deletions backend/src/domains/vouchers/vouchers.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,38 @@ export class VouchersService {
};
}

async getAllWithPagination(page: number, limit: number) {
if (page < 1) page = 1;
if (limit < 1) limit = 10;

const skip = (page - 1) * limit;

const [vouchers, total] = await Promise.all([
this.voucherModel.find().skip(skip).limit(limit).exec(),
this.voucherModel.countDocuments().exec(),
]);

const totalPages = Math.ceil(total / limit);

this.logger.debug(
`Fetched vouchers with pagination: page ${page}, limit ${limit}`,
);

return {
success: true,
message: 'Vouchers fetched successfully.',
data: {
vouchers,
pagination: {
total,
page,
limit,
totalPages,
},
},
};
}

async getOne(identifier: string) {
const voucher = await this.findVoucherByIdentifier(identifier);

Expand Down
7 changes: 0 additions & 7 deletions backend/src/utils/hash.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,3 @@ import * as argon2 from 'argon2';
export const hash = async (plainPassword: string): Promise<string> => {
return await argon2.hash(plainPassword);
};

export const verify = async (
hashedPassword: string,
plainPassword: string,
): Promise<boolean> => {
return await argon2.verify(hashedPassword, plainPassword);
};
Loading

0 comments on commit e635cd7

Please sign in to comment.