그저 내가 되었고

항해99) 4주차:: 주특기 숙련; 개인과제 전체코드(JS)(ver.MongoDB) 본문

개발/항해99 9기

항해99) 4주차:: 주특기 숙련; 개인과제 전체코드(JS)(ver.MongoDB)

hyuunii 2022. 10. 11. 17:23

사족

이걸 굳이 매번 다 올리는 이유는...

항해하면서 너무 힘들지만 절대 포기하고 싶지 않은 분들이 보시고 꼭 도움 받으시길 원하기 때문입니다.

제 뒤에 항해하시게 될 누군가가 만약 저처럼 너무너무 힘들어 하고 계시다면(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;