Skip to content

Commit a913893

Browse files
authored
Merge pull request #16 from boostcampwm-2022/feat/#15-K
Feat/#15-K: μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 생성, μ°Έμ—¬ API 및 μ„œλ²„ utils μ•½κ°„
2 parents 1059d41 + f1296c9 commit a913893

23 files changed

+308
-36
lines changed

β€Žpackage-lock.jsonβ€Ž

Lines changed: 84 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,38 @@
11
import express, { Request, Response, NextFunction } from "express";
2+
import asyncWrapper from "@utils/async-wrapper";
23
import * as authService from "./service";
4+
import { OK } from "@constants/http-status";
35

46
const router = express.Router();
57

68
router.post(
79
"/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-
}
10+
asyncWrapper(async (req: Request, res: Response, next: NextFunction) => {
11+
const { code } = req.body;
12+
13+
const { loginToken, refreshToken } = await authService.login(code);
14+
15+
const cookieOptions = {
16+
httpOnly: true,
17+
sameSite: "lax",
18+
maxAge: 1000 * 60 * 60 * 24,
19+
signed: true,
20+
};
21+
res.cookie("accessToken", loginToken, cookieOptions);
22+
res.cookie("refreshToken", refreshToken, cookieOptions);
23+
24+
res.status(OK).send();
25+
})
2826
);
2927

30-
router.delete("/logout", (req: Request, res: Response) => {
31-
authService.logout(req.signedCookies.accessToken);
28+
router.delete(
29+
"/logout",
30+
asyncWrapper(async (req: Request, res: Response) => {
31+
await authService.logout(req.signedCookies.accessToken);
3232

33-
res.clearCookie("accessToken");
34-
res.status(200).send();
35-
});
33+
res.clearCookie("accessToken");
34+
res.status(OK).send();
35+
})
36+
);
3637

3738
export default router;

β€Žserver/apis/auth/service.tsβ€Ž

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import axios from "axios";
22
import env from "@config";
33
import userModel from "@apis/user/model";
44
import * as jwt from "@utils/jwt";
5+
import AuthorizationError from "@errors/authorization-error";
56

67
interface TokenResponse {
78
access_token: string;
@@ -31,7 +32,7 @@ const getAccessToken = async (code: string) => {
3132
);
3233

3334
if (accessTokenResponse.error) {
34-
throw new Error("access token 생성 μš”μ²­ μ‹€νŒ¨");
35+
throw new AuthorizationError("access token 생성 μš”μ²­ μ‹€νŒ¨");
3536
}
3637

3738
return accessTokenResponse;
@@ -45,7 +46,7 @@ const getGithubUser = async (accessToken: string, tokenType: string) => {
4546
});
4647

4748
if (user.error) {
48-
throw new Error("OAuth μœ μ € 정보 μš”μ²­ μ‹€νŒ¨");
49+
throw new AuthorizationError("OAuth μœ μ € 정보 μš”μ²­ μ‹€νŒ¨");
4950
}
5051

5152
return user;
@@ -64,7 +65,7 @@ export const login = async (code: string) => {
6465
const isSignedUp = userModel.exists({ id });
6566

6667
if (!isSignedUp) {
67-
userModel.create({
68+
await userModel.create({
6869
id,
6970
name,
7071
avatarUrl,
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import express, { Request, Response, NextFunction } from "express";
2+
import asyncWrapper from "@utils/async-wrapper";
3+
import jwtAuthenticator from "@middlewares/jwt-authenticator";
4+
import * as workspaceService from "./service";
5+
import { OK } from "@constants/http-status";
6+
7+
const router = express.Router();
8+
9+
router.post(
10+
"/",
11+
asyncWrapper(async (req: Request, res: Response, next: NextFunction) => {
12+
const { name } = req.body;
13+
14+
const workspace = await workspaceService.create(name);
15+
16+
res.status(OK).send({ ...workspace });
17+
})
18+
);
19+
20+
router.post(
21+
"/join",
22+
jwtAuthenticator,
23+
asyncWrapper(async (req: Request, res: Response, next: NextFunction) => {
24+
const { code } = req.body;
25+
26+
const joinedWorkspace = await workspaceService.join(req.user.id, code);
27+
28+
res.status(OK).send(joinedWorkspace);
29+
})
30+
);
31+
32+
export default router;

β€Žserver/apis/workspace/index.tsβ€Ž

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

β€Žserver/apis/workspace/model.tsβ€Ž

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
import { Schema } from "mongoose";
22
import mongoose from "@db";
3+
import autoIncrement from "mongoose-auto-increment";
34

45
interface Workspace {
56
id: number;
67
name: string;
8+
code: string;
79
users: number[];
810
moms: number[];
911
}
1012

1113
const workspaceSchema = new Schema<Workspace>({
1214
id: { type: Number, required: true },
1315
name: { type: String, required: true },
14-
users: Array<Number>,
15-
moms: Array<Number>,
16+
code: { type: String, required: true },
17+
users: { type: [Number], default: [] },
18+
moms: { type: [Number], default: [] },
19+
});
20+
workspaceSchema.plugin(autoIncrement.plugin, {
21+
model: "workspace",
22+
field: "id",
23+
startAt: 1,
24+
increment: 1,
1625
});
1726

1827
const workspaceModel = mongoose.model("Workspace", workspaceSchema);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { v4 as uuidv4 } from "uuid";
2+
import workspaceModel from "./model";
3+
import userModel from "@apis/user/model";
4+
import AuthorizationError from "@errors/authorization-error";
5+
import InvalidJoinError from "@errors/invalid-join-error";
6+
7+
export const create = async (name: string) => {
8+
const code = uuidv4();
9+
10+
const workspace = await workspaceModel.create({ name, code });
11+
12+
return { name: workspace.name, code: workspace.code };
13+
};
14+
15+
export const join = async (userId: number, code: string) => {
16+
if (!userId) throw new AuthorizationError("μœ μ € 인증 μ‹€νŒ¨");
17+
18+
if (!code) throw new InvalidJoinError("μ°Έμ—¬μ½”λ“œλ₯Ό μž…λ ₯ν•˜μ„Έμš” ^^");
19+
20+
const workspace = await workspaceModel.findOne({ code });
21+
22+
if (!workspace) throw new InvalidJoinError("잘λͺ»λœ μ°Έμ—¬μ½”λ“œμ—μš” ^^");
23+
24+
const { id, name } = workspace;
25+
26+
await workspaceModel.updateOne({ id }, { $push: { users: userId } });
27+
await userModel.updateOne({ id: userId }, { $push: { workspaces: id } });
28+
29+
return { id, name, code };
30+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const OK = 200;
2+
3+
export const BAD_REQUEST = 400;
4+
export const UNAUTHORIZED = 401;
5+
6+
export const INTERNAL_SERVER_ERROR = 500;

β€Žserver/constants/index.tsβ€Ž

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

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import mongoose from "mongoose";
2+
import autoIncrement from "mongoose-auto-increment";
23
import env from "../config";
34

45
const options = {
@@ -8,4 +9,6 @@ const options = {
89
const DATABASE_URL = `mongodb://${env.DATABASE_USER}:${env.DATABASE_PASSWORD}@${env.DATABASE_HOST}:${env.DATABASE_PORT}/${env.DATABASE_NAME}`;
910
mongoose.connect(DATABASE_URL, options);
1011

12+
autoIncrement.initialize(mongoose.connection);
13+
1114
export default mongoose;

0 commit comments

Comments
Β (0)