그저 내가 되었고
항해99) 4주차:: 주특기 숙련; 개인과제 전체코드(JS)(ver.MongoDB) 본문
사족
이걸 굳이 매번 다 올리는 이유는...
항해하면서 너무 힘들지만 절대 포기하고 싶지 않은 분들이 보시고 꼭 도움 받으시길 원하기 때문입니다.
제 뒤에 항해하시게 될 누군가가 만약 저처럼 너무너무 힘들어 하고 계시다면(T T) 그 마음을 너무 잘 알기에.. 제 마음도 많이 아플 것 같아요.
답지 보고 공부하는것도 도움이 많이 되더라고요. 잘 이해만 하면 돼요.
꼭, 이해하는것 절대로 포기하지 마시고 끝까지 완주해봅시다,,,,,(나도!!!!!!!!!!!!!!!!!!!!!!!)
app.js
더보기
const express = require("express");
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost/4W_indivAssg", {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error:"));
const app = express();
const router = express.Router();
app.use(express.json()); //JSON 이라는 규격의 body 데이터를 손쉽게 코드에서 사용할 수 있게 도와주는 미들웨어
app.use("/", express.urlencoded({ extended: false }), router); //form-urlencoded 라는 규격의 body 데이터를 손쉽게 코드에서 사용할 수 있게 도와주는 미들웨어
const postsRouter = require("./routes/posts");
const commentsRouter = require("./routes/comments");
const signupRouter = require("./routes/signup");
const loginRouter = require("./routes/login");
app.use("/", [postsRouter, commentsRouter, signupRouter, loginRouter]);
app.listen(8080, () => {
console.log("서버가 요청을 받을 준비가 됐어요");
});
middlewares/auth-middleware.js
더보기
const jwt = require("jsonwebtoken");
const User = require("../models/user");
module.exports = async (req, res, next) => {
const {authorization} = req.headers;
//console.log(authorization)
const [authType, authToken] = (authorization || "").split(" ");
//console.log(authToken)
if (!authToken || authType !== "Bearer") {
res.status(401).send({
errorMessage: "로그인이 필요합니다.",
});
return;
}
try {
const { userId } = jwt.verify(authToken, "시크릿키");
const user = await User.findOne( { nickname: userId } ); //💛💛사용자 1인의 데이터 전체
res.locals.user = user; // 바로 위에서 찾은 사용자 1명을 res~변수에 다 보관
// User.findOne({ nickname: userId }).then((user) => {
// res.locals.user = user; //토큰의 userId로 해당 사용자가 맞는지 확인함. 이미 db에서 사용자 정보 가져온 것. 그러므로 이 미들웨어를 사용하는 라우터에서는 굳이 db에서 사용자 정보를 꺼내오지 않아도 되도록 express가 제공하는 안전한 변수(res.locals.user)에 담아두고 언제나 꺼내서 사용할 수 있게 작성함. 이렇게 담아둔 값은 정상적으로 응답 값을 보내고 나면 소멸하므로 해당 데이터가 어딘가에 남아있을 걱정의 여지를 남겨두지 않게 됨.
next();
// });
} catch (err) {
res.status(401).send({
errorMessage: "로그인이 필요한 기능입니다.",
});
}
};
models/user.js
더보기
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
nickname: String,
password: String,
});
/*UserSchema.virtual("userId").get(function () {
return this._id.toHexString();
});
UserSchema.set("toJSON", {
});*/
module.exports = mongoose.model("User", UserSchema);
models/post.js
더보기
const mongoose = require("mongoose");
const postsSchema = new mongoose.Schema({
postId: {
type: Number,
required: false,
},
nickname: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
content: {
type: String,
required: true,
},
likes: {
type: Number,
required: true,
},
},
{
timestamps: true
});
module.exports = mongoose.model("Posts", postsSchema);
models/like.js
더보기
const mongoose = require("mongoose");
const postsSchema = new mongoose.Schema({
postId: {
type: String,
required: true,
},
nickname: {
type: String,
required: true,
},
title: {
type: String,
//required: true,
},
likes: {
type: Number,
required: true,
},
},
{
timestamps: true
});
module.exports = mongoose.model("Likes", postsSchema);
models/comment.js
더보기
const mongoose = require("mongoose");
const commentsSchema = new mongoose.Schema({
postId: {
type: String
},
commentId: {
type: Number
},
// userId: {
// type: String,
// required: true,
// },
nickname: {
type: String,
required: true,
},
comment: {
type: String,
//required: true,
},
},
{
timestamps: true
});
module.exports = mongoose.model("Comments", commentsSchema);
routes/signup.js
더보기
const express = require("express");
const router = express.Router();
const User = require("../models/user");
const Joi = require("joi");
const userSchema = Joi.object({
nickname: Joi.string(), //.pattern(new RegExp("^[a-zA-Z0-9]{3,30}$")).required(),
password: Joi.string(), //.pattern(new RegExp("^{4,30}$")).required(),
confirm: Joi.string() //.pattern(new RegExp("^{4,30}$")).required(),
});
router.post("/signup", async (req, res) => {
try {
const {nickname, password, confirm} = await userSchema.validateAsync(req.body);
if (password.search(nickname) === nickname) {
res.status(400).send({
errorMessage: "형식에 맞지 않는 비밀번호입니다.",
});
return;
}
if (password !== confirm) {
res.status(400).send({
errorMessage: "패스워드가 패스워드 확인란과 다릅니다.",
});
return;
}
const existsUsers = await User.findOne({nickname});
if (existsUsers) {
res.status(400).send({
errorMessage: "중복된 닉네임입니다.",
});
return;
}
const user = new User({nickname, password});
await user.save();
res.status(201).send({message: "회원가입에 성공하였습니다."});
} catch (error) {
console.log(`${req.method} ${req.originalUrl} : ${error.message}`);
res.status(400).send({
errorMessage: "요청한 데이터 형식이 올바르지 않습니다.",
});
}
});
module.exports = router;
routes/posts.js
더보기
const express = require('express');
const router = express.Router();
const Posts = require("../models/post")
const Likes = require("../models/like");
const authMiddleware = require("../middlewares/auth-middleware");
//1. 전체 게시글 목록 조회 API
router.get("/posts", async (req, res) => {
const item = await Posts.find().sort({updatedAt: -1})
const mapItem = item.map((item) => {
return {
postId: item._id,
nickname: item.nickname,
title: item.title,
createdAt: item.createdAt,
updatedAt: item.updatedAt,
likes: item.likes
}
})
res.json({item: mapItem});
});
//6. 라잌 게시글 목록 조회 API
router.get("/posts/like", authMiddleware, async (req, res) => {
const { nickname } = res.locals.user;
console.log(nickname);
const item = await Likes.find({ nickname }).sort({ likes: -1})
const mapItem = item.map((item) => {
return {
postId: item.postId,
nickname: item.nickname,
title: item.title,
createdAt: item.createdAt,
updatedAt: item.updatedAt,
likes: item.likes
}
})
res.json({item: mapItem});
});
//7. 라잌/디스라잌 게시글 API
router.put("/posts/:postId/like", authMiddleware, async (req, res) => {
const { postId } = req.params;
const { nickname } = res.locals.user;
console.log(nickname)
const is_liked = await Likes.findOne({$and: [{ nickname }, { postId }]});
const existLikes = await Posts.find({ postId: postId }).sort("-likes");
let likesnum = 0;
/*취소*/
if (is_liked) {
await Likes.deleteOne({
postId: postId,
});
likesnum = (existLikes[0].likes)*1 - 1;
await Posts.updateOne({ postId: postId }, {$set: { likes : likesnum }});
res.send({result: "success", message: "게시글의 좋아요를 취소하였습니다."});
}
/*신규*/
else {
// if (existLikes.length) {
const post = await Posts.findOne({ postId: postId });
likesnum = (existLikes[0].likes) * 1 + 1;
await Likes.create({
postId: postId,
nickname: nickname,
title: post.title,
likes: likesnum
});
await Posts.updateOne({postId: postId}, {$set: {likes: likesnum}});
res.send({result: "success", message: "게시글의 좋아요를 등록하였습니다."});
//}
// } else {
// const title = await Posts.findOne([{ postId: postId }])
// await Likes.create({
// postId: postId,
// nickname: user.nickname,
// title: title.title
// });
// likesnum = (existLikes[0].likes)*1 + 1;
// await Posts.updateOne({ postId: postId }, {$set: { likes : likesnum}});
//
// res.send({result: "success", message: "게시글의 등록하였습니다."});
// }
}
});
//2. 게시글 상세 조회 API
router.get("/posts/:postId", async (req, res) => {
const {postId} = req.params;
const posts = await Posts.find();
const filteredPosts = posts.filter((item) => {
return item["postId"].toString() === postId;
});
const mapPosts = filteredPosts.map((item) => {
return {
postId: item.postId,
nickname: item.nickname,
title: item.title,
content: item.content,
createdAt: item.createdAt,
updatedAt: item.updatedAt,
likes: item.likes
}
})
res.json({ mapPosts });
})
//3. 게시글 작성 API
router.post("/posts", authMiddleware, async (req, res) => {
try {
const {user} = res.locals;
const existPosts = await Posts.find().sort("-postId");
if (existPosts.length !== 0) {
postId = existPosts[0].postId + 1;
await Posts.create({
postId: postId,
nickname: user.nickname,
title: req.body.title,
content: req.body.content,
likes: 0
});
res.status(201).send({ message: "게시글 작성에 성공하였습니다." });
} else {
await Posts.create({
postId: 1,
nickname: user.nickname,
title: req.body.title,
content: req.body.content,
likes: 0
});
res.status(201).send({ message: "게시글 작성에 성공하였습니다." });
}
} catch (Error) {
return res.status(400).json({ message: "게시글 작성에 실패하였습니다." });
}
})
//4. 게시글 수정 API
router.put("/posts/:postId", authMiddleware, async (req, res) => {
const { postId } = req.params;
const { content, title } = req.body;
const existsPost = await Posts.findOne({ postId: postId });
if (existsPost) {
await Posts.updateOne({ postId: postId }, { $set: { content, title } });
res.send({ result: "success", message: "게시글을 수정하였습니다." });
} else {
res.send({ result: "fail" });
}
})
//5. 게시글 삭제 API
router.delete("/posts/:postId", authMiddleware, async (req, res) => {
const {postId} = req.params;
const existsPost = await Posts.findOne({ postId: postId });
if (existsPost) {
await Posts.deleteOne({ postId: postId });
res.send({ result: "success", message: "게시글을 삭제하였습니다." });
} else {
res.send({ result: "fail" });
}
})
module.exports = router;
routes/login.js
더보기
const express = require("express");
const User = require("../models/user");
const router = express.Router();
const jwt = require("jsonwebtoken");
router.post("/login", async (req, res) => {
const { nickname, password } = req.body;
const user = await User.findOne({ nickname, password });
if (!user || password !== user.password || nickname !== user.nickname) {
res.status(400).send({
errorMessage: "닉네임 또는 패스워드를 확인해주세요.",
});
return;
}
res.send({
token: jwt.sign({ userId: user.nickname }, "시크릿키"),
});
});
module.exports = router;
routes/comments.js
더보기
const express = require('express');
const router = express.Router();
const Comments = require("../models/comment")
const authMiddleware = require("../middlewares/auth-middleware");
const Posts = require("../models/post");
//1. 댓글 목록 조회 API
router.get("/comments/:postId", async (req, res) => {
const { postId } = req.params;
const existsPosts = await Comments.find({ postId: postId }).sort({ updatedAt: -1 });
const mapComments = existsPosts.map((item) => {
return {
commentId: item.commentId,
userId: item.userId,
nickname: item.nickname,
comment: item.comment,
createdAt: item.createdAt,
updatedAt: item.updatedAt
}
})
res.json({mapComments});
});
//2. 댓글 작성
router.post("/comments/:postId", authMiddleware, async (req, res) => {
const { postId } = req.params;
const { user } = res.locals;
const existComments = await Comments.find().sort("-commentId");
if (existComments.length !== 0) {
if (req.body.comment === "") {
res.status(400).json({ success: false, errorMessage: "댓글 내용을 입력해주세요" });
} else {
commentId = existComments[0].commentId + 1;
await Comments.create({
postId: postId,
commentId: commentId,
//userId: user.userId,
nickname: user.nickname,
comment: req.body.comment
});
res.status(201).send({ message: "댓글 등록이 완료되었습니다." });
}
} else {
commentId = 1;
await Comments.create({
postId: postId,
commentId: commentId,
//userId: user.userId,
nickname: user.nickname,
comment: req.body.comment
});
res.status(201).send({message: "댓글 등록이 완료되었습니다."});
}
})
//3. 댓글 수정
router.put("/comments/:commentId", authMiddleware, async (req, res) => {
try {
const { commentId } = req.params;
const { user } = res.locals;
const { comment } = req.body;
if (comment === "") {
res.status(400).json({ success: false, errorMessage: "댓글 내용을 입력해주세요" });
} else {
await Comments.updateOne({ commentId: commentId }, {$set: { comment }});
res.send({ message: "댓글을 수정하였습니다." })
}
} catch (e) {
return res.status(400).json({ success: false });
}
})
//4. 댓글 삭제
router.delete("/comments/:commentId", authMiddleware, async (req, res) => {
try {
const { commentId } = req.params;
const existsComment = await Comments.findOne({ commentId: commentId });
if (existsComment) {
await Comments.deleteOne({commentId: commentId});
res.send({ result: "success", message: "댓글을 삭제하였습니다." });
}
} catch (e) {
return res.status(400).json({ result: "fail" });
}
})
module.exports = router;
'개발 > 항해99 9기' 카테고리의 다른 글
항해99) 4주차:: 주특기 숙련; 📚미들웨어 (0) | 2022.10.12 |
---|---|
항해99) 4주차:: 주특기 숙련; 📚MySQL → Sequelize (0) | 2022.10.12 |
항해99) 4주차:: 주특기 숙련; 📚쿠키 & 세션 & JWT (0) | 2022.10.11 |
항해99) 3주차:: 💡3주차 맺음 WIL; Restful API, package.json + 소회✍🏻 (0) | 2022.10.09 |
항해99) 3주차:: 주특기 입문; 개인과제 전체 코드(JS) (0) | 2022.10.07 |