Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:TeamSparker/Spark-Server into fe…
Browse files Browse the repository at this point in the history
…ature/#13
  • Loading branch information
xxeol2 committed Jan 11, 2022
2 parents 7a7fabe + f4d7b19 commit a76570d
Show file tree
Hide file tree
Showing 10 changed files with 3,473 additions and 17 deletions.
28 changes: 14 additions & 14 deletions functions/api/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// 각종 모듈들
const functions = require("firebase-functions");
const express = require("express");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const dotenv = require("dotenv");
const hpp = require("hpp");
const helmet = require("helmet");
const functions = require('firebase-functions');
const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
const hpp = require('hpp');
const helmet = require('helmet');

// 보안 상 깃허브에 올리면 안 되는 정보를 .env라는 파일로 관리하기 위해 사용하는 모듈
dotenv.config();
Expand All @@ -19,7 +19,7 @@ app.use(cors());

// 보안을 위한 미들웨어들
// process.env.NODE_ENV는 배포된 서버에서는 'production'으로, 로컬에서 돌아가는 서버에서는 'development'로 고정됨.
if (process.env.NODE_ENV === "production") {
if (process.env.NODE_ENV === 'production') {
app.use(hpp());
app.use(helmet());
}
Expand All @@ -30,29 +30,29 @@ app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());

// 라우팅: routes 폴더로 관리
app.use("/", require("./routes"));
app.use('/', require('./routes'));

// route 폴더에 우리가 지정할 경로가 아닌 다른 경로로 요청이 올 경우,
// 잘못된 경로로 요청이 들어왔다는 메시지를 클라이언트에 보냄
app.use("*", (req, res) => {
app.use('*', (req, res) => {
res.status(404).json({
status: 404,
success: false,
message: "잘못된 경로입니다.",
message: '요청 경로가 올바르지 않습니다',
});
});

// express를 firebase functions로 감싸주는 코드
module.exports = functions
.runWith({
timeoutSeconds: 300, // 요청을 처리하는 과정이 300초를 초과하면 타임아웃 시키기
memory: "512MB", // 서버에 할당되는 메모리
memory: '512MB', // 서버에 할당되는 메모리
})
.region("asia-northeast3") // 서버가 돌아갈 region. asia-northeast3는 서울
.region('asia-northeast3') // 서버가 돌아갈 region. asia-northeast3는 서울
.https.onRequest(async (req, res) => {
// 들어오는 요청에 대한 로그를 콘솔에 찍기. 디버깅 때 유용하게 쓰일 예정.
// 콘솔에 찍고 싶은 내용을 원하는 대로 추가하면 됨. (req.headers, req.query 등)
console.log("\n\n", "[api]", `[${req.method.toUpperCase()}]`, req.originalUrl, req.body);
console.log('\n\n', '[api]', `[${req.method.toUpperCase()}]`, req.originalUrl, req.body);

// 맨 위에 선언된 express app 객체를 리턴.
// 요것이 functions/index.js 안의 api: require("./api")에 들어가는 것.
Expand Down
4 changes: 3 additions & 1 deletion functions/api/routes/room/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const express = require('express');
const router = express.Router();
const { checkUser } = require('../../../middlewares/auth');

// router.post('/signup', require('./userSignupPOST'));
router.get('/code/:code', checkUser, require('./roomCodeGET'));
router.post('', checkUser, require('./roomPOST'));

module.exports = router;
86 changes: 86 additions & 0 deletions functions/api/routes/room/roomCodeGET.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* @코드로_대기_방_정보_확인
* @route GET /room/code/:code
* @error
* 1. 참여 코드가 전달되지 않음
* 2. 참여코드에 일치하는 방이 없는 경우
* 3. 이미 시작된 습관방인 경우
* 4. 이미 참여중인 방인 경우
* 5. 한번 내보내진 사용자인 경우
*/

const functions = require('firebase-functions');
const util = require('../../../lib/util');
const statusCode = require('../../../constants/statusCode');
const responseMessage = require('../../../constants/responseMessage');
const db = require('../../../db/db');
const { userDB, roomDB } = require('../../../db');

module.exports = async (req, res) => {
const { code } = req.params;
const user = req.user;
const userId = user.userId;

// @error 1. 참여 코드가 전달되지 않음
if (!code) {
return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, responseMessage.NULL_VALUE));
}

let client;

try {
client = await db.connect(req);

const room = await roomDB.getRoomByCode(client, code);

// @error 2. 참여 코드에 일치하는 방이 없음
if (!room) {
return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, responseMessage.GET_WAITROOM_DATA_NULL));
}

// @error 3. 참여 코드에 해당하는 방은 이미 습관 시작한 방임
if (room.isStarted) {
return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, responseMessage.GET_WAITROOM_DATA_STARTED));
}

// @error 5. 한번 내보내진 사용자인 경우
const isKicked = await roomDB.checkKickedByRoomIdAndUserId(client, room.roomId, userId);
if (isKicked) {
return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, responseMessage.GET_WAITROOM_DATA_KICKED));
}

const creator = await userDB.getUserById(client, room.creator);
const entries = await roomDB.getEntriesByRoomId(client, room.roomId);
const imageNum = 3;
let profileImgs = [];

for (let i = 0; i < entries.length; i++) {
if (i < imageNum) {
let user = await userDB.getUserById(client, entries[i].userId);
profileImgs.push(user.profileImg);
}

// @error 4. 이미 해당 습관에 참여중인 사용자
if (userId === entries[i].userId) {
return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, responseMessage.GET_WAITROOM_DATA_ALREADY));
}
}

const data = {
roomId: room.roomId,
roomName: room.roomName,
creatorName: creator.nickname,
createrImg: creator.profileImg,
profileImgs,
totalNums: entries.length,
};

res.status(statusCode.OK).send(util.success(statusCode.OK, responseMessage.READ_ONE_POST_SUCCESS, data));
} catch (error) {
functions.logger.error(`[ERROR] [${req.method.toUpperCase()}] ${req.originalUrl}`, `[CONTENT] ${error}`);
console.log(error);
res.status(statusCode.INTERNAL_SERVER_ERROR).send(util.fail(statusCode.INTERNAL_SERVER_ERROR, responseMessage.INTERNAL_SERVER_ERROR));
} finally {
client.release();
}
};
57 changes: 57 additions & 0 deletions functions/api/routes/room/roomPOST.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @습관방_생성
* @route POST /room
* @body roomName:string, fromStart:boolean
* @error
* 1. 습관방 이름 / 습관방 타입이 전달되지 않음
*/

const functions = require('firebase-functions');
const util = require('../../../lib/util');
const statusCode = require('../../../constants/statusCode');
const responseMessage = require('../../../constants/responseMessage');
const db = require('../../../db/db');
const { userDB, roomDB } = require('../../../db');
const { nanoid } = require('nanoid');

module.exports = async (req, res) => {
const { roomName, fromStart } = req.body;
const user = req.user;

console.log(roomName, fromStart);

// error 1. 습관방 이름 또는 타입이 전달되지 않음
if (!roomName || typeof fromStart !== 'boolean') {
return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, responseMessage.NULL_VALUE));
}

let client, code, creatorId;
let isCodeUnique = false;

try {
client = await db.connect(req);
while (!isCodeUnique) {
code = nanoid(7);
isCodeUnique = await roomDB.isCodeUnique(client, code);
}

creatorId = user.userId;

const room = await roomDB.addRoom(client, roomName, code, creatorId, fromStart);
let data = {
roomId: room.roomId,
roomName: room.roomName,
code: room.code,
};
console.log(room.roomId);

res.status(statusCode.OK).send(util.success(statusCode.OK, responseMessage.CREATE_ROOM_SUCCESS, data));
} catch (error) {
functions.logger.error(`[ERROR] [${req.method.toUpperCase()}] ${req.originalUrl}`, `[CONTENT] ${error}`);
console.log(error);

res.status(statusCode.INTERNAL_SERVER_ERROR).send(util.fail(statusCode.INTERNAL_SERVER_ERROR, responseMessage.INTERNAL_SERVER_ERROR));
} finally {
client.release();
}
};
12 changes: 12 additions & 0 deletions functions/constants/responseMessage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module.exports = {
NULL_VALUE: '필요한 값이 없습니다',
OUT_OF_VALUE: '파라미터 값이 잘못되었습니다',
PATH_ERROR: '요청 경로가 올바르지 않습니다',
INTERNAL_SERVER_ERROR: '서버 내부 오류',

// 회원가입
CREATED_USER: '회원 가입 성공',
Expand All @@ -16,4 +18,14 @@ module.exports = {

// 프로필 조회
READ_PROFILE_SUCCESS: '프로필 조회 성공',

// Room
CREATE_ROOM_SUCCESS: '습관 방 생성 성공',
CREATE_ROOM_FAIL: '습관 방 생성 실패',
GET_WAITROOM_DATA_SUCCESS: '대기방 정보 확인 완료',
GET_WAITROOM_DATA_NULL: '참여코드와 일치하는 습관 방이 존재하지 않습니다',
GET_WAITROOM_DATA_STARTED: '이미 습관 형성에 도전중인 방입니다',
GET_WAITROOM_DATA_ALREADY: '이미 사용자가 참가중인 방입니다',
GET_WAITROOM_DATA_FAIL: '대기방 정보 확인 실패',
GET_WAITROOM_DATA_KICKED: '습관 방 생성자에 의해 내보내진 방입니다',
};
1 change: 1 addition & 0 deletions functions/db/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
module.exports = {
userDB: require('./user'),
roomDB: require('./room'),
};
74 changes: 74 additions & 0 deletions functions/db/room.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const _ = require('lodash');
const convertSnakeToCamel = require('../lib/convertSnakeToCamel');

const addRoom = async (client, roomName, code, creator, fromStart) => {
const { rows } = await client.query(
`
INSERT INTO spark.room as r
(room_name, code, creator, from_start)
VALUES
($1, $2, $3, $4)
RETURNING *
`,
[roomName, code, creator, fromStart],
);
return convertSnakeToCamel.keysToCamel(rows[0]);
};

const isCodeUnique = async (client, code) => {
const { rows } = await client.query(
`
SELECT * FROM spark.room as r
WHERE code = $1
AND is_deleted = FALSE
`,
[code],
);
if (rows.length == 0) {
return true;
}
return false;
};

const getRoomByCode = async (client, code) => {
const { rows } = await client.query(
`
SELECT * FROM spark.room
WHERE code = $1
AND is_deleted = FALSE
`,
[code],
);
return convertSnakeToCamel.keysToCamel(rows[0]);
};

const getEntriesByRoomId = async (client, roomId) => {
const { rows } = await client.query(
`
SELECT * FROM spark.entry
WHERE room_id = $1
AND is_out = FALSE
AND is_kicked = FALSE
AND is_deleted = FALSE
ORDER BY created_at
`,
[roomId],
);
return convertSnakeToCamel.keysToCamel(rows);
};

const checkKickedByRoomIdAndUserId = async (client, roomId, userId) => {
const { rows } = await client.query(
`
SELECT * FROM spark.entry
WHERE room_id = $1
AND user_id = $2
AND is_kicked = TRUE
AND is_deleted = FALSE
`,
[roomId, userId],
);
return convertSnakeToCamel.keysToCamel(rows);
};

module.exports = { addRoom, isCodeUnique, getRoomByCode, getEntriesByRoomId, checkKickedByRoomIdAndUserId };
15 changes: 13 additions & 2 deletions functions/db/user.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
const _ = require('lodash');
const convertSnakeToCamel = require('../lib/convertSnakeToCamel');

const getAllUsers = async (client) => {
const { rows } = await client.query(
`
SELECT * FROM spark.user as u
WHERE is_deleted = FALSE
`,
);
return convertSnakeToCamel.keysToCamel(rows);
};

const getUserById = async (client, userId) => {
const { rows } = await client.query(
`
SELECT * FROM spark.user u
SELECT * FROM spark.user as u
WHERE user_id = $1
AND is_deleted = FALSE
`,
Expand Down Expand Up @@ -39,4 +49,5 @@ const addUser = async (client, socialId, nickname, profileImg) => {
return convertSnakeToCamel.keysToCamel(rows[0]);
};

module.exports = { getUserById, getUserBySocialId, addUser };
module.exports = { getAllUsers, getUserById, getUserBySocialId, addUser };

Loading

0 comments on commit a76570d

Please sign in to comment.