[BE201] 、超簡易留言板(下)


Posted by s103071049 on 2021-08-10

把留言板變得更完整

做任何系統前要先做兩件事情

  1. 系統大概有甚麼功能、路由要怎麼設計,他們會怎麼溝通。以留言板而言,已經有了新增功能,剩下編輯和刪除功能
  2. 規劃資料結構,將 table 開好。以 comments 來說,我們放 username 而不放 nickname,因為使用者改名就要一起調整,很煩。我們可以透過 username 去 users 這個表裡面查詢 nickname。要放一個可以關聯到其他表的外鍵!

實作刪除功能

  1. 加上刪除按鈕 => 調整 index.ejs,確認 comments.js in models 有 id 與 username 可以拿 db.query( SELECT U.nickname, C.content, C.id, C.username,同時保證只有我的留言可以刪除
  2. 調整路由 => index.js 加上 app.get('/delete_comments/:id', commentController.delete)
  3. controllers 裡加上 delete
  4. model 裡面加上 delete
// step1 
// index.ejs in views
<% comments.forEach(function(comment) { %>
  <div>
    <h2><%= comment.nickname %></h2>
    <p><%= comment.content %></p>
    <% if (username === comment.username) {%>
      <a href="delete_comments/<%= comment.id %>">刪除</a>
    <% } %>
  </div>
<% })%>
// step3
// comment.js in comments
  delete: (req, res) => {
    // 將 id、username 傳入 model,不該刪除別人的文章
    commentModel.delete(req.session.username, req.params.id, err => {
      res.redirect('/') // 不管成功或失敗都先導回首頁
    })
  }
// step4
// comments.js in model
  delete: (username, id, cb) => {
    db.query(`DELETE FROM comments WHERE id = ? AND username = ?`,
      [id, username],
      (err, results) => {
        if (err) return cb(err)
        cb(null)
      }
    )
  }

小結

  • 刪除要做權限管理,避免他人文章遭刪

實作編輯功能

  1. 加上編輯按鈕 => index.ejs in views 加上 <a href="update_comments/<%= comment.id %>">編輯</a>
  2. 加上路由 => app.get('/update_comments/:id', commentController.update)app.post('/update_comments/:id', commentController.handleUpdate)
  3. update 要先將原本資料拿出來,才會顯示內容 => comment model 建立 get method
  4. 實作 update 的 controller
  5. 實作 update 的 view
  6. 實作提交功能 => 製作 handelUpdate 的 controller
  7. 實作 comment 這個 method
// step3
// comment.js in models
  get: (id, cb) => { // 若有權限設置只有自己能閱讀自己發布的文章,這邊要傳入 username
    db.query(
      `SELECT U.nickname, C.content, C.id, C.username 
      FROM comments as C
      LEFT JOIN users as U on U.username = C.username
      WHERE C.id = ?
      `, [id],
      (err, results) => {
        if (err) return cb(err)
        cb(null, results[0] || {}) // 一種可能是沒有這個 comment,comment 是 undefined
      }
    )
  }
// step4
  update: (req, res) => {
    commentModel.get(req.params.id, (err, result) => {
      res.render('update', {
        comment: result
      })
    })
  },

只要改變 url 就可以編輯其他人的文章,如果要避免這個問題,controllers 裡面的 update 要做權限管理,不能拿到 id 就顯示出來

// step5
// update.ejs views
<h1>編輯文章</h1>
  <form action="/update_comments/<%= comment.id %>" method="POST">
    <textarea name="content"><%= comment.content %></textarea>
    <input type="submit">
  </form>
// step6
// comment.js in controllers
  handleUpdate: (req, res) => {
    // 做權限管理,不能提交非本人的文章
    commentModel.update(req.session.username, req.params.id, req.body.content, err => {
      res.redirect('/')
    })
  }
// step7
// comment.js in models
  update: (username, id, content, cb) => {
    db.query(
      `update comments set content=? where id=? and username=?`
      , [content, id, username],
      (err, results) => {
        if (err) return cb(err)
        cb(null)
      }
    )
  }

小結

  • 權限管理,提交時沒有做,會編輯到他人的文章

美化頁面

目的:將版面變得美麗,運用 bootstrap

透過 ejs 的 include 可以少寫很多代碼

  1. 新增資料夾 template,裡面放 header.ejs
  2. index.js 抽出 header
  3. index.js 製作 nav bar
  4. 改註冊頁面,用一個 container 將我原本的東西包起來
  5. 改登入頁面
  6. 改主畫面
  7. 改編輯畫面
<!--step1 and stpe2-->
<!--header.ejs-->

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

<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">
<title>留言板</title>
<!--step3-->
<!--navbar.ejs-->

<nav class="navbar navbar-light bg-light">
  <a class="navbar-brand">留言板</a>
    <% if (username) { %>
      <a class="btn btn-outline-success" href="/logout">登出</a>
    <% } else { %>
      <div>
        <a class="btn btn-outline-info" href="/register">註冊</a>
        <a class="btn btn-outline-success" href="/login">登入</a>
      </div>
    <% } %>
</nav>
<!--step4-->
<!--register.ejs -->

<!DOCTYPE html>
<html lang="en">
<head>
  <%- include('../template/header') %>
</head>
<body>
  <%- include('../template/navbar') %>
  <div class="container">
    <h2><%= errorMessage %></h2>
    <form action="/register" method="POST">
      <div class="mb-3 row">
        <label for="inputUsername" class="col-sm-2 col-form-label">username</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="inputUsername" name="username">
        </div>
      </div>
      <div class="mb-3 row">
        <label for="inputNickname" class="col-sm-2 col-form-label">nickname</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="inputNickname" name="nickname">
        </div>
      </div>
      <div class="mb-3 row">
        <label for="inputPassword" class="col-sm-2 col-form-label">password</label>
        <div class="col-sm-10">
          <input type="password" class="form-control" id="inputPassword" name="password">
        </div>
      </div>
      <button type="submit" class="btn btn-primary mb-3">submit</button>
    </form>
  </div>
</body>
</html>

登入頁面錯誤訊息的美化

    <% if (errorMessage && errorMessage.length > 0) {%>
      <div class="alert alert-danger" role="alert">
        <h2><%= errorMessage %></h2>
      </div>
    <% } %>
<!--step6-->
<!DOCTYPE html>
<html lang="en">
<head>
  <%- include('template/header') %>
</head>
<body>
  <%- include('template/navbar') %>
  <div class="container">
    <% if (username) { %>
      <form action="/comments" method="POST">
      <div class="mb-3 row">
        <label>留言內容</label>
        <div class="col-sm-10">
          <textarea name="content" class="form-control"></textarea>
        </div>
      </div>
      <button type="submit" class="btn btn-primary mb-3">送出留言</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_comments/<%= comment.id %>">編輯</a>
          <a class="card-link" href="delete_comments/<%= comment.id %>">刪除</a>
        <% } %>
      </div>
    </div>
    <% })%>
  </div>
</body>
</html>
<!--step7-->
<!DOCTYPE html>
<html lang="en">
<head>
  <%- include('./template/header') %>
</head>
<body>
  <%- include('./template/navbar') %>
  <div class="container">
    <form action="/update_comments/<%= comment.id %>" method="POST">
      <div class="mb-3 row">
        <label>編輯文章</label>
        <div class="col-sm-10">
          <textarea name="content" class="form-control"><%= comment.content%></textarea>
        </div>
      </div>
      <button type="submit" class="btn btn-primary mb-3">submit</button>
    </form>
  </div>
</body>
</html>

補充

  1. include ejs 也可以傳參數,

#Express #EJS #Backend #留言板







Related Posts

JavaScript: Scope & Hoisting

JavaScript: Scope & Hoisting

html 自己看系列

html 自己看系列

CH1. 物件導向軟體開發簡介

CH1. 物件導向軟體開發簡介


Comments