Skip to content

Commit

Permalink
Feat announcement (#87)
Browse files Browse the repository at this point in the history
  • Loading branch information
BlueHorn07 authored Dec 11, 2023
1 parent 7cc0c1c commit 46535a7
Show file tree
Hide file tree
Showing 9 changed files with 294 additions and 4 deletions.
44 changes: 42 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "popo-nest-api",
"version": "1.3.6",
"version": "1.4.0",
"description": "POPO, POstechian's POrtal; API",
"author": "bluehorn07",
"private": true,
Expand Down Expand Up @@ -36,6 +36,7 @@
"cookie-parser": "^1.4.6",
"email-validator": "^2.0.4",
"moment": "^2.29.4",
"moment-timezone": "^0.5.43",
"multer": "^1.4.2",
"mysql": "^2.18.1",
"nestjs-form-data": "1.9",
Expand All @@ -56,6 +57,7 @@
"@types/cookie-parser": "^1.4.6",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.11",
"@types/moment-timezone": "^0.5.30",
"@types/node": "^20.4.5",
"@types/passport-jwt": "^3.0.13",
"@types/passport-local": "^1.0.38",
Expand Down
4 changes: 3 additions & 1 deletion src/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Injectable } from '@nestjs/common';
import * as moment from 'moment';
import * as momentTz from "moment-timezone";

@Injectable()
export class AppService {
getHello(): string {
return `Hello POPO! (popo-${process.env.POPO_VERSION})`;
return `Hello POPO! (popo-${process.env.POPO_VERSION}) (server now: ${moment().format('YYYY-MM-DD HH:mm:ss')}, KST now: ${momentTz().tz("Asia/Seoul").format('YYYY-MM-DD HH:mm:ss')})`;
}
}
86 changes: 86 additions & 0 deletions src/popo/notice/notice.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
Put,
UseGuards,
} from '@nestjs/common';
import { ApiBody, ApiTags } from '@nestjs/swagger';
import * as moment from 'moment';

import { NoticeService } from './notice.service';
import { NoticeDto, NoticeImageDto } from './notice.dto';
import { UserType } from '../user/user.meta';
import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard';
import { Roles } from '../../auth/authroization/roles.decorator';
import { RolesGuard } from '../../auth/authroization/roles.guard';
import { FileService } from '../../file/file.service';
import { FileBody } from '../../file/file-body.decorator';

@ApiTags('Notice')
@Controller('notice')
export class NoticeController {
constructor(
private readonly noticeService: NoticeService,
private readonly fileService: FileService,
) {}

@Post()
@Roles(UserType.admin, UserType.association)
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiBody({ type: NoticeDto })
async create(@Body() dto: NoticeDto) {
return this.noticeService.save(dto);
}

@Post('image/:id')
@Roles(UserType.admin, UserType.association)
@UseGuards(JwtAuthGuard, RolesGuard)
@FileBody('image')
async uploadImage(@Param('id') id: number, @Body() dto: NoticeImageDto) {
const image_url = await this.fileService.uploadFile(
`notice/${id}/${moment().format('YYYY-MM-DD/HH:mm:ss')}`,
dto.image,
);
await this.noticeService.updateImageUrl(id, image_url);
return image_url;
}

@Get()
getAll() {
return this.noticeService.find();
}

@Get('active')
getAllActive() {
return this.noticeService.findActive();
}

@Get(':id')
async getOne(@Param('id') id: number) {
return this.noticeService.findOneById(id);
}

@Patch('click/:id')
increaseClickCount(@Param('id') id: number) {
return this.noticeService.increaseClickCount(id);
}

@Put(':id')
@Roles(UserType.admin, UserType.association, UserType.staff)
@UseGuards(JwtAuthGuard, RolesGuard)
async put(@Param('id') id: number, @Body() updateNoticeDto: NoticeDto) {
return this.noticeService.update(id, updateNoticeDto);
}

@Delete(':id')
@Roles(UserType.admin, UserType.association)
@UseGuards(JwtAuthGuard, RolesGuard)
async delete(@Param('id') id: number) {
this.noticeService.remove(id);
}
}
15 changes: 15 additions & 0 deletions src/popo/notice/notice.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { IsFile, MaxFileSize, MemoryStoredFile } from 'nestjs-form-data';

export class NoticeDto {
readonly title: string;
readonly content: string | null;
readonly start_datetime: string | null; // YYYY-MM-DD HH:mm:ss (KST)
readonly end_datetime: string | null; // YYYY-MM-DD HH:mm:ss (KST)
readonly link: string | null;
}

export class NoticeImageDto {
@IsFile()
@MaxFileSize(10 * 1024 * 1024) // 10MB
readonly image: MemoryStoredFile;
}
41 changes: 41 additions & 0 deletions src/popo/notice/notice.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
BaseEntity,
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';

@Entity()
export class Notice extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;

@Column({ nullable: false })
title: string;

@Column('text', { nullable: true })
content: string;

@Column({ nullable: true })
image_url: string;

@Column({ nullable: true })
link: string;

@Column({ nullable: false })
start_datetime: string; // YYYY-MM-DD HH:mm:ss (KST)

@Column({ nullable: false })
end_datetime: string; // YYYY-MM-DD HH:mm:ss (KST)

@Column({ default: 0})
click_count: number;

@CreateDateColumn()
createdAt: Date;

@UpdateDateColumn()
updateAt: Date;
}
20 changes: 20 additions & 0 deletions src/popo/notice/notice.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { NestjsFormDataModule } from 'nestjs-form-data';

import { NoticeController } from './notice.controller';
import { NoticeService } from './notice.service';
import { Notice } from './notice.entity';
import { FileModule } from '../../file/file.module';

@Module({
imports: [
TypeOrmModule.forFeature([Notice]),
NestjsFormDataModule,
FileModule,
],
controllers: [NoticeController],
providers: [NoticeService],
exports: [NoticeService],
})
export class NoticeModule {}
81 changes: 81 additions & 0 deletions src/popo/notice/notice.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { LessThan, MoreThanOrEqual, Repository } from 'typeorm';
import * as moment from "moment-timezone";

import { Notice } from './notice.entity';
import { NoticeDto } from './notice.dto';

const Message = {
NOT_EXISTING_REGION: "There's no such region.",
NOT_EXISTING_USER: "There's no such user.",
NOT_EXISTING_PLACE: "There's no such notice.",
INVALID_OWNER: 'Only Association can have a notice.',
INVALID_STAFF: 'Only Staff and ADMIN can be a manager.',
};

@Injectable()
export class NoticeService {
constructor(
@InjectRepository(Notice)
private readonly noticeRepo: Repository<Notice>,
) {}

save(dto: NoticeDto) {
return this.noticeRepo.save(dto);
}

updateImageUrl(id: number, image_url: string) {
return this.noticeRepo.update({ id: id }, { image_url: image_url });
}

find() {
return this.noticeRepo.find({ order: { updateAt: 'DESC' } });
}

findActive() {
const now = moment().tz("Asia/Seoul").format('YYYY-MM-DD HH:mm:ss');
return this.noticeRepo.find({
where: { start_datetime: LessThan(now), end_datetime: MoreThanOrEqual(now) }
});
}

findOneById(id: number) {
return this.noticeRepo.findOneBy({ id: id });
}

findOneByIdOrFail(id: number) {
const notice = this.findOneById(id);
if (!notice) {
throw new BadRequestException(Message.NOT_EXISTING_PLACE);
}
return notice;
}

async update(id: number, dto: NoticeDto) {
const existNotice = await this.findOneById(id);
if (!existNotice) {
throw new BadRequestException(Message.NOT_EXISTING_PLACE);
}

return this.noticeRepo.update({ id: id }, dto);
}

async increaseClickCount(id: number) {
const notice = await this.noticeRepo.findOneByOrFail({ id: id });
return this.noticeRepo.update(
{ id: id },
{ click_count: notice.click_count + 1 },
);
}

async remove(id: number) {
const existNotice = await this.findOneById(id);

if (!existNotice) {
throw new BadRequestException(Message.NOT_EXISTING_PLACE);
}

return this.noticeRepo.delete({ id: id });
}
}
3 changes: 3 additions & 0 deletions src/popo/popo.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Module } from '@nestjs/common';

import { BenefitModule } from './benefit/benefit.module';
import { EquipModule } from './equip/equip.module';
import { IntroduceModule } from './introduce/introduce.module';
import { NoticeModule } from './notice/notice.module';
import { PlaceModule } from './place/place.module';
import { ReservationModule } from './reservation/reservation.module';
import { SettingModule } from './setting/setting.module';
Expand All @@ -11,6 +13,7 @@ import { WhitebookModule } from './whitebook/whitebook.module';
@Module({
imports: [
BenefitModule,
NoticeModule,
PlaceModule,
EquipModule,
IntroduceModule,
Expand Down

0 comments on commit 46535a7

Please sign in to comment.