Skip to content

Commit dddec12

Browse files
authored
Merge pull request #118 from codeit-moving/release
Release -> Main 20250106 11:38 review post end-point update
2 parents 98a9f17 + 04463f7 commit dddec12

File tree

16 files changed

+198
-198
lines changed

16 files changed

+198
-198
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "1.3.0",
2+
"version": "1.4.0",
33
"dependencies": {
44
"@aws-sdk/s3-request-presigner": "^3.691.0",
55
"@prisma/client": "^5.20.0",

src/controllers/authController.ts

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import createToken, { Payload } from "../utils/token.utils";
66
import upload from "../utils/multer";
77
import passport from "passport";
88
import userService from "../services/userService";
9+
import { uploadFiles } from "../middlewares/uploadFile";
910

1011
const router = Router();
1112

@@ -23,7 +24,7 @@ interface User {
2324
}
2425

2526
interface SignUpCustomer extends User {
26-
imageUrl: Express.Multer.File;
27+
imageUrl: string[];
2728
services: number[];
2829
regions: number[];
2930
}
@@ -33,7 +34,7 @@ interface SignUpMover extends User {
3334
career: number;
3435
introduction: string;
3536
description: string;
36-
imageUrl: Express.Multer.File;
37+
imageUrl: string[];
3738
services: number[];
3839
regions: number[];
3940
}
@@ -66,21 +67,17 @@ router.post("/signout", (_, res) => {
6667

6768
router.post(
6869
"/signup/customer",
69-
upload.single("imageUrl"),
70+
upload.array("imageUrl"),
71+
uploadFiles,
7072
asyncHandle(async (req, res, next) => {
7173
try {
7274
const signUpCustomer: SignUpCustomer = {
7375
...req.body,
74-
imageUrl: req.file!,
75-
services: Array.isArray(req.body.services)
76-
? req.body.services.map(Number)
77-
: JSON.parse(req.body.services).map(Number),
78-
regions: Array.isArray(req.body.regions)
79-
? req.body.regions.map(Number)
80-
: JSON.parse(req.body.regions).map(Number),
76+
imageUrl: req.fileUrls,
77+
services: JSON.parse(req.body.services).map(Number),
78+
regions: JSON.parse(req.body.regions).map(Number),
8179
isOAuth: req.body.isOAuth === "true",
8280
};
83-
8481
await authService.signUpCustomer(signUpCustomer);
8582
res.status(204).send();
8683
} catch (error) {
@@ -91,20 +88,17 @@ router.post(
9188

9289
router.post(
9390
"/signup/mover",
94-
upload.single("imageUrl"),
91+
upload.array("imageUrl"),
92+
uploadFiles,
9593
asyncHandle(async (req, res, next) => {
9694
try {
9795
const SignUpMover: SignUpMover = {
9896
...req.body,
99-
imageUrl: req.file!,
100-
services: Array.isArray(req.body.services)
101-
? req.body.services.map(Number)
102-
: JSON.parse(req.body.services).map(Number),
103-
regions: Array.isArray(req.body.regions)
104-
? req.body.regions.map(Number)
105-
: JSON.parse(req.body.regions).map(Number),
97+
imageUrl: req.fileUrls,
98+
services: JSON.parse(req.body.services).map(Number),
99+
regions: JSON.parse(req.body.regions).map(Number),
106100
isOAuth: req.body.isOAuth === "true",
107-
career: Number(req.body.career),
101+
career: parseInt(req.body.career),
108102
};
109103
await authService.signUpMover(SignUpMover);
110104
res.status(204).send();

src/controllers/customerController.ts

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,23 @@ import { asyncHandle } from "../utils/asyncHandler";
44
import passport from "passport";
55
import { Payload } from "../utils/token.utils";
66
import upload from "../utils/multer";
7+
import { uploadFiles, uploadOptionalFiles } from "../middlewares/uploadFile";
78

89
const router = Router();
910

1011
router.post(
1112
"/",
1213
passport.authenticate("jwt", { session: false }),
13-
upload.single("imageUrl"),
14+
upload.array("imageUrl"),
15+
uploadFiles,
1416
asyncHandle(async (req, res, next) => {
1517
try {
1618
const userId = (req.user as Payload).id;
1719
const profile = {
1820
userId: userId,
19-
imageUrl: req.file!,
20-
regions: req.body.regions
21-
? Array.isArray(req.body.regions)
22-
? req.body.regions.map(Number)
23-
: JSON.parse(req.body.regions).map(Number)
24-
: [],
25-
services: req.body.services
26-
? Array.isArray(req.body.services)
27-
? req.body.services.map(Number)
28-
: JSON.parse(req.body.services).map(Number)
29-
: [],
21+
imageUrl: req.fileUrls!,
22+
regions: JSON.parse(req.body.regions).map(Number),
23+
services: JSON.parse(req.body.services).map(Number),
3024
};
3125
await customerService.createCustomerProfile(profile);
3226
res.status(204).send();
@@ -39,20 +33,16 @@ router.post(
3933
router.patch(
4034
"/",
4135
passport.authenticate("jwt", { session: false }),
42-
upload.single("imageUrl"),
36+
upload.array("imageUrl"),
37+
uploadOptionalFiles,
4338
asyncHandle(async (req, res, next) => {
4439
try {
4540
const userId = (req.user as Payload).id;
4641
const customerId = (req.user as { customerId: number }).customerId;
4742
const profile = {
48-
...req.body,
49-
imageUrl: req.file,
50-
regions: req.body.regions
51-
? JSON.parse(req.body.regions).map(Number)
52-
: [],
53-
services: req.body.services
54-
? JSON.parse(req.body.services).map(Number)
55-
: [],
43+
imageUrl: req.fileUrls,
44+
regions: JSON.parse(req.body.regions).map(Number),
45+
services: JSON.parse(req.body.services).map(Number),
5646
};
5747
await customerService.updateCustomerProfile(userId, customerId, profile);
5848
res.status(204).send();

src/controllers/moverController.ts

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
} from "../middlewares/authMiddleware";
1111
import upload from "../utils/multer";
1212
import { Payload } from "../utils/token.utils";
13+
import { uploadFiles, uploadOptionalFiles } from "../middlewares/uploadFile";
1314

1415
interface queryString {
1516
nextCursorId: string;
@@ -171,21 +172,18 @@ router.delete(
171172
router.patch(
172173
"/",
173174
passport.authenticate("jwt", { session: false }),
174-
upload.single("imageUrl"),
175+
upload.array("imageUrl"),
176+
uploadOptionalFiles,
175177
asyncHandle(async (req, res, next) => {
176178
try {
177179
const userId = (req.user as Payload).id;
178180
const moverId = (req.user as { moverId: number }).moverId;
179181
const profile = {
180182
...req.body,
181-
imageUrl: req.file,
183+
imageUrl: req.fileUrls,
182184
career: parseInt(req.body.career),
183-
regions: req.body.regions
184-
? JSON.parse(req.body.regions).map(Number)
185-
: [],
186-
services: req.body.services
187-
? JSON.parse(req.body.services).map(Number)
188-
: [],
185+
regions: JSON.parse(req.body.regions).map(Number),
186+
services: JSON.parse(req.body.services).map(Number),
189187
};
190188
await moverService.updateMoverProfile(userId, moverId, profile);
191189
res.status(204).send();
@@ -198,25 +196,18 @@ router.patch(
198196
router.post(
199197
"/",
200198
passport.authenticate("jwt", { session: false }),
201-
upload.single("imageUrl"),
199+
upload.array("imageUrl"),
200+
uploadFiles,
202201
asyncHandle(async (req, res, next) => {
203202
try {
204203
const userId = (req.user as Payload).id;
205204
const profile = {
206205
userId: userId,
207206
...req.body,
207+
imageUrl: req.fileUrls,
208208
career: parseInt(req.body.career),
209-
imageUrl: req.file!,
210-
regions: req.body.regions
211-
? Array.isArray(req.body.regions)
212-
? req.body.regions.map(Number)
213-
: JSON.parse(req.body.regions).map(Number)
214-
: [],
215-
services: req.body.services
216-
? Array.isArray(req.body.services)
217-
? req.body.services.map(Number)
218-
: JSON.parse(req.body.services).map(Number)
219-
: [],
209+
regions: JSON.parse(req.body.regions).map(Number),
210+
services: JSON.parse(req.body.services).map(Number),
220211
};
221212
await moverService.createMoverProfile(profile);
222213
res.status(204).send();

src/controllers/quoteController.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,21 +110,16 @@ router.post(
110110
const moverId = user.moverId;
111111
const movingRequestId = parseInt(req.params.movingRequestId);
112112

113-
// 파라미터 검증 후에 서비스를 호출하고 응답을 보내는 부분이 없어요!
113+
// 파라미터 검증
114114
if (!movingRequestId) {
115115
const error: customError = new Error("Bad Request");
116116
error.status = 400;
117-
error.message = "Bad Request";
118-
error.data = {
119-
message: "이사 요청 ID가 필요합니다.",
120-
};
117+
error.message = "이사 요청 ID가 필요합니다.";
121118
throw error;
122119
}
123120

124-
// 서비스 호출 추가
125121
const result = await quoteService.rejectRequest(moverId, movingRequestId);
126122

127-
// 응답 추가
128123
res.status(200).send(result);
129124
})
130125
);

src/controllers/reviewController.ts

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import passport from "passport";
33
import { asyncHandle } from "../utils/asyncHandler";
44
import reviewService from "../services/reviewService";
55
import customError from "../utils/interfaces/customError";
6-
import { ReviewCreateData, ReviewQuery } from "../utils/review/types";
7-
import { uploadFile } from "../utils/s3.utils";
86
import upload from "../utils/multer";
7+
import { uploadOptionalFiles } from "../middlewares/uploadFile"; // 추가
8+
import { throwHttpError } from "../utils/constructors/httpError";
99

1010
interface User {
1111
customerId: number;
@@ -60,43 +60,29 @@ router.get(
6060
router.post(
6161
"/",
6262
passport.authenticate("jwt", { session: false }),
63-
upload.array("images", 10),
63+
upload.array("imageUrl", 3), // 수정: images -> imageUrl로 변경 (DB 필드명과 일치)
64+
uploadOptionalFiles, // 미들웨어 추가
6465
asyncHandle(async (req, res) => {
6566
const user = req.user as User;
6667
const customerId = user.customerId;
68+
const { confirmedQuoteId, rating, content } = req.body;
6769

6870
if (!customerId) {
69-
const error: customError = new Error("Bad Request");
70-
error.status = 400;
71-
error.message = "고객 ID가 필요합니다.";
72-
throw error;
71+
throwHttpError(400, "고객 ID가 필요합니다.");
7372
}
7473

75-
const { confirmedQuoteId, rating, content } = req.body;
76-
7774
if (!confirmedQuoteId || !rating) {
78-
// moverId 체크 제거
79-
const error: customError = new Error("Bad Request");
80-
error.status = 400;
81-
error.message = "필수 항목이 누락되었습니다.";
82-
throw error;
83-
}
84-
85-
// 이미지 파일이 있다면 S3에 업로드
86-
let imageUrl: string[] = []; // 배열로 초기화
87-
if (req.files && Array.isArray(req.files) && req.files.length > 0) {
88-
const uploadedUrl = await uploadFile(req.files[0]); // 첫 번째 이미지만 업로드
89-
imageUrl = uploadedUrl ? [uploadedUrl] : []; // 배열로 감싸서 저장
75+
throwHttpError(400, "필수 항목이 누락되었습니다.");
9076
}
9177

9278
const result = await reviewService.createNewReview(customerId, {
93-
confirmedQuoteId,
94-
rating,
79+
confirmedQuoteId: Number(confirmedQuoteId),
80+
rating: Number(rating),
9581
content,
96-
imageUrl,
82+
imageUrl: req.fileUrls || [], // S3에 업로드된 URL 배열 전달
9783
});
9884

99-
res.status(200).send(result);
85+
res.status(201).send(result); // 수정: 201 Created 상태코드 사용
10086
})
10187
);
10288

src/middlewares/uploadFile.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { throwHttpError } from "../utils/constructors/httpError";
2+
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
3+
import {
4+
AWS_S3_ACCESS_KEY,
5+
AWS_S3_BUCKET_NAME,
6+
AWS_S3_REGION,
7+
AWS_S3_SECRET_KEY,
8+
} from "../env";
9+
import { asyncHandle } from "../utils/asyncHandler";
10+
11+
declare global {
12+
namespace Express {
13+
interface Request {
14+
fileUrls?: string[];
15+
}
16+
}
17+
}
18+
19+
const s3Client = new S3Client({
20+
region: process.env.AWS_S3_REGION,
21+
credentials: {
22+
accessKeyId: AWS_S3_ACCESS_KEY!,
23+
secretAccessKey: AWS_S3_SECRET_KEY!,
24+
},
25+
});
26+
27+
export const uploadFiles = asyncHandle(async (req, res, next) => {
28+
const files = req.files as Express.Multer.File[];
29+
30+
if (files.length === 0) {
31+
throwHttpError(400, "이미지 파일이 없습니다.");
32+
}
33+
34+
try {
35+
const uploadPromises = files.map(async (file) => {
36+
const key = `profiles/${Date.now()}-${file.originalname}`;
37+
await s3Client.send(
38+
new PutObjectCommand({
39+
Bucket: AWS_S3_BUCKET_NAME,
40+
Key: key,
41+
Body: file.buffer,
42+
ContentType: file.mimetype,
43+
})
44+
);
45+
return `https://${AWS_S3_BUCKET_NAME}.s3.${AWS_S3_REGION}.amazonaws.com/${key}`;
46+
});
47+
48+
req.fileUrls = await Promise.all(uploadPromises);
49+
console.log(req.fileUrls);
50+
next();
51+
} catch (e) {
52+
throwHttpError(500, "이미지 업로드 실패");
53+
}
54+
});
55+
56+
export const uploadOptionalFiles = asyncHandle(async (req, res, next) => {
57+
if (!req.files) {
58+
return next();
59+
}
60+
61+
const files = req.files as Express.Multer.File[];
62+
63+
try {
64+
const uploadPromises = files.map(async (file) => {
65+
const key = `profiles/${Date.now()}-${file.originalname}`;
66+
await s3Client.send(
67+
new PutObjectCommand({
68+
Bucket: AWS_S3_BUCKET_NAME,
69+
Key: key,
70+
Body: file.buffer,
71+
ContentType: file.mimetype,
72+
})
73+
);
74+
return `https://${AWS_S3_BUCKET_NAME}.s3.${AWS_S3_REGION}.amazonaws.com/${key}`;
75+
});
76+
77+
req.fileUrls = await Promise.all(uploadPromises);
78+
next();
79+
} catch (e) {
80+
throwHttpError(500, "이미지 업로드 실패");
81+
}
82+
});
83+
84+
export default { uploadFiles, uploadOptionalFiles };

0 commit comments

Comments
 (0)