게시판 CRUD 만들기 2

이재경·2022년 12월 28일
0

백엔드

목록 보기
3/7

1.short-id.js

const { nanoid } = require('nanoid');

const shortId = {
  type: String,
  default: () => {
    return nanoid()
  },
  require: true,
  index: true,
}

module.exports = shortId;

2.post.js

const { Schema } = require('mongoose');
const shortId=require('./types/short-id.js')
const PostSchema = new Schema({
  // shortId 추가
  shortId,
  title: {
    type: String,
    required: true,
  },
  content: {
    type: String,
    required: true,
  },
  author: {
    type: String,
    default: '작성자',
  },
  
}, {
  timestamps: true,
});

module.exports = PostSchema;

3.app.js

const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const mongoose = require('mongoose');
const dayjs = require('dayjs');

const indexRouter = require('./routes');
const postsRouter = require('./routes/posts');

mongoose.connect('mongodb://localhost:27017/simple-board');

mongoose.connection.on('connected', () => {
  console.log('MongoDB Connected');
});

const app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.locals.formatDate = (date) => {
  return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
}

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/posts', postsRouter);

// catch 404 and forward to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// error handler
app.use((err, req, res, next) => {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

4.index.js

const { Router } = require('express');

const router = Router();

router.get('/', (req, res) => {
  res.redirect('/posts')
});

module.exports = router;

5.posts.js

const { Router } = require('express');
const { Post } = require('../models');

const router = Router();

router.get('/', async (req, res, next) => {
  if (req.query.write) {
    res.render('post/edit');
    return;
  }
  
  const posts =await Post.find({})
   // 게시글 목록
  
  res.render('post/list', { posts });
});

router.get('/:shortId', async (req, res, next) => {
  const { shortId } = req.params;
  const post = await Post.findOne({shortId})
  // shortId 로 게시글 찾기
  
  if (req.query.edit) {
    res.render('post/edit', { post });
    return;
  }
  
  res.render('post/view', { post });
});

router.post('/', async (req, res, next) => {
  const { title, content } = req.body;
  
  try {
    if (!title || !content) {
      throw new Error('제목과 내용을 입력해 주세요');
    }
    
    const post = await Post.create({title,content})
    // 게시글 생성
    res.redirect(`/posts/${post.shortId}`);
  } catch (err) {
    next(err);
  }
});

router.post('/:shortId', async (req, res, next) => {
  const { shortId } = req.params;
  const { title, content } = req.body;
  
  try {
    if (!title || !content) {
      throw new Error('제목과 내용을 입력해 주세요');
    }
    await Post.updateOne({shortId},{title,content})
    // shortId 로 게시글 수정
    res.redirect(`/posts/${shortId}`);
  } catch (err) {
    next(err);
  }
});

router.delete('/:shortId', async (req, res, next) => {
  const { shortId } = req.params;
  await Post.deleteOne({shortId})
  // shortId 로 게시글 삭제
  res.send('OK');
});

module.exports = router;

6.list.pug

extends ../layout

block content
  div
    h1 전체 글 목록
  table
    tbody
      each post in posts
        tr
          td: a(href="/posts/"+post.shortId)= post.title
          td= post.author
          td= formatDate(post.createdAt)
  a(href="/posts?write=true"): button 등록하기

7.view.pug

  extends ../layout

block content
  h1= post.title
  table
    tbody
      tr
        th= post.author
        th(colspan="2")= formatDate(post.createdAt)
      tr
        td(colspan="3")
          pre= post.content
      tr
        td: a(href="/posts"): button 목록으로
        td: a(href="?edit=true"): button 수정
        td: button.delete(onclick='deletePost()') 삭제
  script(type="text/javascript").
    function deletePost() {
      fetch('/posts/#{post.shortId}', { method: 'delete' })
        .then((res) => {
          if (res.ok) {
            alert('삭제되었습니다.');
            window.location.href = '/posts';
          } else {
            alert('오류가 발생했습니다.');
          }
        })
        .catch((err) => {
          alert('오류가 발생했습니다.');
        });
    }

8.edit.pug

    extends ../layout

block content
  h1= post ? "글 수정하기": "새 글 등록하기"
  form(action=post ? "/posts/"+post.shortId : "/posts", method="post")
    div
      label 제목
      input(type="text" name="title" value=post&&post.title)
    div
      label 내용
      textarea(name="content")= post&&post.content
    div: input(type="submit" value=post ? "수정":"등록")
profile
코딩으로 빛나게

0개의 댓글