From b385774523bdfbe24f05a96c9f9721e055930a60 Mon Sep 17 00:00:00 2001 From: sunrabbit123 Date: Fri, 24 Dec 2021 09:51:33 +0900 Subject: [PATCH 1/2] add Only Admin decorator --- src/DTO/user.dto.ts | 4 ++++ src/middleware/auth.ts | 20 +++++++++++++++++++- src/repository/user.ts | 13 +++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/repository/user.ts diff --git a/src/DTO/user.dto.ts b/src/DTO/user.dto.ts index c4cbc5d..260c46f 100644 --- a/src/DTO/user.dto.ts +++ b/src/DTO/user.dto.ts @@ -1 +1,5 @@ export type IdentityType = "faculty" | "graduate" | "student"; +export interface DecodedAccessToken { + isAdmin: boolean; + email: string; +} diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts index 4a143d0..d49d69b 100644 --- a/src/middleware/auth.ts +++ b/src/middleware/auth.ts @@ -1,5 +1,5 @@ import { APIGatewayEvent } from "aws-lambda"; -import { getRepository } from "typeorm"; +import { getCustomRepository, getRepository } from "typeorm"; import { ALLOWED_ORIGINS, createErrorRes, createRes } from "../util/http"; import { verifyToken } from "../util/token"; @@ -7,6 +7,8 @@ import { checkQuestionAnswer } from "../util/verify"; import { User } from "../entity"; import jwt, { JwtPayload } from "jsonwebtoken"; import { issuer } from "../config"; +import { UserRepository } from "../repository/user"; +import { DecodedAccessToken } from "../DTO/user.dto"; export class AuthMiddleware { static onlyOrigin(_: any, __: string, desc: PropertyDescriptor) { const originMethod = desc.value; // get function with a decorator on it. @@ -126,4 +128,20 @@ export class AuthMiddleware { return originMethod.apply(this, args); }; } + static onlyAdmin(_: any, __: string, desc: PropertyDescriptor) { + const originMethod = desc.value; + + desc.value = async function (...args: any[]) { + const req: APIGatewayEvent = args[0]; + const token: string = req.headers.Authorization; + + const { email } = verifyToken(token) as DecodedAccessToken; + const userRepo = getCustomRepository(UserRepository); + const isAdmin = await userRepo.getIsAdminByEmail(email); + + return isAdmin + ? originMethod.apply(this, args) + : createErrorRes({ errorCode: "JL002", status: 401 }); + }; + } } diff --git a/src/repository/user.ts b/src/repository/user.ts new file mode 100644 index 0000000..789f704 --- /dev/null +++ b/src/repository/user.ts @@ -0,0 +1,13 @@ +import { EntityRepository, Repository } from "typeorm"; +import { User } from "../entity/User"; + +@EntityRepository(User) +export class UserRepository extends Repository { + async getIsAdminByEmail(email: string): Promise { + return ( + await this.createQueryBuilder("user") + .where("user.email = :email", { email }) + .getOne() + ).isAdmin; + } +} From 0686af92508dfca20d5d4b7bd5e7a494eea8d444 Mon Sep 17 00:00:00 2001 From: sunrabbit123 Date: Fri, 24 Dec 2021 14:42:20 +0900 Subject: [PATCH 2/2] add : modify and delete Algorithm --- serverless.yml | 9 ++++---- src/DTO/algorithm.dto.ts | 2 ++ src/middleware/auth.ts | 1 + src/repository/algorithm.ts | 9 ++++++++ src/router/algorithm/algorithm.service.ts | 28 ++++++++++++++++++++++- src/router/algorithm/index.ts | 21 +++++++++++++---- src/util/http.ts | 4 +++- src/util/number.ts | 2 ++ 8 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 src/util/number.ts diff --git a/serverless.yml b/serverless.yml index e304921..c753cc7 100644 --- a/serverless.yml +++ b/serverless.yml @@ -88,16 +88,16 @@ functions: method: delete cors: true - changeStatusAlgorithm: - handler: src/handler.setAlgorithmStatus + modifyAlgorithm: + handler: src/handler.modifyAlogirithemContent events: - http: path: algoirthm/{id} method: patch cors: true - modifyAlgorithm: - handler: src/handler.modifyAlogirithemContent + changeStatusAlgorithm: + handler: src/handler.setAlgorithmStatus events: - http: path: algoirthm/{id}/status @@ -111,6 +111,7 @@ functions: path: verify method: get cors: true + addVerify: handler: src/handler.addVerifyQuestion events: diff --git a/src/DTO/algorithm.dto.ts b/src/DTO/algorithm.dto.ts index 5ac6c89..8ec26c3 100644 --- a/src/DTO/algorithm.dto.ts +++ b/src/DTO/algorithm.dto.ts @@ -9,3 +9,5 @@ export type AlgorithmStatusType = | "ACCEPTED" | "REJECTED" | "REPORTED"; + +export interface ModifyAlgorithmDTO extends BaseAlgorithmDTO {} diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts index d49d69b..5cbdd02 100644 --- a/src/middleware/auth.ts +++ b/src/middleware/auth.ts @@ -15,6 +15,7 @@ export class AuthMiddleware { desc.value = async function (...args: any[]) { // argument override const req: APIGatewayEvent = args[0]; + const origin = req.headers.Origin || req.headers.origin; if (!ALLOWED_ORIGINS.includes(origin) && origin) { // ignore request from not allowed origin diff --git a/src/repository/algorithm.ts b/src/repository/algorithm.ts index 3d69b47..302b5da 100644 --- a/src/repository/algorithm.ts +++ b/src/repository/algorithm.ts @@ -1,4 +1,5 @@ import { EntityRepository, Repository } from "typeorm"; +import { ModifyAlgorithmDTO } from "../DTO/algorithm.dto"; import { Algorithm } from "../entity"; @@ -11,4 +12,12 @@ export class AlgorithmRepository extends Repository { .groupBy("algorithm.algorithmStatus") .getRawMany(); } + + async modifyAlgorithm(id: number, data: ModifyAlgorithmDTO) { + return this.update(id, data); + } + + async deleteAlgorithm(id: number) { + return this.delete(id); + } } diff --git a/src/router/algorithm/algorithm.service.ts b/src/router/algorithm/algorithm.service.ts index 66228ce..4dfa3d4 100644 --- a/src/router/algorithm/algorithm.service.ts +++ b/src/router/algorithm/algorithm.service.ts @@ -1,11 +1,13 @@ +import { APIGatewayEvent } from "aws-lambda"; import { getCustomRepository, getRepository } from "typeorm"; import { bold13, bold15, ruleForWeb, rules } from "../../config"; -import { BaseAlgorithmDTO } from "../../DTO/algorithm.dto"; +import { BaseAlgorithmDTO, ModifyAlgorithmDTO } from "../../DTO/algorithm.dto"; import { Algorithm } from "../../entity"; import { AlgorithmRepository } from "../../repository/algorithm"; import { getLastPostNumber } from "../../util/algorithm"; import { createErrorRes, createRes } from "../../util/http"; +import { isNumeric } from "../../util/number"; export const AlgorithmService: { [k: string]: Function } = { writeAlgorithm: async ({ title, content, tag }: BaseAlgorithmDTO) => { @@ -48,6 +50,30 @@ export const AlgorithmService: { [k: string]: Function } = { }, }); }, + modifyAlgorithmContent: async (event: APIGatewayEvent) => { + const { id } = event.pathParameters; + + if (!isNumeric(id)) { + return createErrorRes({ errorCode: "JL007" }); + } + + const data: ModifyAlgorithmDTO = JSON.parse(event.body); + const algorithmRepo = getCustomRepository(AlgorithmRepository); + return createRes({ + body: await algorithmRepo.modifyAlgorithm(Number(id), data), + }); + }, + deleteAlgorithm: async (event: APIGatewayEvent) => { + const { id } = event.pathParameters; + + if (!isNumeric(id)) { + return createErrorRes({ errorCode: "JL007" }); + } + + const algorithmRepo = getCustomRepository(AlgorithmRepository); + await algorithmRepo.deleteAlgorithm(Number(id)); + return createRes({}); + }, }; const checkArgument: Function = (...args: any[]): boolean => { diff --git a/src/router/algorithm/index.ts b/src/router/algorithm/index.ts index 9193cce..90c5ab2 100644 --- a/src/router/algorithm/index.ts +++ b/src/router/algorithm/index.ts @@ -9,7 +9,7 @@ export class AlgorithmRouter { static async getAlgorithmCountAtAll(_: APIGatewayEvent, __: any) { return AlgorithmService.getAlgorithmCountAtAll(); } - + static async getAlgorithmRules(_: APIGatewayEvent, __: any) { return AlgorithmService.getAlgorithmRules(); } @@ -27,9 +27,22 @@ export class AlgorithmRouter { static async wirteAlgorithm(event: APIGatewayEvent, _: any, __: Function) { return AlgorithmService.writeAlgorithm(JSON.parse(event.body)); } - + static async setAlgorithmStatus() {} - static async modifyAlgorithmContent() {} + + @AuthMiddleware.onlyOrigin + @DBMiddleware.connectTypeOrm + @AuthMiddleware.onlyAdmin + static async modifyAlgorithmContent(event: APIGatewayEvent, _: any) { + return AlgorithmService.modifyAlgorithmContent(event); + } + static async reportAlgorithm() {} - static async deleteAlgorithm() {} + + @AuthMiddleware.onlyOrigin + @DBMiddleware.connectTypeOrm + @AuthMiddleware.onlyAdmin + static async deleteAlgorithm(event: APIGatewayEvent, _: any) { + return AlgorithmService.deleteAlgorithm(event); + } } diff --git a/src/util/http.ts b/src/util/http.ts index 57b6960..5d25d20 100644 --- a/src/util/http.ts +++ b/src/util/http.ts @@ -17,6 +17,7 @@ export const ERROR_CODE_LIST: { [key in ErrorCodeType]: string } = { JL004: "예상치 못한 에러입니다. 개발자에게 문의해주세요.", JL005: "Token 값을 찾을수 없습니다.", JL006: "Token 인증이 실패하였습니다.", + JL007: "잘못된 요청입니다.", } as const; export type ErrorCodeType = @@ -25,7 +26,8 @@ export type ErrorCodeType = | "JL003" | "JL004" | "JL005" - | "JL006"; + | "JL006" + | "JL007"; export const createRes = ({ statusCode, diff --git a/src/util/number.ts b/src/util/number.ts new file mode 100644 index 0000000..2039484 --- /dev/null +++ b/src/util/number.ts @@ -0,0 +1,2 @@ +export const isNumeric: Function = (data: string): boolean => + !isNaN(Number(data));