Skip to content

Commit dec8e0f

Browse files
authored
Merge pull request #46 from codeit-moving/dev
Dev -> main 20241219 17:58
2 parents 840cfb1 + 732ec68 commit dec8e0f

22 files changed

+692
-68
lines changed

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"@types/express-session": "^1.18.1",
1010
"@types/is-uuid": "^1.0.2",
1111
"@types/multer": "^1.4.12",
12+
"@types/node-cron": "^3.0.11",
1213
"@types/passport": "^1.0.17",
1314
"@types/passport-jwt": "^4.0.1",
1415
"@types/passport-naver": "^1.0.4",
@@ -31,7 +32,9 @@
3132
"node-cron": "^3.0.3",
3233
"passport": "^0.7.0",
3334
"passport-custom": "^1.1.1",
35+
"passport-google-oauth20": "^2.0.0",
3436
"passport-jwt": "^4.0.1",
37+
"passport-kakao": "^1.0.1",
3538
"passport-local": "^1.0.0",
3639
"passport-naver": "^1.0.6",
3740
"prisma": "^5.4.2",
@@ -46,6 +49,8 @@
4649
"@types/dompurify": "^3.2.0",
4750
"@types/jest": "^29.5.14",
4851
"@types/node-cron": "^3.0.11",
52+
"@types/passport-google-oauth20": "^2.0.16",
53+
"@types/passport-kakao": "^1.0.3",
4954
"babel-jest": "^29.7.0",
5055
"jest": "^29.7.0",
5156
"nodemon": "^3.1.4",

prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ model MovingRequest {
9898
id Int @id @unique @default(autoincrement()) //자동증가
9999
service Int //서비스 테이블의 코드값 예 ) 1
100100
movingDate DateTime //이사하는 날
101+
region Int @default(0) //지역 테이블의 코드값 예 ) 8202
101102
pickupAddress String //출발지 pickupAddress
102103
dropOffAddress String //도착지 dropoffAddress
103104
requestCount Int @default(0) //견적서 받은 수 예 0~5

src/app.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import userRouter from "./controllers/userController";
1818
import notificationRouter from "./controllers/notificationController";
1919

2020
import confirmedQuoteRouter from "./controllers/confirmedQuoteController";
21-
import { initNotification } from "./schedules/notifications";
21+
import { scheduleNotification } from "./schedules/notifications";
22+
import { imageCleanup } from "./schedules/images";
2223
const app = express();
2324

2425
//CORS 설정
@@ -60,7 +61,8 @@ app.use(passport.initialize());
6061
app.use(passport.session());
6162

6263
//알림 스케줄 등록
63-
initNotification();
64+
imageCleanup();
65+
scheduleNotification();
6466

6567
//라우터 모음 -> 컨트롤러
6668
app.use("/services", serviceRouter);

src/config/cookie.config.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,23 @@ const accessTokenOption: CookieOptions = {
55
secure: true,
66
sameSite: "none",
77
maxAge: 1000 * 60 * 60, // 1시간
8-
// path: "/",
8+
path: "/",
99
};
1010

1111
const refreshTokenOption: CookieOptions = {
1212
httpOnly: true,
1313
secure: true,
1414
sameSite: "none",
1515
maxAge: 1000 * 60 * 60 * 24 * 7, // 7일
16-
// path: "/auth/refresh",
16+
path: "/auth/refresh",
1717
};
1818

1919
const clearCookieOption: CookieOptions = {
2020
httpOnly: true,
21-
secure: false,
22-
sameSite: "lax",
21+
secure: true,
22+
sameSite: "none",
2323
maxAge: 0,
24+
path: "/",
2425
};
2526

2627
const sessionOption: CookieOptions = {

src/controllers/authController.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,19 @@ router.post(
149149
})
150150
);
151151

152+
router.post(
153+
"/password",
154+
passport.authenticate("jwt", { session: false }),
155+
asyncHandle(async (req, res, next) => {
156+
try {
157+
const userId = (req.user as Payload).id;
158+
const { password } = req.body;
159+
await authService.validatePassword(userId, password);
160+
res.status(204).send();
161+
} catch (error) {
162+
next(error);
163+
}
164+
})
165+
);
166+
152167
export default router;

src/controllers/customerController.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ router.patch(
4343
asyncHandle(async (req, res, next) => {
4444
try {
4545
const userId = (req.user as Payload).id;
46+
const customerId = (req.user as { customerId: number }).customerId;
4647
const profile = {
4748
...req.body,
4849
imageUrl: req.file,
@@ -53,7 +54,7 @@ router.patch(
5354
? JSON.parse(req.body.services).map(Number)
5455
: [],
5556
};
56-
await customerService.updateCustomerProfile(userId, profile);
57+
await customerService.updateCustomerProfile(userId, customerId, profile);
5758
res.status(204).send();
5859
} catch (error) {
5960
next(error);

src/controllers/moverController.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import express from "express";
44
import checkBoolean from "../utils/checkBoolean";
55
import passport from "passport";
66
import { optionalJwtAuth } from "../middlewares/authMiddleware";
7+
import upload from "../utils/multer";
8+
import { Payload } from "../utils/token.utils";
79

810
interface queryString {
911
nextCursorId: string;
@@ -142,4 +144,62 @@ router.get(
142144
})
143145
);
144146

147+
router.patch(
148+
"/",
149+
passport.authenticate("jwt", { session: false }),
150+
upload.single("imageUrl"),
151+
asyncHandle(async (req, res, next) => {
152+
try {
153+
const userId = (req.user as Payload).id;
154+
const moverId = (req.user as { moverId: number }).moverId;
155+
const profile = {
156+
...req.body,
157+
imageUrl: req.file,
158+
career: parseInt(req.body.career),
159+
regions: req.body.regions
160+
? JSON.parse(req.body.regions).map(Number)
161+
: [],
162+
services: req.body.services
163+
? JSON.parse(req.body.services).map(Number)
164+
: [],
165+
};
166+
await moverService.updateMoverProfile(userId, moverId, profile);
167+
res.status(204).send();
168+
} catch (error) {
169+
next(error);
170+
}
171+
})
172+
);
173+
174+
router.post(
175+
"/",
176+
passport.authenticate("jwt", { session: false }),
177+
upload.single("imageUrl"),
178+
asyncHandle(async (req, res, next) => {
179+
try {
180+
const userId = (req.user as Payload).id;
181+
const profile = {
182+
userId: userId,
183+
...req.body,
184+
career: parseInt(req.body.career),
185+
imageUrl: req.file!,
186+
regions: req.body.regions
187+
? Array.isArray(req.body.regions)
188+
? req.body.regions.map(Number)
189+
: JSON.parse(req.body.regions).map(Number)
190+
: [],
191+
services: req.body.services
192+
? Array.isArray(req.body.services)
193+
? req.body.services.map(Number)
194+
: JSON.parse(req.body.services).map(Number)
195+
: [],
196+
};
197+
await moverService.createMoverProfile(profile);
198+
res.status(204).send();
199+
} catch (error) {
200+
next(error);
201+
}
202+
})
203+
);
204+
145205
export default router;

src/controllers/movingRequestController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const router = express.Router();
99

1010
//이사요청 목록 조회
1111
router.get(
12-
"/my-mover",
12+
"/by-mover",
1313
passport.authenticate("jwt", { session: false }),
1414
asyncHandle(async (req, res, next) => {
1515
try {

src/controllers/oauthController.ts

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,105 @@ import { Router } from "express";
22
import passport from "passport";
33
import cookieConfig from "../config/cookie.config";
44
import createToken from "../utils/token.utils";
5+
import {
6+
KAKAO_CALLBACK_URL,
7+
KAKAO_CLIENT_ID,
8+
NAVER_CLIENT_ID,
9+
NAVER_REDIRECT_URI,
10+
} from "../env";
511

612
const router = Router();
713

14+
// router.get(
15+
// "/naver",
16+
// passport.authenticate("naver", {
17+
// scope: ["email"],
18+
// prompt: "consent",
19+
// })
20+
// );
21+
22+
router.get("/naver", (req, res) => {
23+
const baseURL = "https://nid.naver.com/oauth2.0/authorize";
24+
const query = new URLSearchParams({
25+
scope: "email",
26+
response_type: "code",
27+
client_id: NAVER_CLIENT_ID!,
28+
redirect_uri: NAVER_REDIRECT_URI!,
29+
auth_type: "reprompt",
30+
});
31+
32+
res.redirect(`${baseURL}?${query.toString()}`);
33+
});
34+
35+
router.get(
36+
"/naver/callback",
37+
passport.authenticate("naver", { failureRedirect: "/login" }),
38+
(req, res) => {
39+
if (!req.user) {
40+
return res.redirect("/login");
41+
}
42+
const user = req.user as any;
43+
44+
const accessToken = createToken(user, "access");
45+
const refreshToken = createToken(user, "refresh");
46+
47+
res.cookie("accessToken", accessToken, cookieConfig.accessTokenOption);
48+
res.cookie("refreshToken", refreshToken, cookieConfig.refreshTokenOption);
49+
50+
res.redirect(process.env.FRONTEND_URL || "http://localhost:3000");
51+
}
52+
);
53+
54+
// router.get(
55+
// "/kakao",
56+
// passport.authenticate("kakao", {
57+
// scope: ["account_email"],
58+
// })
59+
// );
60+
61+
router.get("/kakao", (req, res) => {
62+
const baseURL = "https://kauth.kakao.com/oauth/authorize";
63+
64+
const query = new URLSearchParams({
65+
client_id: KAKAO_CLIENT_ID!,
66+
redirect_uri: KAKAO_CALLBACK_URL!,
67+
response_type: "code",
68+
scope: "account_email",
69+
prompt: "login",
70+
});
71+
72+
res.redirect(`${baseURL}?${query.toString()}`);
73+
});
74+
875
router.get(
9-
"/naver",
10-
passport.authenticate("naver", {
11-
scope: ["email"],
12-
prompt: "consent",
76+
"/kakao/callback",
77+
passport.authenticate("kakao", { failureRedirect: "/login" }),
78+
(req, res) => {
79+
if (!req.user) {
80+
return res.redirect("/login");
81+
}
82+
const user = req.user as any;
83+
84+
const accessToken = createToken(user, "access");
85+
const refreshToken = createToken(user, "refresh");
86+
87+
res.cookie("accessToken", accessToken, cookieConfig.accessTokenOption);
88+
res.cookie("refreshToken", refreshToken, cookieConfig.refreshTokenOption);
89+
90+
res.redirect(process.env.FRONTEND_URL || "http://localhost:3000");
91+
}
92+
);
93+
94+
router.get(
95+
"/google",
96+
passport.authenticate("google", {
97+
scope: ["profile", "email"],
1398
})
1499
);
15100

16101
router.get(
17-
"/naver/callback",
18-
passport.authenticate("naver", { failureRedirect: "/login" }),
102+
"/google/callback",
103+
passport.authenticate("google", { failureRedirect: "/login" }),
19104
(req, res) => {
20105
if (!req.user) {
21106
return res.redirect("/login");
@@ -32,4 +117,10 @@ router.get(
32117
}
33118
);
34119

120+
router.get("/kakao/signout", (req, res) => {
121+
res.clearCookie("accessToken");
122+
res.clearCookie("refreshToken");
123+
res.redirect(process.env.FRONTEND_URL || "http://localhost:3000");
124+
});
125+
35126
export default router;

src/env.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ export const AWS_S3_BUCKET_NAME = process.env.AWS_S3_BUCKET_NAME;
1515
export const AWS_S3_REGION = process.env.AWS_S3_REGION;
1616
export const AWS_S3_ACCESS_KEY = process.env.AWS_S3_ACCESS_KEY;
1717
export const AWS_S3_SECRET_KEY = process.env.AWS_S3_SECRET_KEY;
18+
export const KAKAO_CLIENT_ID = process.env.KAKAO_CLIENT_ID;
19+
export const KAKAO_CLIENT_SECRET = process.env.KAKAO_CLIENT_SECRET;
20+
export const KAKAO_CALLBACK_URL = process.env.KAKAO_CALLBACK_URL;
21+
export const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID;
22+
export const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET;
23+
export const GOOGLE_CALLBACK_URL = process.env.GOOGLE_CALLBACK_URL;

0 commit comments

Comments
 (0)