把留言板變得更完整
做任何系統前要先做兩件事情
- 系統大概有甚麼功能、路由要怎麼設計,他們會怎麼溝通。以留言板而言,已經有了新增功能,剩下編輯和刪除功能
- 規劃資料結構,將 table 開好。以 comments 來說,我們放 username 而不放 nickname,因為使用者改名就要一起調整,很煩。我們可以透過 username 去 users 這個表裡面查詢 nickname。要放一個可以關聯到其他表的外鍵!
實作刪除功能
- 加上刪除按鈕 => 調整 index.ejs,確認 comments.js in models 有 id 與 username 可以拿
db.query( SELECT U.nickname, C.content, C.id, C.username
,同時保證只有我的留言可以刪除 - 調整路由 => index.js 加上
app.get('/delete_comments/:id', commentController.delete)
- controllers 裡加上 delete
- 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)
}
)
}
小結
- 刪除要做權限管理,避免他人文章遭刪
實作編輯功能
- 加上編輯按鈕 => index.ejs in views 加上
<a href="update_comments/<%= comment.id %>">編輯</a>
- 加上路由 =>
app.get('/update_comments/:id', commentController.update)
、app.post('/update_comments/:id', commentController.handleUpdate)
- update 要先將原本資料拿出來,才會顯示內容 => comment model 建立 get method
- 實作 update 的 controller
- 實作 update 的 view
- 實作提交功能 => 製作 handelUpdate 的 controller
- 實作 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 可以少寫很多代碼
- 新增資料夾 template,裡面放 header.ejs
- index.js 抽出 header
- index.js 製作 nav bar
- 改註冊頁面,用一個 container 將我原本的東西包起來
- 改登入頁面
- 改主畫面
- 改編輯畫面
<!--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>
補充
- include ejs 也可以傳參數,