[BE201] Express & Sequelize part 5


Posted by yymarlerr on 2021-08-24

實作簡易留言板

index.js

主要新增內容

app.get('/', commentController.index)

  • 要先取得留言內容,再 render 首頁,

app.post('/comment', commentController.add)

  • 加一個新增留言的路由

程式碼

const express = require('express')
const bodyParser = require('body-parser')
const session = require('express-session')
const flash = require('connect-flash')
const db = require('./db')
const app = express()
const port = 5001

const todoController = require('./controllers/todo'
)
const userController = require('./controllers/user')
const commentController = require('./controllers/comment')

app.set('view engine', 'ejs')

app.use(bodyParser.urlencoded({ extended: false })) 
app.use(bodyParser.json()) 
app.use(flash())

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
}))

app.use((req, res, next) => {
  res.locals.username = req.session.username
  res.locals.errorMessage = req.flash('errorMessage')
  next()
})

function redirectBack(req, res) { // 自己寫的 Middleware
  res.redirect('back')
}

app.post('/todos', todoController.newTodo)
app.get('/todos', todoController.getAll) 
app.get('/todos/:id', todoController.get)
app.get('/', commentController.index)

app.get('/login', (req, res) => {
  res.render('login')
})

app.get('/login', userController.login)
app.post('/login', userController.handleLogin, redirectBack)
app.get('/logout', userController.logout)
app.get('/register', userController.register)
app.post('/register', userController.handleRegister, redirectBack)

app.post('/comment', commentController.add)


app.post('/login', (req, res) => {
  if (req.body.password === "abc") {
    req.session.isLogin = true 
    res.redirect('/') 
  } else {
    req.flash('errorMessage', 'Please input the correct password')
    res.redirect('/login')
  }
})

app.get('/logout', (req, res) => {
  req.session.isLogin = false
  res.redirect('/')
})

app.listen(port, () => {
  db.connect()
  console.log(`hello world, listening on port ${port}`)
})

controller

comment.js 程式碼

const commentModel = require('../models/comment')

const commentController = {
  add: (req, res) => {
    const {username} = req.session
    const {content} = req.body
    if (!username || !content) {
      return res.redirect('/')
    }
    commentModel.add(username, content, (err) => {
      return res.redirect('/')
    })
  },

  index: (req, res) => {
    commentModel.getAll((err, results) => {
      if (err) {
        console.log(err)
      }
      res.render('user/index', { // 送一個參數到 index.ejs,這樣它就可以拿到所有評論
        comments: results
      })
    })
  }

}

module.exports = commentController

models

comment.js 的程式碼

const db = require('../db')

const commentModel = {
  add: (username, content, cb) => { // 傳進 user 這個 Object
    db.query(
      'INSERT INTO yide_comments (username, content) VALUES (?, ?)', 
      [username, content],
      (error, results) => { 
        if (error) return cb(error);
        cb(null)
    });
  },

  getAll: (cb) => {
    db.query(
      `SELECT U.nickname, C.content 
      FROM yide_comments as C 
      LEFT JOIN yide_users as U on U.username = C.username
      ORDER BY C.id DESC`, 
      (error, results) => { 
        if (error) return cb(error);
        cb(null, results)
    });
  }
}

module.exports = commentModel

view

index.ejs 程式碼

<h1>簡易會員系統</h1>

<!--先判斷是否有登入-->
<% if (username) { %>
  Hello, <%= username %>
  <a href='/logout'>登出</a>

  <form method="POST" action="/comment" >
    <textarea name="content"></textarea>
    <input type="submit" />
  </form>
<% } else { %>
  <a href='/register'>註冊</a>
  <a href='/login'>登入</a>
<% } %>

<% comments.forEach(function(comment) { %>
  <div>
    <h2><%= comment.nickname  %></h2>
    <p><%=  comment.content %></p>
  </div>

<% }) %>

實作刪除、編輯功能

index.js

新增程式碼

pp.get('/delete_comment/:id', commentController.delete) // 冒號 id 代表它是一個動態參數
app.get('/update_comment/:id', commentController.update)
app.post('/update_comment/:id', commentController.handleUpdate)

controller

comment.js 程式碼

const commentModel = require('../models/comment')

const commentController = {
  add: (req, res) => {
    const {username} = req.session
    const {content} = req.body
    if (!username || !content) {
      return res.redirect('/')
    }
    commentModel.add(username, content, (err) => {
      return res.redirect('/')
    })
  },

  index: (req, res) => {
    commentModel.getAll((err, results) => {
      if (err) {
        console.log(err)
      }
      res.render('user/index', { // 送一個參數到 index.ejs,這樣它就可以拿到所有評論
        comments: results
      })
    })
  },

  delete: (req, res) => {
    commentModel.delete(req.session.username, req.params.id, (err) => { // 權限檢查、把 id 傳下去
      res.redirect('/')
    })
  },

  update: (req, res) => {
    commentModel.get(req.params.id, (err, results) => {
      res.render('update', {
        comment: results
      })
    })
  },

  handleUpdate: (req, res) => {
    commentModel.update(req.session.username, req.params.id, req.body.content, (err) => {
      res.redirect('/')
    }) // 做權限管理
  }

}

module.exports = commentController

models

comment.js

const db = require('../db')

const commentModel = {
  add: (username, content, cb) => { // 傳進 user 這個 Object
    db.query(
      'INSERT INTO yide_comments (username, content) VALUES (?, ?)', 
      [username, content],
      (error, results) => { 
        if (error) return cb(error);
        cb(null)
    });
  },

  getAll: (cb) => {
    db.query(
      `SELECT U.nickname, C.content, C.id, C.username 
      FROM yide_comments as C 
      LEFT JOIN yide_users as U on U.username = C.username
      ORDER BY C.id DESC`, 
      (error, results) => { 
        if (error) return cb(error);
        cb(null, results)
    });
  },

  delete: (username, id, cb) => {
    db.query(
      `DELETE FROM yide_comments WHERE id = ? AND username = ?`, 
      [id, username],
      (error, results) => { 
        if (error) return cb(error);
        cb(null, results)
    });
  },

  get: (id, cb) => {
    db.query(
      `SELECT U.nickname, C.content, C.id, C.username 
      FROM yide_comments as C 
      LEFT JOIN yide_users as U on U.username = C.username
      WHERE C.id = ?`, 
      [id], 
      (error, results) => { 
        if (error) return cb(error);
        cb(null, results[0] || {}) // 傳一個空的 object 進去,這樣如果沒有 results 就不會壞掉
    });
  },

  update: (username, id, content, cb) => {
    db.query(
      `UPDATE yide_comments SET content = ? WHERE username = ? AND id = ?`, // 檢查 username 作權限管理
      [content, username, id],
      (error, results) => { 
        if (error) return cb(error);
        cb(null, results)
    });
  },
}

module.exports = commentModel

view

index.ejs

<h1>簡易會員系統</h1>

<!--先判斷是否有登入-->
<% if (username) { %>
  Hello, <%= username %>
  <a href='/logout'>登出</a>

  <form method="POST" action="/comment" >
    <textarea name="content"></textarea>
    <input type="submit" />
  </form>
<% } else { %>
  <a href='/register'>註冊</a>
  <a href='/login'>登入</a>
<% } %>

<% comments.forEach(function(comment) { %>
  <div>
    <h2><%= comment.nickname  %></h2>
    <p><%=  comment.content %></p>
    <% if (username === comment.username) { %>
      <a href="/update_comment/<%= comment.id %>">編輯</a>
      <a href="/delete_comment/<%= comment.id %>">刪除</a>
    <% } %>
  </div>

<% }) %>

update.ejs

<h1>編輯文章</h1>

<form method="POST" action="/update_comment/<%= comment.id %>" >
  <textarea name="content"><%= comment.content %></textarea>
  <input type="submit" />
</form>

美化頁面

在 view 裡面新增 template 這個資料夾,裡面可以放 navbar、header、footer⋯⋯等的模板,再利用 <%- include(<路徑>) %> 的方式引入進來

範例:index.ejs 的程式碼

<!doctype html>
<head>
  <%- include('../template/head') %>
</head>
<html>

  <%- include('../template/navbar') %>

  <div class="container">
    <% if (username) { %>
      <form method="POST" action="/comment" >
        <div class="form-group">
          <label>留言內容</label>
          <textarea name="content" class="form-control" ></textarea>
        </div>
        <button type="submit" class="btn btn-primary">送出留言</button>
      </form>
    <% } %>

    <% comments.forEach(function(comment) { %>
      <div class="card" style="width: 18rem; margin-top: 10px;">
        <div class="card-body">
          <h5 class="card-title"><%= comment.nickname  %></h5>
          <p class="card-text"><%=  comment.content %></p>
          <% if (username === comment.username) { %>
            <a class="card-link" href="/update_comment/<%= comment.id %>">編輯</a>
            <a class="card-link" href="/delete_comment/<%= comment.id %>">刪除</a>
          <% } %>
        </div>
      </div>
    <% }) %>
  </div>
</html>

範例:head.ejs 的程式碼

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" 
rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" 
crossorigin="anonymous">









Related Posts

Git 筆記 - 將本地專案推送至別的儲存庫同步

Git 筆記 - 將本地專案推送至別的儲存庫同步

關於 Slot 元件插槽

關於 Slot 元件插槽

給自己看的 JS 進階-物件導向

給自己看的 JS 進階-物件導向


Comments