Commit 1b8d7cda authored by Yoon, Daeki's avatar Yoon, Daeki 😅
Browse files

Merge branch 'young' into master

parents cada8594 5f25610a
import axios from "axios"
//자동으로 localstorage에 login이 생성됨
export function handleLogin(data) {
sessionStorage.setItem('userId', data.user._id)
sessionStorage.setItem('name', data.user.username)
}
export async function handleLogout() {
alert('로그아웃 되었습니다')
sessionStorage.clear();
await axios.get('/auth/logout')
}
export function isAuthenticated() {
const userId = sessionStorage.getItem('userId')
if (userId) {
return userId
} else {
return false
}
}
\ No newline at end of file
function catchErrors(error, displayError){
let errorMsg
if (error.response){
errorMsg = error.response.data
console.log(errorMsg)
} else if (error.request) {
errorMsg = error.request
console.log(errorMsg)
} else {
errorMsg = error.message
console.log(errorMsg)
}
displayError(errorMsg)
}
export default catchErrors
\ No newline at end of file
{
"name": "messenger",
"version": "1.0.0",
"description": "Messenger 2020 Winter",
"main": "index.js",
"type": "module",
"scripts": {
"dev": "nodemon --ignore client server/server.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://compmath.korea.ac.kr/gitlab/research/messenger.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.21.1",
"bcrypt": "^5.0.0",
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.11.9",
"multer": "^1.4.2",
"nanoid": "^3.1.20",
"nodemon": "^2.0.6",
"react-icons": "^4.1.0",
"socket.io": "^3.0.5",
"styled-components": "^5.2.1",
"validator": "^13.5.2"
}
}
const config = {
env: process.env.NODE_ENV || 'development',
port: process.env.PORT || 3030,
jwtSecret: process.env.JWT_SECRET || 'My_Secret_Key',
mongoDbUri: process.env.MONGODB_URI || 'mongodb://localhost/messenger',
cookieMaxAge: 60 * 60 * 24 * 7 * 1000
//1000이 1초 이므로 7일
}
export default config
\ No newline at end of file
import User from "../models/User.js"
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import config from "../config.js"
//server부분에는 꼭 js붙여주기!!
//sign validation해야됨
const login = async (req, res) => {
const { email, password } = req.body
try {
const user = await User.findOne({ email }).select('+password')
if (!user) {
return res.status(404).send(`${email}을 사용하는 사용자가 없습니다`)
}
const passwordMatch = await bcrypt.compare(password, user.password)
if (passwordMatch) {
//토큰 생성
const token = jwt.sign({ userId: user._id}, config.jwtSecret, {expiresIn: '7d'})
//jwtSecret : 노출되면 안됨. 문자열
//expiresIn: '7d' -> 만기날짜 : 만든 7일후 만기
//쿠키에 저장
//res : client로 넘어가는 객체 cookie('이름', value)
res.cookie('token', token, {
maxAge: config.cookieMaxAge,
//생성일로부터 어느정도까지 살아있을 것인가
httpOnly: true,
//client에서 javascript로 접근할 수 없음
secure: config.env === 'production',
//secure가 true이면 http로 접근하면 cookie가 들어가지 않음.
})
console.log('res.send.user', {user})
res.send({user})
} else {
// 5) 비밀번호가 틀리면 에러 반환
res.status(401).send('비밀번호가 일치하지 않습니다')
}
} catch (error) {
//알수없는 모든 에러발생시 처리
console.log(error)
res.status(500).send('로그인 에러가 발생하였습니다')
}
}
const logout = (req, res) => {
res.clearCookie('token')
res.send('로그아웃 되었습니다')
}
export default { login, logout }
// {} : 객체로 return함
import Room from "../models/Room.js"
import { customAlphabet } from 'nanoid'
import isLength from 'validator/lib/isLength.js'
import Chat from "../models/Chat.js"
import EntryLog from "../models/EntryLog.js"
const nanoid = customAlphabet('1234567890abcdef', 10)
const makeRoom = async (req, res) => {
const { roomName, interest, isOpen, member } = req.body;
const roomId = nanoid()
const room = await Room.findOne({ roomId })
while (room) {
roomId = nanoid()
room = await Room.findOne({ roomId })
}
try {
if (!isLength(roomName, { min: 3, max: 20 })) {
return res.status(422).send('채팅방의 이름은 3-20자여야 합니다.')
} else if (interest == 'Choose...' || interest == '') {
return res.status(422).send('분야를 반드시 선택하여야 합니다.')
}
const newRoom = await new Room({
roomId,
roomName,
interest,
isOpen,
member,
}).save()
res.json(newRoom)
} catch (error) {
console.log(error)
res.status(500).send('방생성 에러')
}
}
const getClosedList = async (req, res) => {
try {
let list = await Room.find({ member: req.query._id })
return res.json(list)
} catch (error) {
res.status(500).send('리스트 불러오기를 실패하였습니다!')
}
}
const getOpenList = async (req, res) => {
try {
let list = await Room.find({ isOpen: true })
return res.json(list)
} catch (error) {
res.status(500).send('리스트 불러오기를 실패하였습니다!')
}
}
const getRoomName = async (req, res) => {
const roomId = req.query.roomCode
try {
let roominfo = await Room.findOne({ roomId: roomId }).select('roomName')
return res.json(roominfo.roomName)
} catch (error) {
res.status(500).send('리스트 불러오기를 실패하였습니다!')
}
}
const changemember = async (req, res) => {
const { userId, roomId } = req.body
let room = await Room.findOne({ roomId: roomId }).select('member')
const isPresent = room.member.indexOf(userId)
try {
if (isPresent < 0) {
const memberId = room.member.push(userId)
await Room.updateOne({ 'roomId': roomId }, { 'member': room.member })
return res.json(true)
}
else {
return res.json(false)
}
} catch (error) {
res.status(500).send('멤버 업데이트 실패')
}
}
const deleteUserId = async (req, res) => {
const { userId, roomId } = req.body
let room = await Room.findOne({ roomId: roomId }).select('member')
const memIndex = room.member.indexOf(userId)
try {
room.member.splice(memIndex, 1)
await Room.updateOne({ 'roomId': roomId }, { 'member': room.member })
return res.json(true)
} catch (error) {
res.status(500).send('멤버 업데이트 실패')
}
}
const roomInf = async (req, res) => {
try {
let roomInf = await Room.find({ roomId: req.query.roomId })
return res.json(roomInf)
} catch (error) {
alert('올바르지 못한 접근입니다.')
}
}
const unreadMessage = async (req, res) => {
const nowTime = new Date().toISOString()
let leaveInfo = req.query
try {
for (const key in Object.keys(leaveInfo)) {
leaveInfo[key] = JSON.parse(leaveInfo[key]) //형식좀 제대로 맞춰주고
}
let countArr = []
for (const key in Object.keys(leaveInfo)) {
const room = await Room.findOne({ roomId: leaveInfo[key].roomCode }) //들어온 방 코드로 그 방의 정보 찾아옴
const entrylog = await EntryLog.findOne({ userId: leaveInfo[key].userId, room: room._id }) //그 방에서 나간시간 가져옴
if (entrylog) {
if (leaveInfo[key].now) { //보는중이면 현재시간과 비교. 즉, 없음
const count = await Chat.find({ room: room._id, createdAt: { $gte: nowTime } }) //채팅 전체에서 그 방의 채팅중 떠난시간 이후의 것들을 가져옴
countArr.push({ roomCode: room.roomId, unreadcount: count.length })
} else {
const count = await Chat.find({ room: room._id, createdAt: { $gte: entrylog.updatedAt } }) //채팅 전체에서 그 방의 채팅중 떠난시간 이후의 것들을 가져옴
countArr.push({ roomCode: room.roomId, unreadcount: count.length })
}
} else {
countArr.push(0)
}
}
res.json(countArr)
} catch (error) {
res.send(error)
}
}
export default { makeRoom, getClosedList, getOpenList, getRoomName, changemember, roomInf, unreadMessage, deleteUserId }
import Room from "../models/Room.js"
import Chat from "../models/Chat.js";
import User from "../models/User.js";
import EntryLog from "../models/EntryLog.js";
const roomEnter = async (req, res) => {
const roomId = req.body.enterCode
try {
const room = await Room.findOne({ roomId })
if (!room) {
return res.status(404).send(`참여코드가 존재하지 않습니다.`)
}
console.log('roomId존재')
const name = await Room.findOne({ roomId: roomId }).select('roomName')
return res.json(name.roomName)
} catch (error) {
//알수없는 모든 에러발생시 처리
console.log(error)
res.status(500).send('방 참여 에러')
}
}
const getChatInfo = async (req, res) => {
const roomId = req.query.roomCode
try {
const room_id = await Room.find({ roomId: roomId }).select('_id') //roomId로 해당 방의 _id를 찾아옴
let infolist = await Chat.find({ room: room_id }).select('message username createdAt profileimg')
res.json(infolist)
} catch (error) {
res.status(500).send('이전 채팅 정보 불러오기를 실패하였습니다!')
}
}
//그사람의 그방에서의 기록이 있는지 확인
const checklog = async (req, res) => {
console.log('@@@@@서버에서 체크 로그')
const { userId, roomCode } = req.query
const roomId = await Room.findOne({ roomId: roomCode })
try {
const entrylog = await EntryLog.findOne({ userId: userId, room: roomId })
res.json(Boolean(entrylog))
} catch (error) {
res.json(false)
}
}
//출입기록 업로드
const uploadlog = async (req, res) => {
console.log('@@@@@서버에서 업로드 로그')
const { userId, leaveTime, roomCode } = req.body
const user = await User.findOne({ _id: userId }) // 받아온 _id로 그 유저의 정보 가져옴
const room = await Room.findOne({ roomId: roomCode }) // 받아온 roomCode로 그 방의 정보 가져옴
try {
const entrylog = await new EntryLog({
userId: user._id,
room: room._id,
leaveTime: leaveTime,
}).save()
res.json(entrylog)
} catch (error) {
console.log(error)
res.send(500).send('출입시간이 기록되지 않았습니다.')
}
}
//출입기록 수정
const updatelog = async (req, res) => {
console.log('@@@@@서버에서 업데이트 로그')
const { userId, leaveTime, roomCode } = req.body
console.log('@@@@@', leaveTime, userId, roomCode)
const room = await Room.findOne({ roomId: roomCode })
try {
await EntryLog.updateOne({ userId: userId, room: room._id }, { leaveTime: leaveTime }) //항상 id와 room이 둘다 맞는걸 수정해야함 !
res.send('finished')
} catch (error) {
console.log(error)
res.send(500).send('출입시간 업데이트 실패')
}
}
export default { roomEnter, getChatInfo, checklog, uploadlog, updatelog }
\ No newline at end of file
import User from "../models/User.js"
import isLength from 'validator/lib/isLength.js'
import isEmail from 'validator/lib/isEmail.js'
import bcrypt from "bcryptjs";
import multer from "multer";
const upload = multer({ dest: 'uploads/' })
const profileUpload = upload.fields([
{ name: 'imageUrl', maxCount: 1 },
])
const signup = async (req, res) => {
const { username, nickname, email, password } = req.body
try {
if (!isLength(username, { min: 3, max: 10 })) {
return res.status(422).send('이름은 3-10자 사이입니다')
} else if (!isLength(nickname, { min: 2, max: 10 })) {
return res.status(422).send('별명은 2-10자 사이입니다.')
} else if (!isLength(password, { min: 6 })) {
return res.status(422).send('비밀번호는 6자 이상입니다.')
} else if (!isEmail(email)) {
return res.status(422).send('유효하지 않은 이메일 형식입니다')
}
const user = await User.findOne({ email })
if (user) {
return res.status(422).send(`${email}이 이미 사용중입니다.`)
}
const hash = await bcrypt.hash(password, 10)
const newUser = await new User({
username,
nickname,
email,
password: hash,
}).save()
res.json(newUser)
} catch (error) {
//알수없는 모든 에러발생시 처리
console.log(error)
res.status(500).send('회원가입 에러발생하였습니다.')
}
}
const update = async (req, res) => {
const username = req.user.username
const newNickname = req.body.newNickname
try {
await User.updateOne({ 'username': username }, { 'nickname': newNickname })
let imageUrl = ''
if (req.files['imageUrl']) {
imageUrl = req.files['imageUrl'][0]
}
const user = req.user
if (req.files['imageUrl']) {
user.profileimg = imageUrl.filename //우리가 사용할 uesr.profileimg에다가 imageUrl의 filename을 저장
}
const updatedUser = await user.save()
res.json(updatedUser)
} catch (error) {
console.log(error)
res.status(500).send('프로필 업데이트 실패')
}
}
const userById = async (req, res, next, id) => { //id로 찾아와서 req.user를 우리가 찾는 user로 저장
try {
const user = await User.findById(id)
if (!user) {
res.status(404).send('사용자를 찾을 수 없습니다.')
}
req.user = user
next()
} catch (error) {
console.log(error)
res.status(500).send('사용자 아이디 검색 실패')
}
}
const getProfile = (req, res) => {
res.json(req.user)
}
const checkUser = async (req, res) => {
try {
const info = await User.findOne({ _id: req.query._id })
return res.json(info)
} catch (error) {
console.log(error)
res.status(500).send('사용자 검색 실패')
}
}
const loginNavbar = async (req, res) => {
try {
let user = await User.findOne(req.body).select('username').exec()
return res.json(user)
} catch (error) {
alert('올바르지 못한 접근입니다.')
}
}
export default { signup, profileUpload, update, userById, getProfile, loginNavbar, checkUser }
// {} : 객체로 return함
import mongoose from 'mongoose'
const { String } = mongoose.Schema.Types
const ChatSchema = new mongoose.Schema({
room: {
type: mongoose.ObjectId,
required: true,
ref: 'Room',
},
username: {
type: String,
required: true,
},
message: {
type: String,
required: true
},
profileimg :{
type: String,
default: '3cd14b9bcb2007f324fcb82e0b566cce'
}
}, {
timestamps: true
})
export default mongoose.models.Chat || mongoose.model('Chat', ChatSchema)
\ No newline at end of file
import mongoose from 'mongoose'
const { String } = mongoose.Schema.Types
const EntryLogSchema = new mongoose.Schema({
userId: {
type: mongoose.ObjectId,
required: true,
ref: 'User',
},
room: {
type: mongoose.ObjectId,
required: true,
ref: 'Room',
},
leaveTime: {
type: String,
required: true,
}
}, {
timestamps: true
})
export default mongoose.models.EntryLog || mongoose.model('EntryLog', EntryLogSchema)
import mongoose from 'mongoose'
const {String} = mongoose.Schema.Types
const {Array} = mongoose.Schema.Types
const RoomSchema = new mongoose.Schema({
roomId: {
type: String,
// default:() => nanoid(),
unique: true
},
roomName: {
type: String,
required: true,
},
interest: {
type: String,
required: true,
// select: false
},
isOpen: {
type: Boolean,
required: true,
},
member: {
type: Array,
required: true,
},
}, {
timestamps: true
})
export default mongoose.models.Room || mongoose.model('Room', RoomSchema)
//주고받는 형식을 정의함.
import mongoose from 'mongoose'
const { String } = mongoose.Schema.Types
const { Array } = mongoose.Schema.Types
//원래 java의 string이 아니라 mongoose의 string을 쓰기 위해 불러옴.
//object의 id를 쓸때에도 추가시켜줘야됨.
//형식을 정의함.
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
},
nickname: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
//unique: 같은 email을 두번넣으면 error발생함
},
password: {
type: String,
required: true,
select: false,
//정보를 찾을때 찾지 않게함
//플러스 옵션을 주면 찾을 수 있음(mongoose에서 용법찾아봐야됨)
},
profileimg: {
type: String,
default: '3cd14b9bcb2007f324fcb82e0b566cce',
},
}, {
timestamps: true
})
export default mongoose.models.User || mongoose.model('User', UserSchema)
import express from 'express'
import authCtrl from '../controllers/auth.controller.js'
const router = express.Router()
//router의 역할 : './주소'부분을 처리하는 역할함.
router.route('/auth/login')
.post(authCtrl.login)
.get(authCtrl.login)
router.route('/auth/logout')
.get(authCtrl.logout)
export default router
\ No newline at end of file
import express from 'express'
import roomCtrl from '../controllers/room.controller.js'
const router = express.Router()
router.route('/room/makeRoom')
.post(roomCtrl.makeRoom)
router.route('/room/changeMem')
.put(roomCtrl.changemember)
.get(roomCtrl.roomInf)
router.route('/room/closedlist')
.get(roomCtrl.getClosedList)
router.route('/room/openlist')
.get(roomCtrl.getOpenList)
router.route('/room/member')
.put(roomCtrl.changemember)
router.route('/room/getRoomName')
.get(roomCtrl.getRoomName)
router.route('/room/unreadMessage')
.get(roomCtrl.unreadMessage)
router.route('/room/deleteMem')
.put(roomCtrl.deleteUserId)
export default router
import express from 'express'
import roomEnterCtrl from '../controllers/roomEnter.controller.js'
const router = express.Router()
router.route('/room/enterRoom')
.post(roomEnterCtrl.roomEnter)
router.route('/room/getChatInfo')
.get(roomEnterCtrl.getChatInfo)
router.route('/room/entrylog')
.get(roomEnterCtrl.checklog)
.post(roomEnterCtrl.uploadlog)
.put(roomEnterCtrl.updatelog)
export default router
\ No newline at end of file
import express from 'express'
import userCtrl from '../controllers/user.controller.js'
const router = express.Router()
router.route('/users/signup')
.post(userCtrl.signup)
router.route('/users/check')
.get(userCtrl.checkUser)
router.route(`/users/:userId`)
.get(userCtrl.getProfile)
.put(userCtrl.profileUpload, userCtrl.update)
router.param('userId', userCtrl.userById)
export default router
\ No newline at end of file
import express from 'express'
import connectDb from './utils/connectDb.js'
import userRouter from './routes/user.routes.js'
import authRouter from './routes/auth.routes.js'
import roomRouter from './routes/room.routers.js'
import roomEnterRouter from './routes/roomEnter.routers.js'
import bodyParser from "body-parser";
import http from "http";
import { Server } from 'socket.io';
import cors from "cors"
import Room from './models/Room.js'
import Chat from "./models/Chat.js"
connectDb()
const app = express()
const server = http.createServer(app);
const io = new Server(server)
io.on("connection", (socket) => { // 기본 연결
console.log("socket connect ok", socket.id)
socket.on('joinRoom', (data) => { // joinRoom을 클라이언트가 emit했을 때
let roomInfo = data;
socket.join(roomInfo); //클라이언트에서 data에 적힌 room으로 참여시킴
});
socket.on('closeRoom', (data) => {
let roomInfo = data;
socket.leave(roomInfo); //클라이언트에서 data에 적힌 room정보를 브로드캐스팅 받지 않는다.
});
socket.on('chat', async (data) => {
const room = await Room.findOne({ roomId: data.roomInfo })
const chat = await new Chat({
room: room._id,
username: data.sendInfo.sender,
message: data.sendInfo.msg,
profileimg: data.sendInfo.img
}).save()
socket.broadcast.to(data.roomInfo).emit('sendedMSG', data.sendInfo); // sender 제외 특정 방으로
socket.broadcast.emit('checking', data.sendInfo) // 메세지를 어딘가에서 보냈다는 신호
});
socket.on('disconnect', () => {
console.log('disconnected from server id=', socket.id)
})
});
app.use(bodyParser.json());
app.use(cors());
app.use('/images', express.static('uploads/'))
app.use(userRouter)
app.use(authRouter)
app.use(roomRouter)
app.use(roomEnterRouter)
server.listen(3030, () => {
console.log('Listening on port 3030')
})
export default server
\ No newline at end of file
function catchErrors(error, displayError){
let errorMsg
if (error.response){
errorMsg = error.response.data
console.log(errorMsg)
} else if (error.request) {
errorMsg = error.request
console.log(errorMsg)
} else {
errorMsg = error.message
console.log(errorMsg)
}
displayError(errorMsg)
}
export default catchErrors
\ No newline at end of file
import mongoose from 'mongoose'
import config from '../config.js'
const connection = {}
async function connectDb() {
if (connection.isConnected) {
return
}
const db = await mongoose.connect(config.mongoDbUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true
})
connection.isConnected = db.connections[0].readyState
}
export default connectDb
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment