-
Notifications
You must be signed in to change notification settings - Fork 6
[SWEP-60] 날짜별 태그 검색 API, 태그로 이미지 검색 API 기능 구현과 여러 설정 #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 42 commits
c5e90ee
74d3768
37c686a
e89ad9f
818f37f
0654054
edf482d
30a498e
7a4143e
5e749fb
8c01216
7e6ba09
42bb522
39883ef
c3d8b73
04f768f
f352ca0
18e85a5
01fafa0
3c0409d
75fbe25
d5110da
6f93856
833a63f
dbffe8f
430b84b
42d7c85
c20859e
fac01c8
bdae5d4
228246f
6fb3189
ac82c5f
b79cd35
faa0b9d
d5095f2
da4df67
dfe67d3
fa85890
b9cd2ae
3ea7102
b07d091
af1f192
87c9238
50d7316
418a5f2
5c93237
51c24e6
5dac6fe
3459b1b
1190a17
f3b39f8
6f8a651
16c237c
cfde138
33dcb61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| { | ||
| "noImplicitAdditionalProperties": "throw-on-extras", | ||
| "entryFile": "src/app.ts", | ||
| "controllerPathGlobs": ["src/controllers/*.controller.ts"], | ||
| "spec": { | ||
| "outputDirectory": "./swagger", | ||
| "host": "localhost:3000", | ||
| "specVersion": 3, | ||
| "spec": { | ||
| "servers": [ | ||
| { | ||
| "url": "http://localhost:3000", | ||
| "description": "Sweepic server" | ||
| } | ||
| ] | ||
| } | ||
| }, | ||
| "routes": { | ||
| "routesDir": "./src/routers", | ||
| "middleware": "express", | ||
| "routesFileName": "tsoaRoutes.ts", | ||
| "esm": true | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,12 +4,14 @@ import express, {Request, Response, Express, NextFunction} from 'express'; | |
| import swaggerAutogen from 'swagger-autogen'; | ||
| import swaggerUiExpress from 'swagger-ui-express'; | ||
| import {memoFolderRouter} from './routers/memo.router.js'; | ||
| import {RegisterRoutes} from './routers/tsoaRoutes.js'; | ||
| import {challengeRouter} from './routers/challenge.router.js'; | ||
| import {authRouter} from './routers/auth.routers.js'; | ||
| import passport from 'passport'; | ||
| import session from 'express-session'; | ||
| import {PrismaSessionStore} from '@quixo3/prisma-session-store'; | ||
| import {prisma} from './db.config.js'; | ||
| import swaggerDocument from '../swagger/swagger.json' assert {type: 'json'}; | ||
|
|
||
| dotenv.config(); | ||
|
|
||
|
|
@@ -25,6 +27,12 @@ app.get('/', (req: Request, res: Response) => { | |
| res.send('Sweepic'); | ||
| }); | ||
|
|
||
| // app.use( | ||
| // '/docs', | ||
| // swaggerUiExpress.serve, | ||
| // swaggerUiExpress.setup(swaggerDocument), | ||
| // ); | ||
|
|
||
| app.use( | ||
| '/docs', | ||
| swaggerUiExpress.serve, | ||
|
|
@@ -80,7 +88,7 @@ app.use((req: Request, res: Response, next: NextFunction) => { | |
| }); | ||
|
|
||
| app.use('/memo', memoFolderRouter); | ||
|
|
||
| RegisterRoutes(app); | ||
|
||
| app.use('/challenge', challengeRouter); | ||
|
|
||
| app.use( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import { | ||
| Body, | ||
| Controller, | ||
| Get, | ||
| Path, | ||
| Post, | ||
| Query, | ||
| Res, | ||
| Route, | ||
| SuccessResponse, | ||
| Tags, | ||
| TsoaResponse, | ||
| } from 'tsoa'; | ||
| import {RequestTagSearch} from '../dtos/image.dto.js'; | ||
| import {findImagesFromTag} from '../services/image.service.js'; | ||
| import {StatusCodes} from 'http-status-codes'; | ||
|
|
||
| @Route('images') | ||
| export class ImagesController extends Controller { | ||
| @Get('/users/{userId}') | ||
| @Tags('Image') | ||
| @SuccessResponse('200', 'OK') | ||
| public async getImageListFromTag( | ||
| @Path() userId: string, | ||
| @Query() tag: string, | ||
| ): Promise<{id: string; mediaId: string}[]> { | ||
| const dto = new RequestTagSearch(tag, userId); | ||
| console.log(dto); | ||
| const images = await findImagesFromTag(dto).catch(err => { | ||
| err.statusCode = StatusCodes.NOT_FOUND; | ||
| throw err; | ||
| }); | ||
|
|
||
| return images; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import { | ||
| Body, | ||
| Controller, | ||
| Get, | ||
| Path, | ||
| Post, | ||
| Query, | ||
| Res, | ||
| Route, | ||
| SuccessResponse, | ||
| TsoaResponse, | ||
| Tags, | ||
| } from 'tsoa'; | ||
| import {findTagsByDate} from '../services/tsoaTag.service.js'; | ||
| import {DateToTags} from '../dtos/tsoaTag.dto.js'; | ||
| import {StatusCodes} from 'http-status-codes'; | ||
|
|
||
| @Route('tags') | ||
| export class TagsController extends Controller { | ||
| @Get('/users/{userId}') | ||
| @Tags('Tag') | ||
| @SuccessResponse('200', 'OK') | ||
| public async getTagListWithDate( | ||
| @Path() userId: string, | ||
| @Query() year: number, | ||
| @Query() month: number, | ||
| @Query() date?: number, | ||
| ): Promise<{tags: string[]}> { | ||
| const dto = new DateToTags(userId, year, month, date); | ||
| const tags = await findTagsByDate(dto) | ||
| .then(result => { | ||
| return {tags: result}; | ||
| }) | ||
| .catch(err => { | ||
| err.statusCode = StatusCodes.NOT_FOUND; | ||
| throw err; | ||
| }); | ||
| return tags; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| export class RequestTagSearch { | ||
| tag: string; | ||
| userId: bigint; | ||
|
|
||
| constructor(tag: string, userId: string) { | ||
| this.tag = tag; | ||
| this.userId = BigInt(userId); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| export class DateToTags { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 tag 부분의 dto를 간단하게 썼는데 class 사용해서 만드셨네요. 혹시 이유가 있을까요? |
||
| createdAt: Date; | ||
| userId: bigint; | ||
| dateExisted: boolean = true; | ||
|
|
||
| constructor(userId: string, year: number, month: number, date?: number) { | ||
| if (!date) { | ||
| date = 1; | ||
| this.dateExisted = false; | ||
| } | ||
| this.createdAt = new Date(year, month - 1, date); | ||
| this.createdAt.setHours(this.createdAt.getHours() + 9); | ||
| this.userId = BigInt(userId); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export interface ResponseFromTags { | ||
| tags: string[]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import {Image} from '@prisma/client'; | ||
| import {prisma} from '../db.config.js'; | ||
|
|
||
| export const selectImagesFromTag = async ( | ||
| tag: string, | ||
| userId: bigint, | ||
| ): Promise<Pick<Image, 'id' | 'mediaId'>[]> => { | ||
|
||
| const images = await prisma.image.findMany({ | ||
| where: { | ||
| AND: [ | ||
| { | ||
| tags: { | ||
| some: { | ||
| tag: { | ||
| content: tag, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| userId: userId, | ||
| }, | ||
| ], | ||
| }, | ||
| select: { | ||
| id: true, | ||
| mediaId: true, | ||
| }, | ||
| }); | ||
| return images; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| import {Tag} from '@prisma/client'; | ||
| import {DateToTags} from '../dtos/tsoaTag.dto.js'; | ||
| import {prisma} from '../db.config.js'; | ||
|
|
||
| export const selectTagsByDate = async ( | ||
| dto: DateToTags, | ||
| endDate: Date, | ||
| ): Promise<Pick<Tag, 'content'>[]> => { | ||
| const tags = await prisma.tag | ||
| .findMany({ | ||
| where: { | ||
| images: { | ||
| some: { | ||
| AND: [ | ||
| { | ||
| image: { | ||
| createdAt: { | ||
| gte: dto.createdAt, | ||
| lt: endDate, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| image: { | ||
| userId: dto.userId, | ||
| }, | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
| }, | ||
| select: { | ||
| content: true, | ||
| }, | ||
| orderBy: { | ||
| content: 'asc', | ||
| }, | ||
| }) | ||
| .catch(() => { | ||
| throw new Error('DB 에러'); | ||
| }); | ||
|
|
||
| console.log(dto.createdAt); | ||
| console.log(endDate); | ||
| return tags; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| /* tslint:disable */ | ||
| /* eslint-disable */ | ||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
| import type {TsoaRoute} from '@tsoa/runtime'; | ||
| import {fetchMiddlewares, ExpressTemplateService} from '@tsoa/runtime'; | ||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
| import {TagsController} from './../controllers/tsoaTag.controller.js'; | ||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
| import {ImagesController} from './../controllers/image.controller.js'; | ||
| import type { | ||
| Request as ExRequest, | ||
| Response as ExResponse, | ||
| RequestHandler, | ||
| Router, | ||
| } from 'express'; | ||
|
|
||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
|
|
||
| const models: TsoaRoute.Models = {}; | ||
| const templateService = new ExpressTemplateService(models, { | ||
| noImplicitAdditionalProperties: 'throw-on-extras', | ||
| bodyCoercion: true, | ||
| }); | ||
|
|
||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
|
|
||
| export function RegisterRoutes(app: Router) { | ||
| // ########################################################################################################### | ||
| // NOTE: If you do not see routes for all of your controllers in this file, then you might not have informed tsoa of where to look | ||
| // Please look into the "controllerPathGlobs" config option described in the readme: https://github.com/lukeautry/tsoa | ||
| // ########################################################################################################### | ||
|
|
||
| const argsTagsController_getTagListWithDate: Record< | ||
| string, | ||
| TsoaRoute.ParameterSchema | ||
| > = { | ||
| userId: {in: 'path', name: 'userId', required: true, dataType: 'string'}, | ||
| year: {in: 'query', name: 'year', required: true, dataType: 'double'}, | ||
| month: {in: 'query', name: 'month', required: true, dataType: 'double'}, | ||
| date: {in: 'query', name: 'date', dataType: 'double'}, | ||
| }; | ||
| app.get( | ||
| '/tags/users/:userId', | ||
| ...fetchMiddlewares<RequestHandler>(TagsController), | ||
| ...fetchMiddlewares<RequestHandler>( | ||
| TagsController.prototype.getTagListWithDate, | ||
| ), | ||
|
|
||
| async function TagsController_getTagListWithDate( | ||
| request: ExRequest, | ||
| response: ExResponse, | ||
| next: any, | ||
| ) { | ||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
|
|
||
| let validatedArgs: any[] = []; | ||
| try { | ||
| validatedArgs = templateService.getValidatedArgs({ | ||
| args: argsTagsController_getTagListWithDate, | ||
| request, | ||
| response, | ||
| }); | ||
|
|
||
| const controller = new TagsController(); | ||
|
|
||
| await templateService.apiHandler({ | ||
| methodName: 'getTagListWithDate', | ||
| controller, | ||
| response, | ||
| next, | ||
| validatedArgs, | ||
| successStatus: 200, | ||
| }); | ||
| } catch (err) { | ||
| return next(err); | ||
| } | ||
| }, | ||
| ); | ||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
| const argsImagesController_getImageListFromTag: Record< | ||
| string, | ||
| TsoaRoute.ParameterSchema | ||
| > = { | ||
| userId: {in: 'path', name: 'userId', required: true, dataType: 'string'}, | ||
| tag: {in: 'query', name: 'tag', required: true, dataType: 'string'}, | ||
| }; | ||
| app.get( | ||
| '/images/users/:userId', | ||
| ...fetchMiddlewares<RequestHandler>(ImagesController), | ||
| ...fetchMiddlewares<RequestHandler>( | ||
| ImagesController.prototype.getImageListFromTag, | ||
| ), | ||
|
|
||
| async function ImagesController_getImageListFromTag( | ||
| request: ExRequest, | ||
| response: ExResponse, | ||
| next: any, | ||
| ) { | ||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
|
|
||
| let validatedArgs: any[] = []; | ||
| try { | ||
| validatedArgs = templateService.getValidatedArgs({ | ||
| args: argsImagesController_getImageListFromTag, | ||
| request, | ||
| response, | ||
| }); | ||
|
|
||
| const controller = new ImagesController(); | ||
|
|
||
| await templateService.apiHandler({ | ||
| methodName: 'getImageListFromTag', | ||
| controller, | ||
| response, | ||
| next, | ||
| validatedArgs, | ||
| successStatus: 200, | ||
| }); | ||
| } catch (err) { | ||
| return next(err); | ||
| } | ||
| }, | ||
| ); | ||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
|
|
||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
|
|
||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa | ||
| } | ||
|
|
||
| // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분이 문제이군요. 남겨두겠습니다 ~