그저 내가 되었고

항해99) 5주차:: 주특기 심화; 팀과제 전체코드(JS) 본문

개발/항해99 9기

항해99) 5주차:: 주특기 심화; 팀과제 전체코드(JS)

hyuunii 2022. 10. 17. 22:04

app.js

더보기
const express = require("express");
const likeRouter = require("./routes/like.routes.js");
const postsRouter = require("./routes/posts.routes.js");
const commentsRouter = require("./routes/comments.routes.js");
const userRouter = require("./routes/user.routes.js");

const app = express();
const router = express.Router();

app.use(express.json());
// 👆🏻JSON 이라는 규격의 body 데이터를 손쉽게 사용할 수 있게 도와주는 미들웨어
app.use("/", express.urlencoded({ extended: false }), router);
// 👆🏻form-urlencoded 라는 규격의 body 데이터를 손쉽게 사용할 수 있게 도와주는 미들웨어
app.use("/", [likeRouter, postsRouter, commentsRouter, userRouter]);

app.listen(8080, () => {
    console.log("서버가 요청을 받을 준비가 됐어요");
});

 

 

user.routes.js

더보기
const express = require('express');
const userRouter = express.Router();
const UserController = require('../controllers/user.controller');  //⭐
const userController = new UserController();  //⭐AuthController에 대한 클래스 선언해서 authController에 담음
const authMiddleware = require("../middlewares/auth-middlewares");

userRouter.post('/signup', userController.signup);  //⭐②createPost 메소드로 연결
userRouter.post('/login', userController.login);  //⭐②createPost 메소드로 연결

module.exports = userRouter;

 

posts.routes.js

더보기
const express = require('express');
const router = express.Router();

const PostsController = require('../controllers/posts.controller');  //⭐
const postsController = new PostsController();  //⭐PostsController에 대한 클래스 선언해서 postsController에 담음

router.get('/posts', postsController.getPosts);  //⭐①getPosts 메소드로 연결; http 메소드가 겟이고, 기본  url로 들어왔을 때, postsController의 getPosts 메소드가 실행된다~!
router.get('/posts/:postId', postsController.getPostById); //❤
router.post('/posts', postsController.createPost);  //⭐②createPost 메소드로 연결
router.put('/posts/:postId', postsController.updatePost);  //❤
router.delete('/posts/:postId', postsController.deletePost); //❤

module.exports = router;

 

like.routes.js

더보기
const express = require('express');
const router = express.Router();
const authMiddleware = require("../middlewares/auth-middlewares");

const LikeController = require('../controllers/like.controller');  //⭐
const likeController = new LikeController();  //⭐PostsController에 대한 클래스 선언해서 postsController에 담음

router.get('/posts/like', authMiddleware, likeController.getLikedPosts); //❤
router.put('/posts/:postId/like', authMiddleware, likeController.updateLike);  //❤

module.exports = router;

 

comments.routes.js

더보기
const express = require('express');
const router = express.Router();

const CommentsController = require('../controllers/comments.controller');
const commentsController = new CommentsController();

router.get('/comments/:postId', commentsController.getComments);
router.post('/comments/:postId', commentsController.createComment);
router.put('/comments/:commentId', commentsController.updateComment);
router.delete('/comments/:commentId', commentsController.deleteComment);

module.exports = router;

 

 

user.controller.js

더보기
const UserService = require('../services/user.service');
const Joi = require('joi');
const schema = Joi.object({
    nickname: Joi.string().min(2).max(15).required(),
    password: Joi.string().min(4).max(20).required(),
    confirm: Joi.string().min(4).max(20).required(),
});

class UserController {

    userService = new UserService();

    signup = async (req, res, next) => {
        try {
            const verifyFormat = await schema.validateAsync(req.body)
            //console.log(verifyFormat);
            const registerUser = await this.userService.signup(verifyFormat);
            res.status(200).json({data: registerUser})
        } catch (error) {
            console.log(`${error.message}`);
            res.status(400).send({errorMessage: "요청한 데이터 형식이 올바르지 않습니다."});
        }
    };


    login = async (req, res, next) => {
        try {
            const {nickname, password} = req.body;
            const user = await this.userService.login(nickname, password);
           // console.log(user)
            res.status(200).json({data: user});
        } catch (error) {
            console.log(`${error.message}`);
            res.status(400).send({errorMessage: "요청한 데이터 형식이 올바르지 않습니다."});
        }
    };
}

module.exports = UserController;

 

posts.controller.js

더보기
const PostService = require('../services/posts.service');

// Post의 컨트롤러(Controller)역할을 하는 클래스
class PostsController {
    postService = new PostService(); // Post 서비스 클래스를/컨트롤러 클래스의/멤버 변수로 할당

    getPosts = async (req, res, next) => {  //①getPosts 메소드
        // 서비스 계층에 구현된 findAllsPost 로직을 실행합니다.
        const posts = await this.postService.findAllPosts();  //PostsController 클래스에서 멤버 변수로 정의한 postService에서 findAllPosts 메소드를 실행하고 그 결괏값을 posts라는 변수에 할당하는 코드
        res.status(200).json({data: posts})  //위에서 할당한 결괏값을 사용자에게 리턴하는 코드
    }

    getPostById = async (req, res, next) => {
        const {postId} = req.params
        const post = await this.postService.findPostById(postId);
        res.status(200).json({data: post});
    };

    createPost = async (req, res, next) => {  //②createPost 메소드
        const {nickname, password, title, content} = req.body;  //body 데이터를 객체구조분해할당해서 4개의 인자들을 변수로 선언
        // 서비스 계층에 구현된 createPost 로직을 실행합니다.
        const createPostData = await this.postService.createPost(nickname, password, title, content);  //위의 인자들을 createPost라는 로직으로 구현, 로직 실행 후 결괏값을 createPostData라는 변수에 할당하고
        res.status(201).json({data: createPostData});  //할당값을 http 스테이러스 코드 201로 사용자에게 리턴
    }

    updatePost = async (req, res, next) => {
        const { postId } = req.params;
        const { password, title, content } = req.body;
        const updatePost = await this.postService.updatePost(
            postId,
            password,
            title,
            content
        );
        res.status(200).json({data: updatePost});
    };

    deletePost = async (req, res, next) => {
        const { postId } = req.params;
        const { password } = req.body;
        const deletePost = await this.postService.deletePost(postId, password);
        res.status(200).json({data: deletePost});
    };
}

module.exports = PostsController;

 

like.controllers.js

더보기
const LikeService = require('../services/like.service');
const PostService = require('../services/posts.service');

class LikeController {
    likeService = new LikeService(); // Post 서비스 클래스를/컨트롤러 클래스의/멤버 변수로 할당

    getLikedPosts = async (req, res, next) => {
        const { nickname } = res.locals.user;
        const likedPosts = await this.likeService.getLikedPosts(nickname);
        res.status(200).json({data: likedPosts});
    };

    updateLike = async (req, res, next) => {
        const { postId } = req.params;
        const { nickname } = res.locals.user;
        const isLiked = await this.likeService.didILikeThis(postId, nickname);

        /*취소*/
        if (isLiked) {
            const cancelLike = await this.likeService.cancelLike(postId, nickname);
            res.status(200).json({data: cancelLike});
        }

        /*신규*/
        else {
            const addLike = await this.likeService.addLike(postId, nickname);
            res.status(200).json({data: addLike});
        }
    }
}

module.exports = LikeController;

 

comments.controllers.js

더보기
const CommentService = require('../services/comments.service')

// Post의 컨트롤러(Controller)역할을 하는 클래스
class CommentsController {
    commentService = new CommentService(); // Post 서비스 클래스를/컨트롤러 클래스의/멤버 변수로 할당

    getComments = async (req, res, next) => {  //①getPosts 메소드
        // 서비스 계층에 구현된 findAllPost 로직을 실행합니다.
        const { postId } = req.params;
        const comments = await this.commentService.findAllComments(postId);  //PostsController 클래스에서 멤버 변수로 정의한 postService에서 findAllPost 메소드를 실행하고 그 결괏값을 posts라는 변수에 할당하는 코드
        res.status(200).json({data: comments})  //위에서 할당한 결괏값을 사용자에게 리턴하는 코드
    }

    createComment = async (req, res, next) => {  //②createPost 메소드
        const { postId } = req.params;
        const { nickname, comment, password } = req.body;  //body 데이터를 객체구조분해할당해서 4개의 인자들을 변수로 선언
        // 서비스 계층에 구현된 createPost 로직을 실행합니다.
        const createCommentData = await this.commentService.createComment(postId, nickname, comment, password);  //위의 인자들을 createPost라는 로직으로 구현, 로직 실행 후 결괏값을 createPostData라는 변수에 할당하고
        res.status(201).json({data: createCommentData});  //할당값을 http 스테이러스 코드 201로 사용자에게 리턴
    }

    updateComment = async (req, res, next) => {
        const { commentId } = req.params;
        const { nickname, comment, password } = req.body;
        const updateComment = await this.commentService.updateComment(
            commentId,
            nickname,
            comment,
            password
        );
        res.status(200).json({data: updateComment});
    };

    deleteComment = async (req, res, next) => {
        const { commentId } = req.params;
        const { password } = req.body;
        const deleteComment = await this.commentService.deleteComment(commentId, password);
        res.status(200).json({data: deleteComment});
    };
}

module.exports = CommentsController;

 

 

user.services.js

더보기
const UserRepository = require('../repositories/user.repository');
const jwt = require("jsonwebtoken");
const { User } = require("../models");

class UserService {
    userRepository = new UserRepository();

    signup = async (verifyFormat) => {
        try {
            if (verifyFormat.password !== verifyFormat.confirm) {
                throw new Error("패스워드와 패스워드 확인란이 다릅니다")
            }

                    console.log(verifyFormat)
            const existsUser = await this.userRepository.findUserByNickname(verifyFormat);

            if (existsUser) {
                throw new Error("중복된 닉네임입니다.")
            }

            await this.userRepository.signup(verifyFormat.nickname, verifyFormat.password);
            return "회원가입에 성공하였습니다.";
        } catch (error) {
            console.log(`${error.name} : ${error.message}`);
            throw new Error(error);
        }
    };

    login = async (nickname, password) => {
        const user = await this.userRepository.login(nickname, password);
        if (!user || password !== user.password || nickname !== user.nickname) {
           return "닉네임 또는 패스워드를 확인해주세요."
        }
        let token =  jwt.sign({userId: user.userId}, "mySecretKey");
        return { message: "로그인 성공", token: token };
    }
}

module.exports = UserService;



/*router.post("/signup", async (req, res) => {
    try {
        const {nickname, password, confirm} = await userSchema.validateAsync(req.body);
        const existsUsers = await Users.findOne({where: { nickname }})
        if (password.search(nickname) === nickname) {
            res.status(400).send({ errorMessage: "형식에 맞지 않는 비밀번호입니다." });
            return;
        }
        if (password !== confirm) {
            res.status(400).send({ errorMessage: "패스워드가 패스워드 확인란과 다릅니다." });
            return;
        }
        if (existsUsers) {
            res.status(400).send({ errorMessage: "중복된 닉네임입니다." });
            return;
        }
        await Users.create({nickname, password});
        res.status(201).send({message: "회원가입에 성공하였습니다."});
    } catch (error) {
        a
    }
});*/

 

posts.services.js

더보기
const PostRepository = require('../repositories/posts.repository');  //서비스 계층은 실제로 db 안의 정보를 사용하며, 그러기 위해서는 하위 계층의 repository모듈을 호출.

class PostService { //PostService 클래스 내부에
    postRepository = new PostRepository();  //멤버 변수로 postRepository 선언, 그 변수는 postRepository 클래스를 만든 인스턴스

    findAllPosts = async () => {   //①findAllPost 메소드 하나
        // 저장소(Repository)에게 데이터를 요청합니다.
        const allPosts = await this.postRepository.findAllPosts();  //레파지토리에서 findAllPost라는 메소드 실행해서 가져온 데이터들을 allPost라는 변수에 할당함

        // 호출한 Post들을 가장 최신 게시글 부터 정렬합니다.
        allPosts.sort((a, b) => {  //그리고 위에서 repository에서 가져온 모든 게시글들을 정렬함
            return b.createdAt - a.createdAt;
        })

        // 비즈니스 로직을 수행한 후 사용자에게 보여줄 데이터를 가공합니다.
        return allPosts.map(post => {  //정렬된 데이터를 맵으로 가공 후 컨트롤러에 반환. 맵 실행하면 결과는 배열로 나오고, 거기다가 내부의 각각 하나의 데이터(postId 등)들은 큰 array 안의 각각의 post 객체에서 가져왔다(그니까.. password는 빼고 보여줘야 할 것 아님? 그거심)
            return {  //data 가공해서 컨트롤러에 전달 위한 부분
                postId: post.postId,
                nickname: post.nickname,
                title: post.title,
                createdAt: post.createdAt,
                updatedAt: post.updatedAt
            }
        });
    }

    findPostById = async (postId) => {
        const post = await this.postRepository.findPostById(postId);
        return {  //data 가공해서 컨트롤러에 전달 위한 부분
            postId: post.postId,
            nickname: post.nickname,
            title: post.title,
            createdAt: post.createdAt,
            updatedAt: post.updatedAt
        };
    };

    createPost = async (nickname, password, title, content) => {  //②createPost 메소드 둘. 네 개의 인자를 받아 실제로 post 생성함.
        // 저장소(Repository)에게 데이터를 요청합니다.
        const createPostData = await this.postRepository.createPost(nickname, password, title, content);  //받은 데이터로 바로 포스트 생성해버림. repository에 createPost라는 메소드 호출해서 실제로 단순하게 게시글 작성하는 문법. 작성된 결괏값을 createPostData에 할당

        // 비즈니스 로직을 수행한 후 사용자에게 보여줄 데이터를 가공합니다.
        return {  //createPostData를 이 로직으로 아래와 같이 가공하여 컨트롤러에 반환함.
            postId: createPostData.null,
            nickname: createPostData.nickname,
            title: createPostData.title,
            content: createPostData.content,
            createdAt: createPostData.createdAt,
            updatedAt: createPostData.updatedAt,
        };
    }

    updatePost = async (postId, password, title, content) => {
        const findPost = await this.postRepository.findPostById(postId);
        if (!findPost) throw new Error("Post doesn't exist");

        await this.postRepository.updatePost(postId, password, title, content);

        const updatePost = await this.postRepository.findPostById(postId);

        return {
            postId: updatePost.postId,
            nickname: updatePost.nickname,
            title: updatePost.title,
            content: updatePost.content,
            createdAt: updatePost.createdAt,
            updatedAt: updatePost.updatedAt,
        };
    };

    deletePost = async (postId, password) => {
        const findPost = await this.postRepository.findPostById(postId);
        if (!findPost) throw new Error("Post doesn't exist");

        await this.postRepository.deletePost(postId, password);

        return {
            postId: findPost.postId,
            nickname: findPost.nickname,
            title: findPost.title,
            content: findPost.content,
            createdAt: findPost.createdAt,
            updatedAt: findPost.updatedAt,
        };
    };
}

module.exports = PostService;

 

like.services.js

더보기
const LikeRepository = require('../repositories/like.repository');  //서비스 계층은 실제로 db 안의 정보를 사용하며, 그러기 위해서는 하위 계층의 repository모듈을 호출.
const PostRepository = require('../repositories/posts.repository');

class LikeService { //PostService 클래스 내부에
    likeRepository = new LikeRepository();
    postRepository = new PostRepository();
    //멤버 변수로 postRepository 선언, 그 변수는 postRepository 클래스를 만든 인스턴스

    getLikedPosts = async (nickname) => {
        const likedPosts = await this.likeRepository.getLikedPosts(nickname);
        const arrPostId = likedPosts.map((post) => {
            return post.postId;
        })
       // const forPostId
        const getLikedPosts = await this.postRepository.getLikedPosts(arrPostId);

        const mapPosts = getLikedPosts.map((post) => {
            return {
                postId: post.postId,
                nickname: post.nickname,
                title: post.title,
                likes: post.likes,
                createdAt: post.createdAt,
                updatedAt: post.updatedAt,
            }
        })
        return mapPosts;
    };

    didILikeThis = async (postId, nickname) => {
        const likedOrNot = await this.likeRepository.didILikeThis(postId, nickname);
        return likedOrNot
    };

    addLike = async (postId, nickname) => {
        await this.likeRepository.addLike(postId, nickname);
        await this.postRepository.plusLikesNum(postId);
        return ("좋아요 등록");
    };

    cancelLike = async (postId, nickname) => {
        await this.likeRepository.cancelLike(postId, nickname);
        await this.postRepository.minusLikesNum(postId);
        return ("좋아요 취소");
    };
}

module.exports = LikeService;

 

comments.services.js

더보기
const commentRepository = require('../repositories/comments.repository');  //서비스 계층은 실제로 db 안의 정보를 사용하며, 그러기 위해서는 하위 계층의 repository모듈을 호출.

class CommentService {
   commentRepository = new commentRepository();  //멤버 변수로 postRepository 선언, 그 변수는 postRepository 클래스를 만든 인스턴스

    findAllComments = async (postId) => {   //①findAllPost 메소드 하나
        const allComments = await this.commentRepository.findAllComments(postId);

        allComments.sort((a, b) => {
            return b.createdAt - a.createdAt;
        })

        // 비즈니스 로직을 수행한 후 사용자에게 보여줄 데이터를 가공합니다.
        return allComments.map(comment => {  //정렬된 데이터를 맵으로 가공 후 컨트롤러에 반환. 맵 실행하면 결과는 배열로 나오고, 거기다가 내부의 각각 하나의 데이터(postId 등)들은 큰 array 안의 각각의 post 객체에서 가져왔다(그니까.. password는 빼고 보여줘야 할 것 아님? 그거심)
            return {  //data 가공해서 컨트롤러에 전달 위한 부분
                postId: comment.postId,
                commentId: comment.commentId,
                nickname: comment.nickname,
                createdAt: comment.createdAt,
                updatedAt: comment.updatedAt
            }
        });
    }

    createComment = async (postId, nickname, password, comment) => {  //②createPost 메소드 둘. 네 개의 인자를 받아 실제로 post 생성함.
        // 저장소(Repository)에게 데이터를 요청합니다.
        const createCommentData = await this.commentRepository.createComment(postId, nickname, password, comment);  //받은 데이터로 바로 포스트 생성해버림. repository에 createPost라는 메소드 호출해서 실제로 단순하게 게시글 작성하는 문법. 작성된 결괏값을 createPostData에 할당

        // 비즈니스 로직을 수행한 후 사용자에게 보여줄 데이터를 가공합니다.
        return {  //createPostData를 이 로직으로 아래와 같이 가공하여 컨트롤러에 반환함.
            postId: createCommentData.postId,
            commentID: createCommentData.commentID,
            nickname: createCommentData.nickname,
            comment: createCommentData.comment,
            createdAt: createCommentData.createdAt,
            updatedAt: createCommentData.updatedAt,
        };
    }

    updateComment = async (commentId, nickname, comment, password) => {
        const findComment = await this.commentRepository.findCommentById(commentId);
        if (!findComment) throw new Error("Comment doesn't exist");

        await this.commentRepository.updateComment(commentId, nickname, comment, password);

        const updateComment = await this.commentRepository.findCommentById(commentId);

        return {
            commentId: updateComment.commentId,
            nickname: updateComment.nickname,
            comment: updateComment.comment,
            createdAt: updateComment.createdAt,
            updatedAt: updateComment.updatedAt,
        };
    };

    deleteComment = async (commentId, password) => {
        const findComment = await this.commentRepository.findCommentById(commentId);
        if (!findComment) throw new Error("Comment doesn't exist");

        await this.commentRepository.deleteComment(commentId, password);

        return {
            postId: findComment.postId,
            commentId: findComment.commentId,
            nickname: findComment.nickname,
            content: findComment.content,
            createdAt: findComment.createdAt,
            updatedAt: findComment.updatedAt,
        };
    };
}

module.exports = CommentService;

 

 

user.repositories.js

더보기
const { User } = require("../models");

class UserRepository {
    findUserByNickname = async (verifyFormat) => {
        const nickname = verifyFormat.nickname;
        const user = await User.findOne({where: {nickname}});
        return user;
    };

    signup = async (nickname, password) => {
        const registerUser = await User.create( {nickname, password});
        return registerUser;
        console.log(registerUser)
    }

    login = async (nickname, password) => {
        const findUser = await User.findOne({where: {nickname, password}});
        return findUser;
    }
}

module.exports = UserRepository;

 

posts.repositories.js

더보기
// repositories/posts.repository.js

const {Posts} = require('../models');  //⓪models 안의 Posts 모듈을 가져옴. 왜? 이 repository에서 sequelize를 통해서 Posts 테이블에 접근을 하기 위해서

class PostRepository {  //PostRepository클래스는 ORM인 Sequelize에서 Posts 모델의 findAll 메소드를 사용해 데이터를 요청
    findAllPosts = async () => {  //①findAllPost메소드와
        const posts = await Posts.findAll();  //⓪에서 가져온 Posts에서 실제 db에 접근하여 데이터 사용. Posts 라는 모델에서 findAll 이용해서 데이터(게시글) 몽땅 찾아서 posts란 변수에 할당 후
        return posts;  //걔를 리턴
    }

    findPostById = async (postId) => {
        const post = await Posts.findByPk(postId);
        return post;
    };

    createPost = async (nickname, password, title, content) => {  //②createPost 메소드를 가짐
        // ORM인 Sequelize에서 Posts 모델의 create 메소드를 사용해 데이터를 요청합니다.
        const createPostData = await Posts.create({nickname, password, title, content});
        return createPostData;
    }

    updatePost = async (postId, password, title, content) => {
        const updatePostData = await Posts.update({title, content}, {where: {postId, password}}
        );
        return updatePostData;
    };

    deletePost = async (postId, password) => {
        const updatePostData = await Post.destroy({Where: {postId, password}});
        return updatePostData;
    };
}

module.exports = PostRepository;

 

like.repositories.js

더보기
// repositories/posts.repository.js

const { Like } = require('../models');  //⓪models 안의 Posts 모듈을 가져옴. 왜? 이 repository에서 sequelize를 통해서 Posts 테이블에 접근을 하기 위해서

class LikeRepository {
    getLikedPosts = async (nickname) => {
        const likedPosts = await Like.findAll({ where: { nickname } })
        return likedPosts;
    }

    didILikeThis = async (postId, nickname) => {
        const hereItIs = await Like.findOne({ where: { postId, nickname } });
        return hereItIs;
    };

    addLike = async (postId, nickname) => {
        const updateLikeData = await Like.create({ postId, nickname });
        return updateLikeData;
    };

    cancelLike = async (postId, nickname) => {
        const updateLikeData = await Like.destroy({where: {postId, nickname}});
        return updateLikeData;
    };
}

module.exports = LikeRepository;

 

comments.repositories.js

더보기
const { Comments } = require('../models');  //⓪models 안의 Posts 모듈을 가져옴. 왜? 이 repository에서 sequelize를 통해서 Posts 테이블에 접근을 하기 위해서

class CommentRepository {
    findAllComments = async (postId) => {
        const comments = await Comments.findAll({where: {postId}});
        return comments;
    }

    findCommentById = async (commentID) => {
        const comment = await Comments.findByPk(commentID);
        return comment;
    }

    createComment = async (postId, nickname, comment, password) => {
        const createCommentData = await Comments.create({postId, nickname, comment, password});
        return createCommentData;
    }

    updateComment = async (commentId, nickname,  comment, password) => {
        const updateCommentData = await Comments.update({ comment }, {where: {commentId, nickname, password}}
        );
        return updateCommentData;
    };

    deleteComment = async (commentId, password) => {
        const updateCommentData = await Comments.destroy({where: {commentId, password}});
        return updateCommentData;
    };
}

module.exports = CommentRepository;