Skip to content

Commit 387b1cc

Browse files
authored
Merge pull request #14 from boostcampwm-2022/feat/#9-K
Feat/#9-K: ๋กœ๊ทธ์ธ ๋ฐ ๋กœ๊ทธ์•„์›ƒ API
2 parents d455ec7 + 89816a6 commit 387b1cc

File tree

16 files changed

+792
-78
lines changed

16 files changed

+792
-78
lines changed

โ€Žpackage-lock.jsonโ€Ž

Lines changed: 513 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import express, { Request, Response, NextFunction } from "express";
2+
import * as authService from "./service";
3+
4+
const router = express.Router();
5+
6+
router.post(
7+
"/login",
8+
async (req: Request, res: Response, next: NextFunction) => {
9+
try {
10+
const { code } = req.body;
11+
12+
const { loginToken, refreshToken } = await authService.login(code);
13+
14+
const cookieOptions = {
15+
httpOnly: true,
16+
sameSite: "lax",
17+
maxAge: 1000 * 60 * 60 * 24,
18+
signed: true,
19+
};
20+
res.cookie("accessToken", loginToken, cookieOptions);
21+
res.cookie("refreshToken", refreshToken, cookieOptions);
22+
23+
res.status(200).send();
24+
} catch (e) {
25+
next(e);
26+
}
27+
}
28+
);
29+
30+
router.delete("/logout", (req: Request, res: Response) => {
31+
authService.logout(req.signedCookies.accessToken);
32+
33+
res.clearCookie("accessToken");
34+
res.status(200).send();
35+
});
36+
37+
export default router;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import axios from "axios";
2+
import env from "@config";
3+
import userModel from "@apis/user/model";
4+
import * as jwt from "@utils/jwt";
5+
6+
interface TokenResponse {
7+
access_token: string;
8+
token_type: string;
9+
}
10+
11+
const ACCESS_TOKEN_REQUEST_URL = "https://github.com/login/oauth/access_token";
12+
const USER_REQUEST_URL = "https://api.github.com/user";
13+
14+
const getAccessToken = async (code: string) => {
15+
const body = {
16+
client_id: env.GITHUB_CLIENT_ID,
17+
client_secret: env.GITHUB_CLIENT_SECRET,
18+
code,
19+
};
20+
const headers = {
21+
"Content-Type": "application/json",
22+
Accept: "application/json",
23+
};
24+
25+
const { data: accessTokenResponse } = await axios.post(
26+
ACCESS_TOKEN_REQUEST_URL,
27+
body,
28+
{
29+
headers,
30+
}
31+
);
32+
33+
if (accessTokenResponse.error) {
34+
throw new Error("access token ์ƒ์„ฑ ์š”์ฒญ ์‹คํŒจ");
35+
}
36+
37+
return accessTokenResponse;
38+
};
39+
40+
const getGithubUser = async (accessToken: string, tokenType: string) => {
41+
const { data: user } = await axios.get(USER_REQUEST_URL, {
42+
headers: {
43+
Authorization: `${tokenType} ${accessToken}`,
44+
},
45+
});
46+
47+
if (user.error) {
48+
throw new Error("OAuth ์œ ์ € ์ •๋ณด ์š”์ฒญ ์‹คํŒจ");
49+
}
50+
51+
return user;
52+
};
53+
54+
export const login = async (code: string) => {
55+
const { access_token: accessToken, token_type: tokenType }: TokenResponse =
56+
await getAccessToken(code);
57+
58+
const {
59+
id,
60+
login: name,
61+
avatar_url: avatarUrl,
62+
} = await getGithubUser(accessToken, tokenType);
63+
64+
const isSignedUp = userModel.exists({ id });
65+
66+
if (!isSignedUp) {
67+
userModel.create({
68+
id,
69+
name,
70+
avatarUrl,
71+
});
72+
}
73+
74+
const payload = { id, name, avatarUrl };
75+
76+
const loginToken = jwt.generateAccessToken(payload);
77+
const refreshToken = jwt.generateRefreshToken(payload);
78+
79+
return { loginToken, refreshToken };
80+
};
81+
82+
export const logout = async (accessToken: string) => {
83+
try {
84+
const { id } = jwt.verifyToken(accessToken);
85+
86+
userModel.updateOne({ id }, { refreshToken: null });
87+
return;
88+
} catch (err) {
89+
/*
90+
https://github.com/auth0/node-jsonwebtoken
91+
92+
err = {
93+
name: 'TokenExpiredError',
94+
message: 'jwt expired',
95+
expiredAt: 1408621000
96+
}
97+
98+
throw err;
99+
*/
100+
}
101+
};

โ€Žserver/apis/mom/model.tsโ€Ž

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Schema } from "mongoose";
2+
import mongoose from "@db";
3+
4+
interface Block {
5+
type: String;
6+
contents?: String;
7+
}
8+
9+
interface Mom {
10+
id: number;
11+
name: string;
12+
blocks: Block[];
13+
}
14+
15+
const momSchema = new Schema<Mom>({
16+
id: Number,
17+
name: String,
18+
blocks: Array<Block>,
19+
});
20+
21+
const momModel = mongoose.model("Mom", momSchema);
22+
23+
export default momModel;

โ€Žserver/apis/user/index.tsโ€Ž

Lines changed: 0 additions & 1 deletion
This file was deleted.

โ€Žserver/apis/user/model.tsโ€Ž

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Schema } from "mongoose";
2+
import mongoose from "@db";
3+
4+
interface User {
5+
id: number;
6+
name: string;
7+
avatarUrl: string;
8+
createdAt: Date;
9+
workspaces: number[];
10+
}
11+
12+
const userSchema = new Schema<User>({
13+
id: { type: Number, required: true },
14+
name: { type: String, required: true },
15+
avatarUrl: { type: String, required: true },
16+
createdAt: { type: Date, default: new Date() },
17+
workspaces: { type: [Number], default: [] },
18+
});
19+
20+
const userModel = mongoose.model("User", userSchema);
21+
22+
export default userModel;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Schema } from "mongoose";
2+
import mongoose from "@db";
3+
4+
interface Workspace {
5+
id: number;
6+
name: string;
7+
users: number[];
8+
moms: number[];
9+
}
10+
11+
const workspaceSchema = new Schema<Workspace>({
12+
id: { type: Number, required: true },
13+
name: { type: String, required: true },
14+
users: Array<Number>,
15+
moms: Array<Number>,
16+
});
17+
18+
const workspaceModel = mongoose.model("Workspace", workspaceSchema);
19+
20+
export default workspaceModel;

โ€Žserver/config/index.tsโ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ export default {
88
DATABASE_USER: process.env.DATABASE_USER,
99
DATABASE_PASSWORD: process.env.DATABASE_PASSWORD,
1010
DATABASE_NAME: process.env.DATABASE_NAME,
11+
COOKIE_SECRET_KEY: process.env.COOKIE_SECRET_KEY,
12+
JWT_SECRET_KEY: process.env.JWT_SECRET_KEY,
13+
GITHUB_CLIENT_ID: process.env.GITHUB_CLIENT_ID,
14+
GITHUB_CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET,
1115
};

โ€Žserver/db/connection.tsโ€Ž

Lines changed: 0 additions & 63 deletions
This file was deleted.

โ€Žserver/db/index.tsโ€Ž

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import mongoose from "mongoose";
2+
import env from "../config";
3+
4+
const options = {
5+
maxPoolSize: 10,
6+
};
7+
8+
const DATABASE_URL = `mongodb://${env.DATABASE_USER}:${env.DATABASE_PASSWORD}@${env.DATABASE_HOST}:${env.DATABASE_PORT}/${env.DATABASE_NAME}`;
9+
mongoose.connect(DATABASE_URL, options);
10+
11+
export default mongoose;

0 commit comments

Comments
ย (0)