Skip to content

Commit

Permalink
Merge pull request #10 from erik1110/feature/api
Browse files Browse the repository at this point in the history
[feat] update api
  • Loading branch information
erik1110 committed Jan 16, 2024
2 parents d9fc73c + c5e5955 commit 80c5750
Show file tree
Hide file tree
Showing 17 changed files with 404 additions and 88 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->

# Hotel Reservation Backend

This is a hotel backend service built with NestJS, featuring user login, order management, latest news, delicious dishes, room type management, and including admin functionalities.

This project set up Swagger docs, utilizing the Render service in conjunction with MongoDB. You can refer to the following [URL](https://hotel-reservation-backend-sgtq.onrender.com/api-docs).

If you find this project appealing and decide to give it a GitHub star ⭐️, I would sincerely appreciate your support. Thank you!

<img src="./image/Swagger.png">

## Description

[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
Expand Down
Binary file added image/Swagger.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Get, Controller } from '@nestjs/common';
import { ApiOperation } from '@nestjs/swagger';

@Controller()
export class AppController {
@Get()
@ApiOperation({ summary: '健康檢查 Health Check' })
root(): string {
return 'Health Check';
}
Expand Down
47 changes: 46 additions & 1 deletion src/features/culinary/culinary.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,44 @@ import {
CreateCulinarySuccessDto,
DeleteCulinarySuccessDto,
GetCulinarySuccessDto,
GetOneCulinarySuccessDto,
UpdateCulinaryDto,
UpdateCulinarySuccessDto,
} from './dto/culinary.dto';
import { IsObjectIdPipe } from 'nestjs-object-id';
import { AuthGuard } from '@nestjs/passport';


@ApiTags('Home/Culinary - 美味佳餚')
@ApiErrorDecorator(
HttpStatus.INTERNAL_SERVER_ERROR,
'CriticalError',
'系統錯誤,請洽系統管理員',
)
@UseGuards(AuthGuard('jwt'))
@ApiBearerAuth()
@Controller('/api/v1/home/culinary')
export class CulinaryController {
constructor(private readonly culinaryService: CulinaryService) {}

@Get('')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '取得所有美味佳餚 Get all delicious dishes' })
@ApiOkResponse({ type: GetCulinarySuccessDto })
async getallCulinary(@Req() req: Request) {
return await this.culinaryService.getallCulinary(req);
}

@Get(':id')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '取得單筆美味佳餚 Get one delicious dish' })
@ApiOkResponse({ type: GetOneCulinarySuccessDto })
async getOneCulinary(
@Param('id', IsObjectIdPipe) id: string,
@Req() req: Request) {
return await this.culinaryService.getOneCulinary(id, req);
}
}

@ApiTags('Admin/Culinary - 美味佳餚管理')
@UseGuards(RolesGuard)
Expand All @@ -41,7 +75,7 @@ import { IsObjectIdPipe } from 'nestjs-object-id';
'系統錯誤,請洽系統管理員',
)
@Controller('api/v1/admin/culinary')
export class CulinaryController {
export class CulinaryAdminController {
constructor(private readonly culinaryService: CulinaryService) {}

@Get('')
Expand All @@ -53,6 +87,17 @@ export class CulinaryController {
return await this.culinaryService.getallCulinary(req);
}

@Get(':id')
@Roles('admin')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '取得單筆美味佳餚 Get one delicious dish' })
@ApiOkResponse({ type: GetOneCulinarySuccessDto })
async getOneCulinary(
@Param('id', IsObjectIdPipe) id: string,
@Req() req: Request) {
return await this.culinaryService.getOneCulinary(id, req);
}

@Post('')
@Roles('admin')
@HttpCode(HttpStatus.OK)
Expand Down
4 changes: 2 additions & 2 deletions src/features/culinary/culinary.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common';
import { CulinaryController } from './culinary.controller';
import { CulinaryAdminController, CulinaryController } from './culinary.controller';
import { CulinaryService } from './culinary.service';
import { CulinarySchema } from './schemas/culinary.schema';
import { MongooseModule } from '@nestjs/mongoose';
Expand All @@ -8,7 +8,7 @@ import { MongooseModule } from '@nestjs/mongoose';
imports: [
MongooseModule.forFeature([{ name: 'Culinary', schema: CulinarySchema }]),
],
controllers: [CulinaryController],
controllers: [CulinaryController, CulinaryAdminController],
providers: [CulinaryService],
})
export class CulinaryModule {}
14 changes: 14 additions & 0 deletions src/features/culinary/culinary.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,22 @@ export class CulinaryService {

async getallCulinary(req: Request) {
const result = await this.culinaryModel.find();
const ids = result.map(order => order._id.toString());
return getHttpResponse.successResponse({
message: '取得所有美味佳餚',
data: ids,
});
}

async getOneCulinary(id: string, req: Request) {
const result = await this.culinaryModel.findOne({
_id: id,
});
if (!result) {
throw new AppError(HttpStatus.NOT_FOUND, 'UserError', '此美味佳餚不存在');
}
return getHttpResponse.successResponse({
message: '取得單筆美味佳餚',
data: result,
});
}
Expand Down
37 changes: 25 additions & 12 deletions src/features/culinary/dto/culinary.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,36 @@ export class GetCulinarySuccessDto {

@ApiProperty({
example: [
{
_id: '658e628a4963529557a6561b',
title: '大魔術熊貓豆腐',
description: longDescription
.replace(/(\r\n|\r|\n)/g, ' ')
.replace(/\s+/g, ' '),
diningTime: 'SUN-MON 11:00-20:30',
image: 'https://fakeimg.pl/300/',
creator: '658b9367df4b59a38f24e143',
createdAt: '2023-12-27T03:00:55.922Z',
updatedAt: '2023-12-28T04:01:21.006Z',
},
"658e985c1c91c1765e2972b5",
],
})
data: object;
}

export class GetOneCulinarySuccessDto {
@ApiProperty({ example: true })
status: boolean;

@ApiProperty({ example: '取得單筆美味佳餚' })
message: string;

@ApiProperty({
example: {
_id: '658e628a4963529557a6561b',
title: '烈冰鮮鯛山',
description: longDescription2
.replace(/(\r\n|\r|\n)/g, ' ')
.replace(/\s+/g, ' '),
diningTime: 'SUN-MON 13:00-22:30',
image: 'https://fakeimg.pl/300/',
creator: '658b9367df4b59a38f24e143',
createdAt: '2023-12-27T03:00:55.922Z',
updatedAt: '2023-12-28T04:01:21.006Z',
},
})
data: object;
}

export class UpdateCulinarySuccessDto {
@ApiProperty({ example: true })
status: boolean;
Expand Down
31 changes: 22 additions & 9 deletions src/features/news/dto/news.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,33 @@ export class GetNewsSuccessDto {

@ApiProperty({
example: [
{
_id: '658e628a4963529557a6561b',
title: '秋季旅遊,豪華享受方案',
description: '秋天就是要來場豪華的旅遊...',
image: 'https://fakeimg.pl/300/',
creator: '658b9367df4b59a38f24e143',
createdAt: '2023-12-27T03:00:55.922Z',
updatedAt: '2023-12-28T04:01:21.006Z',
},
"658e985c1c91c1765e2972b5",
],
})
data: object;
}

export class GetOneNewsSuccessDto {
@ApiProperty({ example: true })
status: boolean;

@ApiProperty({ example: '取得單筆最新資訊' })
message: string;

@ApiProperty({
example: {
_id: '658e628a4963529557a6561b',
title: '秋季旅遊,豪華享受方案',
description: '秋天就是要來場豪華的旅遊...',
image: 'https://fakeimg.pl/300/',
creator: '658b9367df4b59a38f24e143',
createdAt: '2023-12-27T03:00:55.922Z',
updatedAt: '2023-12-28T04:01:21.006Z',
},
})
data: object;
}

export class UpdateNewsSuccessDto {
@ApiProperty({ example: true })
status: boolean;
Expand Down
48 changes: 47 additions & 1 deletion src/features/news/news.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,46 @@ import {
CreateNewsSuccessDto,
DeleteNewsSuccessDto,
GetNewsSuccessDto,
GetOneNewsSuccessDto,
UpdateNewsSuccessDto,
} from './dto/news.dto';
import { Roles } from 'src/auth/decorators/roles.decorator';
import { RolesGuard } from 'src/auth/guards/roles.guard';
import { IsObjectIdPipe } from 'nestjs-object-id';
import { AuthGuard } from '@nestjs/passport';


@ApiTags('Home/News - 最新消息')
@ApiErrorDecorator(
HttpStatus.INTERNAL_SERVER_ERROR,
'CriticalError',
'系統錯誤,請洽系統管理員',
)
@UseGuards(AuthGuard('jwt'))
@ApiBearerAuth()
@Controller('/api/v1/home/news')
export class NewsController {
constructor(private readonly newsService: NewsService) {}

@Get('')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '取得所有最新消息 Get all latest news' })
@ApiOkResponse({ type: GetNewsSuccessDto })
async getallNews(@Req() req: Request) {
return await this.newsService.getallNews(req);
}

@Get(':id')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '取得單筆最新消息 Get one latest news' })
@ApiOkResponse({ type: GetOneNewsSuccessDto })
async getOneNews(
@Param('id', IsObjectIdPipe) id: string,
@Req() req: Request) {
return await this.newsService.getOneNews(id, req);
}

}

@ApiTags('Admin/News - 最新消息管理')
@UseGuards(RolesGuard)
Expand All @@ -40,7 +75,7 @@ import { IsObjectIdPipe } from 'nestjs-object-id';
'系統錯誤,請洽系統管理員',
)
@Controller('api/v1/admin/news')
export class NewsController {
export class NewsAdminController {
constructor(private readonly newsService: NewsService) {}

@Get('')
Expand All @@ -52,6 +87,17 @@ export class NewsController {
return await this.newsService.getallNews(req);
}

@Get(':id')
@Roles('admin')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '取得單筆最新消息 Get one latest news' })
@ApiOkResponse({ type: GetOneNewsSuccessDto })
async getOneNews(
@Param('id', IsObjectIdPipe) id: string,
@Req() req: Request) {
return await this.newsService.getOneNews(id, req);
}

@Post('')
@Roles('admin')
@HttpCode(HttpStatus.OK)
Expand Down
4 changes: 2 additions & 2 deletions src/features/news/news.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Module } from '@nestjs/common';
import { NewsController } from './news.controller';
import { NewsAdminController, NewsController } from './news.controller';
import { MongooseModule } from '@nestjs/mongoose';
import { NewsSchema } from './schemas/news.schema';
import { NewsService } from './news.service';

@Module({
imports: [MongooseModule.forFeature([{ name: 'New', schema: NewsSchema }])],
controllers: [NewsController],
controllers: [NewsController, NewsAdminController],
providers: [NewsService],
})
export class NewsModule {}
16 changes: 15 additions & 1 deletion src/features/news/news.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,22 @@ export class NewsService {

async getallNews(req: Request) {
const result = await this.newsModel.find();
const ids = result.map(order => order._id.toString());
return getHttpResponse.successResponse({
message: '取得所有資訊',
message: '取得所有最新資訊',
data: ids,
});
}

async getOneNews(id: string, req: Request) {
const result = await this.newsModel.findOne({
_id: id,
});
if (!result) {
throw new AppError(HttpStatus.NOT_FOUND, 'UserError', '此最新資訊不存在');
}
return getHttpResponse.successResponse({
message: '取得單筆最新資訊',
data: result,
});
}
Expand Down
Loading

0 comments on commit 80c5750

Please sign in to comment.