<자기 글 수정, 삭제>
자기 글인 경우에 수정, 삭제 버튼이 활성화되게 하였다.
posts 테이블에 writer라는 속성을 넣어서 글을 쓸 때 username을 넣도록 하였다.
그리고 read에서 iswriter라는 변수를 ejs 파일로 전달하였다.
const iswriter = req.session.user && req.session.user.username === post.writer;
res.render('board/read', { post: post, iswriter: iswriter });
이렇게 전달한 iswriter를 read.ejs 파일에서 받아서 조건문을 설정하였다.
<% if (iswriter) { %>
<form action="/board/edit/<%= post.idx %>" method="get">
<button type="submit">글 수정</button>
</form>
<form action="/board/delete/<%= post.idx %>" method="post">
<button type="submit">글 삭제</button>
</form>
<% } %>
이렇게 iswriter가 참일 때 수정과 삭제 버튼을 만들었다.
edit은 edit 페이지로 이동하도록 하였고, delete는 post로 요청을 보내서 페이지 이동 없이 처리를 하였다.
edit부터 살펴보면,
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시글 수정</title>
</head>
<body>
<h1>게시글 수정</h1>
<form action="/board/update/<%= post.idx %>" method="post">
<label for="title">제목:</label>
<input type="text" id="title" name="title" value="<%= post.title %>" required>
<br>
<label for="content">내용:</label>
<textarea id="content" name="content" rows="10" required><%= post.content %></textarea>
<br>
<button type="submit">수정 완료</button>
</form>
</body>
</html>
이렇게 게시글을 수정할 수 있는 양식을 놓고 update로 post 요청을 보냈다.
router.get('/edit/:id', async (req, res) => {
const postId = req.params.id;
const post = await db.posts.findByPk(postId);
res.render('board/edit', { post });
});
router.post('/update/:id', async (req, res) => {
const postId = req.params.id;
const { title, content} = req.body;
const result = await db.posts.update({ title, content }, { where: { idx: postId } });
res.redirect('/board');
});
edit 링크는 edit.ejs 파일을 렌더링하고, edit.ejs 파일 안에서 update 링크로 post 요청을 보내면, posts.update 함수로
입력받은 title과 content로 업데이트를 하고 board로 redirect 했다.
router.post('/delete/:id', (req, res) => {
const postId = req.params.id;
db.posts.destroy({
where:{idx:postId}
}).then(function(result){
res.redirect('/board');
})
})
delete은 전이랑 크게 달라지지 않았다.
<비밀글>
비밀글 기능을 만들기 위해 posts 테이블에 secret과 password 속성을 추가하였다.
module.exports = function(sequelize, DataTypes){
return sequelize.define('posts', {
idx: {
type : DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true,
allowNull: false
},
title: {
type: DataTypes.STRING(255),
allowNull: false
},
content: {
type: DataTypes.TEXT,
allowNull: false
},
writer: {
type: DataTypes.STRING(255),
allowNull: false
},
secret: {
type: DataTypes.BOOLEAN,
defaultValue: false,
},
password: {
type: DataTypes.STRING,
allowNull: true,
}
});
}
secret은 비밀글인지 나타내는 bool 변수이고,
password는 비밀글이 아닌 경우 null이기 때문에 allowNull을 true로 설정했다.
그리고 write를 할 때 비밀글인지, 비밀번호를 입력하게 하기 위해서 write.ejs 파일을 수정하였다.
<label for="secret">비밀글:</label>
<input type="checkbox" id="secret" name="secret">
<label for="password">비밀번호 (비밀글일 경우):</label>
<input type="password" id="password" name="password">
이렇게 추가하였다.
router.post('/write', async(req, res) => {
const { title, content, secret, password } = req.body;
if(!req.session.user){
res.redirect('/auth/login');
}
const hashedPassword = secret && password ? await bcrypt.hash(password, 10) : null;
db.posts.create({
title: title,
content: content,
writer: req.session.user.username,
secret: secret === 'on',
password: hashedPassword
}).then(function(result){
res.redirect('/board');
})
});
라우터에서는 전에 로그인 비밀번호를 암호화했던 것과 같은 방식으로 비밀번호를 암호화해주고,
create를 할 때 secret과 password 속성을 추가했다.
읽을 때, read 부분이 좀 많이 달라졌는데,
우선 get 방식의 read/id부터 보면, 처음 게시판에서 글을 클릭해서 들어오는 링크인데
router.get('/read/:id', async(req, res) => {
const postId = req.params.id;
const post = await db.posts.findByPk(postId)
const iswriter = req.session.user && req.session.user.username === post.writer;
if (post.secret && (!req.session.user || req.session.user.username !== post.writer || 1 === 1)) {
return res.render('board/secret', { postId: post.idx });
}
res.render('board/read', { post: post, iswriter: iswriter });
});
iswriter로 자기 글인지 판단하고, 비밀글이고, 자기 글이 아니거나 로그인되어 있지 않은 경우 secret 파일로 이동한다.
(1 === 1 은 원래 있으면 안되지만, 기능을 테스트해 볼 때 계정 2개로 왔다갔다 하면서 하기 너무 오래 걸려서 잠시 저렇게 해두었다.)
그리고 만약 자기글이거나 비밀글이 아니면, 바로 read.ejs 파일이 렌더링 되어서 글을 볼 수 있다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/public/main.css" rel="stylesheet" />
</head>
<body>
<h1>비밀글입니다. 비밀번호를 입력하세요.</h1>
<form action="/board/read/<%= postId %>/secret" method="post">
<label for="password">비밀번호:</label>
<input type="password" id="password" name="password">
<button type="submit">확인</button>
</form>
</body>
</html>
secret.ejs 파일이다. 비밀번호를 입력하면, read/id/secret링크로 post 요청을 보낸다.
router.post('/read/:id/secret', async (req, res) => {
const postId = req.params.id;
const { password } = req.body;
const post = await db.posts.findByPk(postId);
if (!post) {
return res.status(404).send('게시글을 찾을 수 없습니다.');
}
if (await bcrypt.compare(password, post.password)) {
const iswriter = req.session.user && req.session.user.username === post.writer;
return res.render('board/read', { post: post, iswriter: iswriter });
} else {
return res.render('board/secret', { postId: post.id, error: '비밀번호가 틀렸습니다.' });
}
});
라우터에서 해당 요청을 보면, id로 테이블에서 게시글 데이터를 가져오고, bcrypt.compare 함수로 비밀번호가 맞는지 확인한다. 비밀번호가 들리면 그대로 다시 secret.ejs 파일을 렌더링하고, 비밀번호가 맞으면 read.ejs를 렌더링한다.
그리고 추가로 board의 main.ejs 파일에서 글 목록을 보여줄 때 비밀글인 경우 미리 표시가 되도록 하기 위해서
<ul>
<% posts.forEach(function(post) { %>
<li><a href="/board/read/<%= post.idx %>"><%= post.title %></a></li>
<% if (post.secret) { %>
<span>(비밀글)</span>
<% } %>
<% }); %>
</ul>
main.ejs 파일을 이렇게 약간 수정하였다.
'웹개발' 카테고리의 다른 글
게시판-추천 (0) | 2023.10.26 |
---|---|
게시판-댓글 (0) | 2023.10.26 |
게시판-이메일 인증, 아이디 찾기 (0) | 2023.10.25 |
게시판-회원가입, 로그인 (0) | 2023.10.24 |
게시판-CRUD (0) | 2023.10.24 |