Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
c5e90ee
Initial commit
jjiinaaa Dec 23, 2024
74d3768
Update README.md
jjiinaaa Dec 23, 2024
37c686a
[SWEP-1] Jira Test
jjiinaaa Dec 23, 2024
e89ad9f
[SWEP-6] Jira Autumation Test
jjiinaaa Dec 24, 2024
818f37f
[SWEP-6] Jira Autumation Test
jjiinaaa Dec 24, 2024
0654054
[SWEP-17] Server PR Template
jjiinaaa Dec 30, 2024
edf482d
Update README.md
jjiinaaa Dec 30, 2024
30a498e
[SWEP-19] Issue Template
jjiinaaa Dec 30, 2024
7a4143e
[SWEP-17] PR Template
jjiinaaa Dec 31, 2024
5e749fb
[SWEP-19] Issue Template
jjiinaaa Dec 31, 2024
8c01216
Update: issue 템플릿 수정 (#6)
jjiinaaa Jan 4, 2025
7e6ba09
[SWEP-12] 초기 설정 및 Readme 파일 구성 (#10)
jjiinaaa Jan 4, 2025
42bb522
[SWEP-22] CI/CD 파이프라인 구축 (#13)
asjasj3964 Jan 7, 2025
39883ef
[SWEP-28] GTS 적용 및 코드 컨벤션 문서 정리 (#18)
jjiinaaa Jan 9, 2025
c3d8b73
[SWEP-35] Swagger 초기 설정 (#23)
jjiinaaa Jan 9, 2025
04f768f
[SWEP-35] 빌드 시 스웨거 문서 미복사 문제 해결 (#27) (#28)
jjiinaaa Jan 11, 2025
f352ca0
[SWEP-43] AWS S3 클라이언트 설정 및 파일 관리 함수 구현 (#36)
asjasj3964 Jan 15, 2025
18e85a5
[SWEP-36] schema.prisma 작성완료
GodUser1005 Jan 15, 2025
01fafa0
Merge branch 'feat/db-schema' into develop
GodUser1005 Jan 15, 2025
3c0409d
[SWEP-36] migration 파일 일부 수정
GodUser1005 Jan 15, 2025
75fbe25
[SWEP-36] ./src/models/user.model.ts 에서 UserModel 수정
GodUser1005 Jan 15, 2025
d5110da
Merge pull request #39 from GodUser1005/develop
GodUser1005 Jan 15, 2025
6f93856
Merge pull request #40 from Sweepic/feature/SWEP-36
GodUser1005 Jan 16, 2025
833a63f
[SWEP-42] 메모장 POST API 구현 (#46)
asjasj3964 Jan 20, 2025
dbffe8f
[SWEP-37] 위치 기반 챌린지 API
codie0226 Jan 21, 2025
430b84b
[SWEP-51] Session 테이블 수정 및 마이그레이션 추가
GodUser1005 Jan 21, 2025
42d7c85
Merge pull request #56 from GodUser1005/develop
GodUser1005 Jan 21, 2025
c20859e
[SWEP-37] swagger 적용, 피드백 반영 및 코드 수정
codie0226 Jan 21, 2025
fac01c8
Merge pull request #57 from Sweepic/fix/SWEP-51
GodUser1005 Jan 21, 2025
bdae5d4
Merge pull request #52 from Sweepic/feature/SWEP-37
codie0226 Jan 21, 2025
228246f
tsconfig.json update(enable tsoa decorator)
GodUser1005 Jan 22, 2025
6fb3189
[SWEP-50] 메모장 조회 API 구현 (#59)
asjasj3964 Jan 23, 2025
ac82c5f
[SWEP-40] 소셜 로그인 구현 (#62)
Socializedistp Jan 23, 2025
b79cd35
날짜별 태그보기 API 구현
GodUser1005 Jan 23, 2025
faa0b9d
Merge branch 'develop' of github.com:GodUser1005/sweepic-Server into …
GodUser1005 Jan 23, 2025
d5095f2
feat: 태그 검색기능 구현
GodUser1005 Jan 23, 2025
da4df67
chore: tsoa 설정파일 tsoa.json 설정
GodUser1005 Jan 23, 2025
dfe67d3
chore: tsconfig.json node 버전 높은버전사용
GodUser1005 Jan 23, 2025
fa85890
chore: swagger 폴더 생성 및 정적파일 생성
GodUser1005 Jan 23, 2025
b9cd2ae
gitignore update
GodUser1005 Jan 23, 2025
3ea7102
resolve conflict
GodUser1005 Jan 23, 2025
b07d091
Merge pull request #84 from GodUser1005/develop
GodUser1005 Jan 23, 2025
af1f192
resolve conflict app.ts
GodUser1005 Jan 26, 2025
87c9238
resolve conflict app.ts, tsconfig.json
GodUser1005 Jan 26, 2025
50d7316
[SWEP-60] 스웨거 문서 두개로 나눠 출력, git workflow tsoa 스웨거문서 생성 추가
GodUser1005 Jan 27, 2025
418a5f2
Merge branch 'develop' of github.com:GodUser1005/sweepic-Server into …
GodUser1005 Jan 27, 2025
5c93237
[SWEP-60] Image관련 파일명 -> tsoaImage로 변환
GodUser1005 Jan 27, 2025
51c24e6
[SWEP-60] tsoaRoutes.ts 수정
GodUser1005 Jan 27, 2025
5dac6fe
[SWEP-60] build.ts console.log 삭제
GodUser1005 Jan 27, 2025
3459b1b
resolve conflict error response
GodUser1005 Jan 27, 2025
1190a17
memo-ocr 경로관련 코드 수정
GodUser1005 Jan 27, 2025
f3b39f8
[SWEP-60] tsoaResponse 클래스 생성
GodUser1005 Jan 27, 2025
6f8a651
[SWEP-60] tag error 응답 통일
GodUser1005 Jan 27, 2025
16c237c
[SWEP-60] 태그기반 이미지 검색 응답통일
GodUser1005 Jan 27, 2025
cfde138
[SWEP-60] 깃허브 액션 워크플로우 ai-key 전달 추가
GodUser1005 Jan 27, 2025
33dcb61
Merge pull request #114 from GodUser1005/develop
GodUser1005 Jan 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/deploy-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
node-version: '20'

- name: Install dependencies
run: |
Expand All @@ -35,6 +35,7 @@ jobs:
- name: Generate Swagger document
run: |
yarn tsx ./swagger/swagger.js
yarn tsoa spec -c ./config/tsoa.json

- name: Run build
run: |
Expand Down Expand Up @@ -70,6 +71,9 @@ jobs:
ssh sweepic-ec2 'sudo mkdir -p /opt/app'
ssh sweepic-ec2 'sudo chown ubuntu:ubuntu /opt/app'
scp -r ./dist sweepic-ec2:/opt/app
ssh sweepic-ec2 'sudo echo "$SWEEPIC_AI" > /opt/app/sweepicai-00d515e813ea.json'
env:
SWEEPIC_AI: ${{secrets.SWEEPIC_AI}}

# 원격 서버에서 애플리케이션을 Systemd 서비스로 등록하는 과정
- name: Copy systemd service file
Expand All @@ -83,6 +87,7 @@ jobs:
User=${USER}
WorkingDirectory=/opt/app
ExecStart=/usr/bin/node dist/app.cjs
ExecStart=/usr/bin/node dist/app.cjs
Restart=always

[Install]
Expand Down
24 changes: 24 additions & 0 deletions config/tsoa.json
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": "3.37.137.212:3000",
"specVersion": 3,
"spec": {
"servers": [
{
"url": "http://3.37.137.212:3000",
"description": "Sweepic server"
}
]
}
},
"routes": {
"routesDir": "./src/routers",
"middleware": "express",
"routesFileName": "tsoaRoutes.ts",
"esm": true
}
}
20 changes: 12 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
"fix": "gts fix",
"prepare": "yarn run compile",
"pretest": "yarn run compile",
"posttest": "yarn run lint"
"posttest": "yarn run lint",
"swagger": "tsx swagger/swagger.ts",
"tsoa-swagger": "tsoa spec -c ./config/tsoa.json",
"tsoa-routes": "tsoa routes -c ./config/tsoa.json"
},
"author": "",
"license": "ISC",
Expand All @@ -25,6 +28,7 @@
"@google-cloud/vision": "^4.3.2",
"@prisma/client": "^6.1.0",
"@quixo3/prisma-session-store": "^3.1.13",
"@tsoa/runtime": "^6.6.0",
"coordinate-parser": "^1.0.7",
"cors": "^2.8.5",
"dotenv": "^16.4.7",
Expand All @@ -50,24 +54,24 @@
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/express-session": "^1.18.1",
"@types/multer": "^1.4.12",
"@types/multer-s3": "^3.0.3",
"@types/node": "^22.10.3",
"@types/passport": "^1.0.17",
"@types/passport-google-oauth20": "^2.0.16",
"@types/swagger-ui-express": "^4.1.7",
"@typescript-eslint/eslint-plugin": "^8.19.1",
"@typescript-eslint/parser": "^8.19.1",
"@types/multer": "^1.4.12",
"@types/multer-s3": "^3.0.3",
"@types/passport-kakao": "^1.0.3",
"@types/passport-naver": "^1.0.4",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.7",
"@typescript-eslint/eslint-plugin": "^8.19.1",
"@typescript-eslint/parser": "^8.19.1",
"esbuild": "^0.24.2",
"esbuild-plugin-copy": "^2.1.1",
"eslint": "^9.17.0",
"gts": "^6.0.2",
"nodemon": "^3.1.9",
"tsoa": "^6.6.0",
"tsx": "^4.19.2",
"typescript": "^5.6.3",
"tsoa": "^6.6.0"
"typescript": "^5.6.3"
}
}
2 changes: 1 addition & 1 deletion scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ async function build() {
outExtension: {'.js': '.cjs'},
platform: 'node',
target: 'node20',
minify: true,
minify: false,
keepNames: true,
plugins: [
copy({
Expand Down
33 changes: 27 additions & 6 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ import express, {
NextFunction,
ErrorRequestHandler,
} 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 swaggerDocumentOne from '../swagger/openapi.json' assert {type: 'json'};
import swaggerDocumentTwo from '../swagger/swagger.json' assert {type: 'json'};
import {BaseError} from './errors.js';
import swaggerDocument from '../swagger/openapi.json' assert {type: 'json'};
import {ValidateError} from 'tsoa';

dotenv.config();

Expand All @@ -32,9 +34,15 @@ app.use(express.urlencoded({extended: false}));

// Swagger Docs
app.use(
'/docs',
swaggerUiExpress.serve,
swaggerUiExpress.setup(swaggerDocument),
'/docs/v1',
swaggerUiExpress.serveFiles(swaggerDocumentOne),
swaggerUiExpress.setup(swaggerDocumentOne),
);

app.use(
'/docs/v2',
swaggerUiExpress.serveFiles(swaggerDocumentTwo),
swaggerUiExpress.setup(swaggerDocumentTwo),
);

// Response customization middleware
Expand Down Expand Up @@ -85,10 +93,11 @@ app.use(

app.use(passport.initialize());
app.use(passport.session());

app.use('/oauth2', authRouter);

app.use('/memo', memoFolderRouter);
app.use('/challenge', challengeRouter);
RegisterRoutes(app);

app.get('/', (req: Request, res: Response) => {
res.send('Sweepic');
Expand All @@ -113,6 +122,18 @@ const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
return;
}

if (err instanceof ValidateError) {
res.status(err.status).json({
resultType: 'FAIL',
error: {
errorCode: 'VAL-001',
reason: 'Validation Error',
data: err.fields,
},
success: null,
});
}

console.error('Unexpected error:', err);
res.status(500).json({
resultType: 'FAIL',
Expand Down
39 changes: 39 additions & 0 deletions src/controllers/tsoaImage.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
Body,
Controller,
Get,
Path,
Post,
Query,
Res,
Route,
SuccessResponse,
Tags,
TsoaResponse,
} from 'tsoa';
import {RequestTagSearch} from '../dtos/tsoaImage.dto.js';
import {findImagesFromTag} from '../services/tsoaImage.service.js';
import {BaseError, ServerError} from '../errors.js';
import {Response} from '../models/tsoaResponse.js';

@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<Response> {
const dto = new RequestTagSearch(tag, userId);
const images = await findImagesFromTag(dto).catch(err => {
if (err instanceof BaseError) {
throw err;
} else {
throw new ServerError();
}
});

return new Response(images);
}
}
45 changes: 45 additions & 0 deletions src/controllers/tsoaTag.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
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 {BaseError, ServerError, TagBadRequest} from '../errors.js';
import {Response} from '../models/tsoaResponse.js';

@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<Response> {
const dto = new DateToTags(userId, year, month, date);
const tags = await findTagsByDate(dto)
.then(result => {
return {tags: result};
})
.catch(err => {
if (!(err instanceof BaseError)) {
throw new ServerError();
} else {
throw err;
}
});

return new Response(tags);
}
}
9 changes: 9 additions & 0 deletions src/dtos/tsoaImage.dto.ts
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);
}
}
14 changes: 14 additions & 0 deletions src/dtos/tsoaTag.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export class DateToTags {
Copy link
Contributor

Choose a reason for hiding this comment

The 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(Date.UTC(year, month - 1, date));
this.userId = BigInt(userId);
}
}
28 changes: 28 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {extname} from 'path';

export type ErrorDetails =
| {folderId?: bigint; userId?: bigint; folderName?: string}
| {imageId?: bigint; imageUrl?: string}
Expand Down Expand Up @@ -122,3 +124,29 @@ export class PhotoDataNotFoundError extends BaseError {
super(404, 'PHO-404', '사진 데이터가 없습니다.', details);
}
}

// 태그 데이터 관련 에러(TAG)
export class TagNotFound extends BaseError {
constructor() {
super(404, 'TAG-001', '태그가 없습니다.');
}
}

export class TagBadRequest extends BaseError {
constructor() {
super(400, 'TAG-002', '잘못된 요청입니다.');
}
}

// 공용 에러
export class DBError extends BaseError {
constructor(details?: ErrorDetails) {
super(500, 'DB-001', 'DB 에러입니다.', details);
}
}

export class ServerError extends BaseError {
constructor(details?: ErrorDetails) {
super(500, 'SER-001', '내부 서버 오류입니다.', details);
}
}
9 changes: 9 additions & 0 deletions src/models/tsoaResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export class Response {
resultType: string = 'SUCCESS';
error = null;
success: {data: any};

constructor(data: any) {
this.success = {data};
}
}
3 changes: 3 additions & 0 deletions src/models/tsoaTag.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface ResponseFromTags {
tags: string[];
}
36 changes: 36 additions & 0 deletions src/repositories/tsoaImage.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {Image} from '@prisma/client';
import {prisma} from '../db.config.js';
import {DBError} from '../errors.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,
},
})
.catch(() => {
throw new DBError();
});
return images;
};
Loading
Loading