1. 회원가입 기능
조건문을 이용해서 적절한 조건을 만들고, 적용하기
id는 1~8글자 영어 + 숫자조합
ps는 특수문자 무조건 포함하도록 조건을 설정함
만약 조건에 맞지않게 회원가입을 시도할경우, 경고문을 보여주도록 동적으로 html을 생성
bcrypt 를 이용해서 비밀번호는 암호화 해서 db에 저장함
<% if (error) { %>
<div class="error-message"><%= error %></div>
<% } %>
// 정규식과 길이 제한 설정
const MIN_LENGTH = 1;
const MAX_LENGTH = 8;
const idRegex = /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]+$/; // 문자와 숫자 조합
const passwordRegex = /^(?=.*[!@#$%^&*])/; // 특수 기호 포함
const { username, password } = req.body;
// 모든 조건 검사
if (username.length < MIN_LENGTH || username.length > MAX_LENGTH || !idRegex.test(username)) {
res.render('signup.ejs', { error: '아이디는 1~8글자의 문자와 숫자 조합이어야 합니다.' });
} else if (password.length < MIN_LENGTH || password.length > MAX_LENGTH || !passwordRegex.test(password)) {
res.render('signup.ejs', { error: '비밀번호는 1~8글자이며, 특수 기호를 포함해야 합니다.' });
} else {
const hashPassword = await bcrypt.hash(password, 10);
await db.collection('user').insertOne({ username, password: hashPassword });
res.redirect('/main/0');
}
회원가입 기능
2. 로그인 기능
input 필드에 입력된 id와 비밀번호를 db에 저장된 내용과 비교해서 검증
만약 정확한 id ps 로 로그인 했다면 req.session.userId = hashPassword._id; 를 변수로 지정해서
session에 user 컬렉션의 document 의 _id를 저장해줌(회원권 지급)
const inputPassword = req.body.password
const hashPassword = await db.collection('user')
.findOne({username : req.body.username})
bcrypt.compare(inputPassword, hashPassword.password , (err, isMatch)=>{
if(err){
console.log('로그인 과정중 에러발생')
}else {
if (isMatch){
console.log('비번 일치함')
req.session.userId = hashPassword._id;
res.redirect('/main/0')
} else {
console.log('비번 불일치함')
}
}
} )
로그인 기능
3. 글쓰기 기능
if 문을 통해 로그인 한 경우에만 글쓰기를 허용
if(req.body.userId){
const result = await db.collection('post').insertOne({
userId : req.session.userId,
title: req.body.title,
content: req.body.content
});
res.redirect('/main/1');
}
글쓰기 기능
4. 글 수정 삭제 기능
detail.ejs 페이지에서 현재 로그인한 사용자가 글 작성자일 경우만 수정, 삭제 버튼을 생성해주도록 코드 작성
<% if (result.userId === sessionUserId) { %>
<a href='/edit/<%= result._id%>' class="edit-button">수정하기</a>
<a href='/delete/<%= result._id%>' class="delete-button">삭제하기</a>
<% } %>
const post = await db.collection('post').findOne({ _id : new ObjectId(req.params.id)});
const postUserId = new ObjectId(post.userId);
if(postUserId.equals(new ObjectId(req.session.userId))){
const result = await db.collection('post').updateOne(
{ _id: new ObjectId(req.params.id)},
{$set : { title : req.body.title, content : req.body.content}}
);
const post = await db.collection('post').findOne({ _id : new ObjectId(req.params.id)});
const postUserId = new ObjectId(post.userId);
if(postUserId.equals(new ObjectId(req.session.userId))){
const result = db.collection('post').deleteOne({ _id : new ObjectId(req.params.id) })
res.redirect('/main/0');
글 수정, 삭제 기능
5. 페이지 네이션 기능
한 페이지당 최대 게시글 갯수를 8개로 구성
페이지당 총 게시글 갯수를 넘어가면, 동적으로 페이지 네이션을 추가로 main.ejs 에서 생성
URL 파라미터 문법을 이용해서 동적으로 같은 기능을 수행하는 여러개의 api를 생성
skip()과 limit()을 적절하게 활용해서 main.ejs에서 게시글을 만들어주는 코드를 동적으로 작성
<%- include('nav') %>
<div class="posts-container">
<% for( let i = 0; i < result.length ; i ++) { %>
<div class="post-card">
<h3 class="post-title"><a href='/detail/<%= result[i]._id %>'><%= result[i].title %></a></h3>
<p class="post-content"><%= result[i].content %></p>
</div>
<% } %>
</div>
<div class="pagination">
<% for(let i = 1; i <= totalPages; i++) { %>
<a href="/main/<%= i %>" class="<%= i === pageId ? 'active' : '' %>"><%= i %></a>
<% } %>
</div>
const pageSize = 8;
const totalCount = await db.collection('post').countDocuments();
const totalPages = Math.ceil(totalCount / pageSize);
const pageId = parseInt(req.params.id) || 1;
const skip = (pageId - 1) * pageSize;
const result = await db.collection('post')
.find()
.skip(skip)
.limit(pageSize)
.toArray();
res.render('main.ejs', {
result: result,
pageId: pageId,
totalPages: totalPages
});
페이지 네이션 기능
6. 작성한 글목록 기능
프로필 탭에서 nav바를 생성해주고
작성한 글목록 탭을 클릭하면
현재 req.session.userId 가 작성한 게시물을 찾아와서
한번에 볼 수 있음
const pageSize = 8;
const totalCount = await db.collection('post').countDocuments();
const totalPages = Math.ceil(totalCount / pageSize);
const pageId = parseInt(req.params.id) || 1;
const skip = (pageId - 1) * pageSize;
const result = await db.collection('post')
.find({userId : req.session.userId})
.skip(skip)
.limit(pageSize)
.toArray();
res.render('writeList.ejs', {
result: result,
pageId: pageId,
totalPages: totalPages
})
작성한 글목록 보여주기 기능
7. 회원 정보 변경 기능
회원 정보 필드를 만들어두고
각각 독립적으로 업데이트 되도록 코드를 구성
원치않은 동작을 막기위해서 req.session.userId 가 존재할때만 코드를 실행
if(req.session.userId){
const updateData = {
};
if(req.body.username) updateData.username = req.body.username;
if(req.body.password) updateData.password = await bcrypt.hash(req.body.password, 10);
if(req.body.address) updateData.address = req.body.address;
if(req.body.phonNum) updateData.phonNum = req.body.phonNum;
await db.collection('user').updateOne(
{ _id : new ObjectId(req.session.userId)},
{ $set : updateData}
);
res.redirect('/profile');
};
회원정보 변경 기능
9. 로그아웃 기능
비 로그인 상태일 경우 nav 탭이 로그인
로그인 상태일 경우 nav 탭이 로그아웃
nav 탭을 동적으로 구성
로그아웃 버튼을 눌러주면 session.destroy()를 이용해서 세션을 파괴해줌
if(req.session.userId){
req.session.destroy((err) =>{
if(err) {
console.error('세션 파괴 오류', err);
return res.status(500).send('로그아웃중 오류 발생')
}
res.redirect('/moveLogin');
})
로그아웃 기능