Skip to content

Commit

Permalink
Merge pull request #9 from IN-SOPT-SERVER/seminar7
Browse files Browse the repository at this point in the history
[7주차] 기본 과제 제출
  • Loading branch information
yeseul106 authored Jan 21, 2023
2 parents a9e92df + c981f4c commit 34a4354
Show file tree
Hide file tree
Showing 36 changed files with 2,435 additions and 839 deletions.
3 changes: 0 additions & 3 deletions seminar6/Basic/.gitignore

This file was deleted.

1 change: 0 additions & 1 deletion seminar6/Basic/src/controller/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion seminar6/Basic/src/middlewares/index.ts

This file was deleted.

826 changes: 0 additions & 826 deletions seminar6/Basic/yarn.lock

This file was deleted.

146 changes: 146 additions & 0 deletions seminar7/Basic/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Created by https://www.toptal.com/developers/gitignore/api/node
# Edit at https://www.toptal.com/developers/gitignore?templates=node

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output

# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

### Node Patch ###
# Serverless Webpack directories
.webpack/

# Optional stylelint cache

# SvelteKit build / generate output
.svelte-kit

# End of https://www.toptal.com/developers/gitignore/api/node.DS_Store

.DS_Store
File renamed without changes.
6 changes: 6 additions & 0 deletions seminar6/Basic/package.json → seminar7/Basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@
"@types/express": "^4.17.14",
"@types/express-validator": "^3.0.0",
"@types/jsonwebtoken": "^8.5.9",
"@types/multer": "^1.4.7",
"@types/multer-s3": "^3.0.0",
"@types/node": "^18.11.9",
"nodemon": "^2.0.20"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.216.0",
"@prisma/client": "^4.5.0",
"bcryptjs": "^2.4.3",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-validator": "^6.14.2",
"jsonwebtoken": "^8.5.1",
"multer": "^1.4.5-lts.1",
"multer-s3": "^3.0.1",
"prisma": "^4.5.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,14 @@ model User {
age Int?
email String @db.VarChar(400)
password String @db.VarChar(400)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model Image {
id Int @id @default(autoincrement())
image String? @db.VarChar(800)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
27 changes: 27 additions & 0 deletions seminar7/Basic/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// src/config/index.ts
import dotenv from "dotenv";

// Set the NODE_ENV to 'development' by default
process.env.NODE_ENV = process.env.NODE_ENV || "development";

const envFound = dotenv.config();

if (envFound.error) {
throw new Error("⚠️ Couldn't find .env file ⚠️");
}

export default {
port: parseInt(process.env.PORT as string, 10) as number,

//? 데이터베이스
database: process.env.DATABASE_URL as string,

//? JWT
jwtSecret: process.env.JWT_SECRET as string,
jwtAlgo: process.env.JWT_ALGO as string,

//? AWS
s3AccessKey: process.env.S3_ACCESS_KEY as string,
s3SecretKey: process.env.S3_SECRET_KEY as string,
bucketName: process.env.S3_BUCKET as string,
};
14 changes: 14 additions & 0 deletions seminar7/Basic/src/config/s3Config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// src/config/s3Config.ts

import { S3Client } from "@aws-sdk/client-s3";
import config from ".";

const s3: S3Client = new S3Client({
region: "ap-northeast-2",
credentials: {
accessKeyId: config.s3AccessKey,
secretAccessKey: config.s3SecretKey,
},
});

export default s3;
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export default {
DELETE_USER_FAIL: "유저 탈퇴 실패",
NO_USER: "탈퇴했거나 가입하지 않은 유저입니다.",
UPDATE_USER_FAIL: "유저 업데이트 실패",
SEARCH_USER_SUCCESS : "유저 검색 성공",
SEARCH_USER_FAIL: "유저 검색 실패",

// 토큰
CREATE_TOKEN_SUCCESS: "토큰 재발급 성공",
Expand All @@ -31,5 +33,10 @@ export default {
EMPTY_TOKEN: "토큰 값이 없습니다.",

// 서버 내 오류
INTERNAL_SERVER_ERROR: "서버 내 오류"
INTERNAL_SERVER_ERROR: "서버 내 오류",

//이미지
NO_IMAGE: "이미지가 없습니다.",
CREATE_IMAGE_SUCCESS : "이미지 저장 성공",
CREATE_IMAGE_FAIL : "이미지 저장 실패"
};
File renamed without changes.
File renamed without changes.
32 changes: 32 additions & 0 deletions seminar7/Basic/src/controller/imageController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Response, Request } from "express";
import { rm, sc } from "../constants";
import { fail, success } from "../constants/response";
import imageService from "../service/imageService";

//* 이미지 업로드 API
const uploadImage = async (req: Request, res : Response) => {
//console.log(req)
const image: Express.MulterS3.File = req.file as Express.MulterS3.File;
//console.log(image)
const { location } = image;
//image.filename 도 있고,, multer가 제공하는 내장 함수값 많음.

// 파일 위치 무조건 보내주셔야해요 !
if (!location) {
return res.status(sc.BAD_REQUEST).send(fail(sc.BAD_REQUEST, rm.NO_IMAGE));
}

const data = await imageService.uploadImage(location);

if (!data) {
return res.status(sc.BAD_REQUEST).send(fail(sc.BAD_REQUEST, rm.CREATE_IMAGE_FAIL));
}
return res.status(sc.CREATED).send(success(sc.CREATED, rm.CREATE_IMAGE_SUCCESS, data));

}

const imageController = {
uploadImage
};

export default imageController;
2 changes: 2 additions & 0 deletions seminar7/Basic/src/controller/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as userController } from "./userController";
export { default as imageController } from "./imageController";
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,17 @@ const getUserById = async (req: Request, res: Response) => {

//* 유저 전체 조회
const getAllUser = async (req: Request, res: Response) => {
const data = await userService.getAllUser();

const { page, limit } = req.params;

const data = await userService.getAllUser(+page, +limit);

if(!data){
return res.status(sc.NO_CONTENT).send(success(sc.NO_CONTENT, rm.READ_ALL_USERS_SUCCESS, data))
}
return res.status(sc.OK).send(success(sc.OK, rm.READ_ALL_USERS_SUCCESS, data))
};

//* 유저 정보 업데이트
//* 유저 정보 업데이트
const updateUser = async (req: Request, res: Response) => {
const userUpdateDto: UserUpdateDTO = req.body;
Expand All @@ -131,14 +133,27 @@ const deleteUser = async (req: Request, res: Response) => {
return res.status(sc.OK).send(success(sc.OK, rm.DELETE_USER_SUCCESS));
};

//*이름으로 유저 검색
//* GET ~api/user?keyword=세훈
const searchUserByName = async (req: Request, res: Response) => {
const { keyword, option } = req.query; // 세훈

const data = await userService.searchUserByName(keyword as string, option as string);

if (!data) {
return res.status(sc.BAD_REQUEST).send(fail(sc.BAD_REQUEST, rm.SEARCH_USER_FAIL));
}
return res.status(sc.OK).send(success(sc.OK, rm.SEARCH_USER_SUCCESS, data));
}

const userController = {
getUserById,
createUser,
getAllUser,
updateUser,
deleteUser,
signInUser
signInUser,
searchUserByName
};

export default userController; //각 함수들을 userController 로 묶어서 한번에 내보내기
File renamed without changes.
4 changes: 4 additions & 0 deletions seminar7/Basic/src/interfaces/image/ImageCreateResponseDTO.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ImageCreateResponseDTO {
id : number,
image : string
}
File renamed without changes.
2 changes: 2 additions & 0 deletions seminar7/Basic/src/middlewares/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as auth } from "./auth";
export { default as upload } from "./upload";
23 changes: 23 additions & 0 deletions seminar7/Basic/src/middlewares/upload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// src/middlewares/upload.ts
import multer from "multer";
import multerS3 from "multer-s3";
import config from "../config";
import s3 from "../config/s3Config";

//? 미들웨어로 사용할 multer 모듈
const upload = multer({ //multer 모듈에는 많은 설정값 존재 ! 찾아보면서 커스텀 하는거 추천
//? 실질적인 storage 는 multerS3 이용해 aws s3 로 설정
storage: multerS3({
s3: s3,
bucket: config.bucketName, //? s3 bucket name 지정
contentType: multerS3.AUTO_CONTENT_TYPE, //? 중요 ! mimetype 은 자동으로 설정 (jpg나 png 타입을 자동으로 타입 맞춰준다는 의미)
acl: "public-read", // Access control for the file

//? key는 파일 이름을 지정. 버킷 내 같은 이름의 파일은 같은 파일로 인식하기 때문에 Unique하도록!
key: function (req: Express.Request, file: Express.MulterS3.File, cb) {
cb(null, `${Date.now()}_${file.originalname}`); //멀터는 이미지 객체 url 던져 준다 !
},
}),
});

export default upload;
File renamed without changes.
11 changes: 11 additions & 0 deletions seminar7/Basic/src/router/imageRouter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Router } from "express";
import { imageController } from "../controller";
import upload from "../middlewares/upload";

const router : Router = Router();


//* 이미지 업로드
router.post("/", upload.single('file'), imageController.uploadImage); //file 이라는 필드에다가 이미지 전달

export default router;
Loading

0 comments on commit 34a4354

Please sign in to comment.