728x90
const express = require('express');
const app = express();
const port = 3030;
const nodemailer = require('nodemailer');
const mysql = require('mysql');
const session = require('express-session');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const crypto = require('crypto');
const moment = require('moment-timezone');
const winston = require('winston');
const bodyParser = require('body-parser');
const SitemapGenerator = require('sitemap-generator');
const multer = require('multer');
require('dotenv').config();
const bcrypt = require('bcrypt');
const path = require('path');
const fs = require('fs');
const http = require('http');
const socketIo = require('socket.io');
// MySQL 연결 설정
const mysqldb = mysql.createConnection({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
charset: 'utf8'
});
mysqldb.connect((err) => {
if (err) {
console.error('MySQL 연결 오류:', err);
throw err;
}
console.log('MySQL 연결 성공');
});
// 로그 설정
const logOptions = {
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(({ timestamp, level, message }) => {
return `${timestamp} [${level}] ${message}`;
})
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: 'app.log' })
]
};
const logger = winston.createLogger(logOptions);
console.log = (...args) => {
logger.info(args.join(' '));
};
// Express 설정
app.use(session({
secret: crypto.randomBytes(32).toString('hex'),
resave: false,
saveUninitialized: false,
}));
app.use(passport.initialize());
app.use(passport.session());
const server = http.createServer(app);
const io = socketIo(server);
const wss = new WebSocket.Server({ server });
app.set('view engine', 'ejs');
app.use('/public', express.static('public/css'));
app.use('/yu', express.static('views/public/css'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use((req, res, next) => {
const clientIp = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
const logMessage = `사용자가 웹 사이트에 접속함 - IP 주소: ${clientIp}`;
logger.info(logMessage);
createAndStoreLog(logMessage, clientIp);
next();
});
function createAndStoreLog(message, clientIPAddress) {
const currentTime = moment().tz('Asia/Seoul').format('YYYY-MM-DD HH:mm:ss');
const logEntry = { timestamp: currentTime, message: message, ip_address: clientIPAddress };
mysqldb.query('INSERT INTO logs SET ?', logEntry, (err, results) => {
if (err) {
console.error('로그 저장 중 오류 발생:', err);
} else {
console.log('로그가 성공적으로 저장되었습니다.');
}
});
}
const generator = SitemapGenerator('https://fg-uonqq.run.goorm.site', {
stripQuerystring: false, // 쿼리 문자열을 포함할지 여부
});
generator.on('done', () => {
console.log('사이트 맵 생성이 완료되었습니다.');
});
const generateSitemapInterval = 24 * 60 * 60 * 1000; // 24시간(하루)마다
const generateSitemap = () => {
generator.start();
};
setInterval(generateSitemap, generateSitemapInterval);
app.get('/sitemap.xml', (req, res) => {
res.sendFile(__dirname + '/sitemap.xml');
});
app.get('/', (req, res) => {
if (req.session.user) {
if (req.session.role === 'admin') {
res.render('index_a.ejs');
console.log('관리자 계정으로 로그인 후 홈');
} else {
res.render('index_u.ejs');
console.log('일반 사용자 계정으로 홈에 접속');
}
} else {
res.render('index.ejs');
console.log('로그인 안한 상태로 접속');
}
});
app.get('/server/error', (req, res) => {
res.render('server_error.ejs');
});
app.get('/shop', (req, res) => {
const products = [
{ name: '상품1', price: 10000 },
{ name: '상품2', price: 20000 },
{ name: '상품3', price: 30000 }
];
res.render('shop', { products });
});
// 회원가입 페이지 렌더링
app.get('/join/membership', (req, res) => {
res.sendFile(__dirname + '/public/html/u.html');
});
app.get('/r', (req, res) => {
res.sendFile(__dirname + '/public/html/r.txt');
});
// 회원가입 POST 요청 처리
app.post('/join/membership', (req, res) => {
// POST 요청으로부터 입력 데이터 추출
const { email, phoneNumber, address, name, id, password } = req.body;
// 빈 칸 검사
if (!email || !phoneNumber || !address || !name || !id || !password) {
return res.status(400).send('필수 입력 정보를 모두 제공해야 합니다.');
}
// 중복 정보 검사 (예: ID가 중복되지 않는지 확인)
mysqldb.query('SELECT * FROM users WHERE id = ?', [id], (err, results) => {
if (err) {
console.error('중복 정보 검사 중 오류 발생:', err);
return res.status(500).send('중복 정보 검사 중 오류 발생');
}
if (results.length > 0) {
return res.status(400).send('이미 사용 중인 ID입니다.');
}
// 암호 해시 생성
bcrypt.hash(password, 10, (err, hash) => {
if (err) {
console.error('암호 해시 생성 중 오류 발생:', err);
return res.status(500).send('암호 해시 생성 중 오류 발생');
}
// 새 사용자 생성 및 데이터베이스에 저장
const newUser = {
email,
phoneNumber,
address,
name,
id,
password: hash,
role: 'user',
};
mysqldb.query('INSERT INTO users SET ?', newUser, (err) => {
if (err) {
console.error('회원가입 중 오류 발생:', err);
return res.status(500).send('회원가입 중 오류 발생');
}
// 가입 완료 페이지로 이동
res.redirect('/Membership/registration/completed');
});
});
});
});
app.get('/Membership/registration/completed', (req, res) => {
res.send('회원가입이 완료되었습니다.');
});
// getLogsFromDatabase 함수 수정
function getLogsFromDatabase(db, callback) {
db.query('SELECT * FROM logs', (err, results) => {
if (err) {
callback(err, null);
} else {
callback(null, results);
}
});
}
// '/logs' 경로에 대한 라우트 핸들러
app.get('/logs', (req, res) => {
if (req.session.user && req.session.role === 'admin') {
// 'admin' 권한이 있는 사용자만 액세스 가능
// 여기에서 데이터베이스에서 로그 목록을 가져오는 코드를 추가
mysqldb.query('SELECT * FROM logs', (err, results) => {
if (err) {
console.error('로그 목록을 가져오는 중 오류:', err);
res.status(500).send('로그 목록을 가져오는 중 오류 발생');
} else {
const logs = results; // 로그 데이터를 변수에 저장
// 로그 데이터를 'logs.ejs' 페이지에 전달
res.render('logs.ejs', { logs });
}
});
} else {
// 'admin' 권한이 아닌 경우 접근 불가능
res.status(403).send('접근이 거부되었습니다.');
}
});
app.get('/googleb1672fc63397d758', (req, res) => {
res.sendFile(__dirname + "/public/html/googleb1672fc63397d758.html");
});
app.get('/robots.txt', (req, res) => {
res.sendFile(__dirname + "/robots.txt");
});
// 로그인 페이지 렌더링
app.get('/login', (req, res) => {
res.render('login.ejs');
});
app.post('/login', (req, res) => {
const { id, password } = req.body;
// 데이터베이스에서 사용자 확인
mysqldb.query('SELECT * FROM users WHERE id = ?', [id], (err, results) => {
if (err) {
console.error('로그인 중 오류 발생:', err);
return res.status(500).send('로그인 중 오류 발생');
}
if (results.length === 1) {
const user = results[0];
// 비밀번호 비교
bcrypt.compare(password, user.password, (bcryptErr, result) => {
if (bcryptErr) {
console.error('비밀번호 확인 중 오류 발생:', bcryptErr);
return res.status(500).send('비밀번호 확인 중 오류 발생');
}
if (result) {
// 비밀번호가 일치하는 경우, 로그인 성공
// 사용자 이름 가져오기
const sqlGetName = 'SELECT name FROM users WHERE id = ?';
mysqldb.query(sqlGetName, [id], (nameErr, nameResults) => {
if (nameErr) {
console.error('사용자 이름 가져오기 오류:', nameErr);
return res.status(500).send('사용자 이름 가져오기 오류');
}
if (nameResults.length === 1) {
const userName = nameResults[0].name;
if (user.role === 'admin') {
// 관리자 계정으로 로그인 성공
req.session.user = user; // 세션에 사용자 정보 저장
req.session.role = 'admin'; // 세션에 권한 저장
req.session.userName = userName; // 사용자 이름을 세션에 저장
console.log('관리자 계정 로그인 성공: ' + user.id);
res.redirect('/');
} else if (user.role === 'user') {
// 일반 사용자 계정으로 로그인 성공
req.session.user = user; // 세션에 사용자 정보 저장
req.session.role = 'user'; // 세션에 권한 저장
req.session.userName = userName; // 사용자 이름을 세션에 저장
console.log('일반 사용자 계정 로그인 성공: ' + user.id);
res.redirect('/');
} else {
// 권한이 없는 경우
console.log('로그인 실패: 권한이 없는 사용자입니다.');
res.render('login.ejs', { error: '권한이 없는 사용자입니다.' });
}
} else {
// 사용자 이름을 찾을 수 없음
console.log('사용자 이름을 찾을 수 없습니다.');
res.status(500).send('사용자 이름을 찾을 수 없습니다.');
}
});
} else {
// 비밀번호가 일치하지 않는 경우, 로그인 실패
console.log('로그인 실패: 비밀번호가 일치하지 않습니다.');
res.render('login.ejs', { error: '비밀번호가 일치하지 않습니다.' });
}
});
} else {
// 아이디가 존재하지 않음
console.log('로그인 실패: 아이디가 존재하지 않습니다.');
res.render('login.ejs', { error: '아이디가 존재하지 않습니다.' });
}
});
});
app.get('/m', (req, res) => {
// 권한 확인: 사용자의 권한이 'admin'인 경우에만 액세스 허용
if (req.session.user && req.session.role === 'admin') {
const sql = 'SELECT id, email, phoneNumber, address, name, role FROM users';
mysqldb.query(sql, (err, results) => {
if (err) {
console.error('회원 정보 가져오기 오류:', err);
return res.status(500).send('오류 발생');
}
// EJS 템플릿 렌더링하여 회원 정보 및 권한 정보 표시
res.render('members.ejs', { members: results });
});
} else {
// 'admin' 권한이 아닌 경우 접근 거부
res.status(403).send('액세스가 거부되었습니다.');
}
});
app.delete('/deleteMember/:id', (req, res) => {
const memberId = parseInt(req.params.id);
// 여기에서 데이터베이스 쿼리를 사용하여 사용자를 삭제하도록 수정해야 합니다.
const sql = 'DELETE FROM users WHERE id = ?';
mysqldb.query(sql, [memberId], (err, results) => {
if (err) {
console.error('사용자 삭제 오류:', err);
return res.json({ success: false });
}
return res.json({ success: true });
});
});
app.get('/admin-dashboard', (req, res) => {
if (req.session.user && req.session.role === 'admin') {
// 'admin' 권한이 있는 사용자만 액세스 가능
res.render('admin-dashboard.ejs', { userName: req.session.userName });
} else {
// 권한이 없는 경우 또는 로그인하지 않은 경우
res.redirect('/login');
}
});
app.get('/dashboard', (req, res) => {
if (req.session.user && req.session.role === 'user') {
// 'user' 권한이 있는 사용자만 액세스 가능
console.log(req.session.userName)
res.render('dashboard.ejs', { userName: req.session.userName });
} else {
// 권한이 없는 경우 또는 로그인하지 않은 경우
res.redirect('/login');
}
});
app.use('/favicon.ico', express.static('public/favicon.ico'));
app.get('/detail/:id', (req, res) => {
const postId = req.params.id;
const currentUser = req.session.user; // 현재 로그인한 사용자 정보
// 글 조회 쿼리를 수행 (post 테이블에서 가져오도록 수정)
mysqldb.query('SELECT * FROM post WHERE id = ?', [postId], (err, results) => {
if (err) {
console.error('데이터베이스에서 글 조회 중 오류:', err);
return res.status(500).send('오류가 발생했습니다.');
}
if (results.length === 0) {
return res.status(404).send('해당 글을 찾을 수 없습니다.');
}
// 글을 조회한 결과를 가져오고 현재 사용자와 글 작성자를 비교
const post = results[0];
// 사용자 역할을 확인하여 관리자인 경우 항상 삭제할 수 있도록 설정
// 또는 글 작성자와 현재 사용자가 동일한 경우에만 삭제할 수 있도록 설정
let canDelete = false;
if (currentUser) {
// 현재 사용자가 로그인한 경우에만
if (currentUser.id === post.user_id || currentUser.role === 'admin') {
canDelete = true;
}
}
// 파일 URL을 파일 이름을 사용하여 생성
const filePath = `/f/${post.file_path}`;
// 파일 유형에 따라 이미지와 비디오를 구별
const isImage = filePath.match(/\.(jpg|jpeg|png|gif)$/i);
const isVideo = filePath.match(/\.(mp4|avi|mkv)$/i);
res.render('detail.ejs', { post, canDelete, filePath, isImage, isVideo });
});
});
app.post('/delete/:id', (req, res) => {
const postId = req.params.id;
if (req.session.user) {
// 글 삭제 권한 확인: 관리자 또는 글 작성자만 삭제할 수 있음
if (req.session.user.role === 'admin') {
// 관리자 권한을 가진 사용자는 언제나 글을 삭제할 수 있음
mysqldb.query('DELETE FROM post WHERE id = ?', [postId], (err) => {
if (err) {
console.error('글 삭제 중 오류:', err);
return res.status(500).send('글 삭제 중 오류 발생');
}
console.log(`글(ID: ${postId})이 삭제되었습니다.`);
res.redirect('/');
});
} else {
// 글 작성자 확인: 로그인한 사용자와 글 작성자가 동일한지 확인
mysqldb.query('SELECT user_id FROM post WHERE id = ?', [postId], (userErr, userResults) => {
if (userErr) {
console.error('글 작성자 확인 중 오류 발생:', userErr);
return res.status(500).send('글 작성자 확인 중 오류 발생');
}
if (userResults && userResults.length > 0) {
const postUserId = userResults[0].user_id;
if (postUserId === req.session.user.id) {
// 글 작성자와 로그인한 사용자가 동일한 경우 글을 삭제할 수 있음
mysqldb.query('DELETE FROM post WHERE id = ?', [postId], (deleteErr) => {
if (deleteErr) {
console.error('글 삭제 중 오류:', deleteErr);
return res.status(500).send('글 삭제 중 오류 발생');
}
console.log(`글(ID: ${postId})이 삭제되었습니다.`);
res.redirect('/');
});
} else {
// 글 작성자와 로그인한 사용자가 동일하지 않은 경우 접근 거부
console.log('글 삭제 권한 없음: 글 작성자와 로그인한 사용자가 다름');
res.status(403).send('글 삭제 권한이 없습니다.');
}
} else {
// 글 작성자를 찾을 수 없음
console.error('글 작성자를 찾을 수 없음.');
res.status(500).send('글 작성자를 찾을 수 없음');
}
});
}
} else {
// 로그인하지 않은 경우 글 삭제 권한이 없음
console.log('글 삭제 권한 없음: 로그인하지 않음');
res.status(403).send('글 삭제 권한이 없습니다.');
}
});
// 게시글 작성 페이지 렌더링
app.get('/write', (req, res) => {
res.render('write.ejs');
});
app.get('/1', (req, res) => {
res.render('1.ejs');
});
app.get('/yt', (req, res) => {
res.render('yt.ejs');
});
// 로그아웃
app.get('/logout', (req, res) => {
req.session.destroy((err) => {
if (err) {
console.error('로그아웃 중 오류 발생:', err);
return res.status(500).send('로그아웃 중 오류 발생');
}
res.redirect('/');
});
});
app.get('/list', (req, res) => {
// 데이터베이스에서 "post" 테이블의 글 목록을 가져오는 쿼리
mysqldb.query('SELECT id, title, content FROM post', (err, results) => {
if (err) {
console.error('데이터베이스에서 글 목록을 가져오는 중 오류 발생:', err);
return res.status(500).send('서버 오류');
}
// 글 목록을 EJS 템플릿으로 렌더링하여 클라이언트에 전달
res.render('list.ejs', { 글목록: results });
});
});
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/'); // 파일 저장 경로 (uploads 디렉토리에 저장)
},
filename: (req, file, cb) => {
const extname = path.extname(file.originalname);
cb(null, Date.now() + extname); // 파일 이름을 고유하게 설정
},
});
const upload = multer({ storage });
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
app.post('/write', upload.single('file'), (req, res) => {
// 로그인하지 않은 경우 글 작성 권한이 없음
if (!req.session.user) {
console.log('글 작성 권한 없음: 로그인하지 않음');
return res.status(403).send('글 작성 권한이 없습니다.');
}
// POST 요청으로부터 입력 데이터 추출
const { title, content } = req.body;
const user_id = req.session.user.id;
// 빈 칸 검사
if (!title || !content) {
console.log('필수 정보를 모두 입력해야 함');
return res.status(400).send('필수 정보를 모두 입력해야 합니다.');
}
// 파일을 서버에 저장하고 제목과 내용을 데이터베이스에 저장
savePostToDatabase(req, title, content, user_id, req.file)
.then((result) => {
console.log('새로운 글(ID: ' + result.insertId + ')이 작성되었습니다.');
res.redirect('/');
})
.catch((err) => {
console.error('글 작성 중 오류 발생:', err);
return res.status(500).send('글 작성 중 오류 발생');
});
});
// 데이터베이스에 제목, 내용 및 파일 저장하는 함수
function savePostToDatabase(req, title, content, user_id, file) {
return new Promise((resolve, reject) => {
const query = 'INSERT INTO post (title, content, user_id, file_path) VALUES (?, ?, ?, ?)';
const filePath = file ? 'uploads/' + file.filename : null;
mysqldb.query(query, [title, content, user_id, filePath], (err, result) => {
if (err) {
reject(err);
} else {
resolve(result); // 새로 생성된 게시물 정보 반환
}
});
});
}
app.get('/f/uploads/:filename', (req, res) => {
const fileName = req.params.filename;
const filePath = path.join(__dirname, 'uploads', fileName);
// 파일 확장자에 따라 Content-Type 설정
if (fileName.endsWith('.jpg') || fileName.endsWith('.jpeg')) {
res.setHeader('Content-Type', 'image/jpeg');
} else if (fileName.endsWith('.png')) {
res.setHeader('Content-Type', 'image/png');
} else if (fileName.endsWith('.gif')) {
res.setHeader('Content-Type', 'image/gif');
} else if (fileName.endsWith('.mp4')) {
res.setHeader('Content-Type', 'video/mp4');
} else if (fileName.endsWith('.avi')) {
res.setHeader('Content-Type', 'video/x-msvideo');
} else if (fileName.endsWith('.mkv')) {
res.setHeader('Content-Type', 'video/x-matroska');
} else {
return res.status(403).send('이미지 또는 동영상 파일이 아닙니다.');
}
// 파일을 클라이언트로 전송
fs.createReadStream(filePath).pipe(res);
});
// Express 서버 실행
app.listen(port, () => {
console.log(`서버가 http://localhost:${port} 에서 실행 중입니다.`);
});
// 이메일 전송 설정
const transporter = nodemailer.createTransport({
service: 'Gmail', // 사용하는 이메일 제공자
auth: {
user: 'woldeog12@gmail.com', // 여기에 자신의 이메일 주소
pass: '비공계', // 여기에 자신의 이메일 비밀번호
},
});
// 이메일 전송 라우트
app.post('/sendEmail', (req, res) => {
const { to, subject, text } = req.body;
// 이메일 옵션 설정
const mailOptions = {
from: 'woldeog12@gmail.com', // 보내는 이메일 주소
to: to, // 받는 이메일 주소
subject: subject, // 이메일 제목
text: text, // 이메일 내용
};
// 이메일 전송
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log('이메일 전송 실패:', error);
res.status(500).json({ success: false, message: '이메일 전송 실패' });
} else {
console.log('이메일 전송 성공:', info.response);
res.status(200).json({ success: true, message: '이메일 전송 성공' });
}
});
});
wss.on('connection', (ws) => {
console.log('클라이언트가 연결했습니다.');
// 클라이언트로부터 메시지 수신
ws.on('message', (message) => {
console.log(`받은 메시지: ${message}`);
// 모든 클라이언트에게 메시지 전송
wss.clients.forEach((client) => {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
});
});
app.get('/2', (req, res) => {
res.render('2.ejs');
});
회원가입 구현 내용수정 이메일인증 코드 추가 아래 html 파일 첨부 해드릴게용!
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>회원가입</title>
<link href="/public/u.css" rel="stylesheet">
</head>
<body>
<h1>회원가입</h1>
<form action="/join/membership" method="POST" id="signupForm">
<label for="email">이메일:</label>
<input type="email" name="email" required id="emailInput"><br>
<!-- 이메일 인증 버튼 -->
<button type="button" id="sendEmailButton">이메일 인증 요청</button><br>
<label for="phoneNumber">전화번호:</label>
<input type="tel" name="phoneNumber" required><br>
<label for="address">주소:</label>
<input type="text" name="address" required><br>
<label for="name">이름:</label>
<input type="text" name="name" required><br>
<label for="id">ID:</label>
<input type="text" name="id" required><br>
<label for="password">비밀번호:</label>
<input type="password" name="password" required><br>
<label for="verificationCode">인증번호:</label>
<input type="text" name="verificationCode" id="verificationCodeInput" required><br>
<span id="randomNumber"></span><br> <!-- 랜덤 숫자를 표시할 곳 -->
<input type="button" value="인증번호 확인" id="verifyCodeButton"><br>
<input type="submit" value="회원가입" id="signupButton" disabled>
</form>
<script>
const sendEmailButton = document.getElementById('sendEmailButton');
const emailInput = document.getElementById('emailInput');
const randomNumberElement = document.getElementById('randomNumber');
const verificationCodeInput = document.getElementById('verificationCodeInput');
const verifyCodeButton = document.getElementById('verifyCodeButton');
const signupButton = document.getElementById('signupButton');
let generatedVerificationCode = null;
sendEmailButton.addEventListener('click', () => {
const email = emailInput.value;
if (email) {
// 랜덤 6자리 숫자 생성
generatedVerificationCode = generateRandomSixDigitNumber();
// 이메일 내용 생성
const emailContent = `seulnetlki 사이트 회원가입을 완료하려면 아래의 인증 코드를 입력하세요: ${generatedVerificationCode} seulnetlki 사이트 가입 해주셔서 감사합니다!`;
// 이메일 주소와 내용을 백엔드로 전송하여 이메일을 전송
fetch('/sendEmail', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ to: email, subject: '이메일 인증 요청', text: emailContent }),
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('이메일을 전송했습니다. 이메일을 확인하세요.');
} else {
alert('이메일 전송에 실패했습니다.');
}
})
.catch(error => {
console.error('이메일 전송 요청 실패:', error);
alert('이메일 전송 요청에 실패했습니다.');
});
}
});
verifyCodeButton.addEventListener('click', () => {
const enteredCode = verificationCodeInput.value;
if (enteredCode === generatedVerificationCode) {
alert('인증번호가 일치합니다. 회원가입이 가능합니다.');
signupButton.removeAttribute('disabled');
} else {
alert('인증번호가 일치하지 않습니다.');
}
});
// 랜덤한 6자리 숫자 생성 함수
function generateRandomSixDigitNumber() {
const min = 000000;
const max = 999999;
return String(Math.floor(Math.random() * (max - min + 1)) + min);
}
</script>
</body>
</html>
이렇식으로 해서 인즈오드 발송 인증코드확인등 코드이다
728x90
반응형
'node.js웹사이트 만들기' 카테고리의 다른 글
node.js 만든 사이트 가비아 호스팅 (0) | 2024.05.21 |
---|---|
웹개발 (0) | 2023.10.23 |
node.js 사이트 만들기 (1) | 2023.10.11 |