블로그 기능 구현

> 글쓰기, 수정, 삭제 구현
> 목록 페이지 벽돌 레이아웃 구성
> 로그인 기능 추가
> 컨텐츠 공개/숨김 기능 추가
This commit is contained in:
javamon117
2023-08-03 21:09:18 +09:00
parent 590beba676
commit 19359fa961
6 changed files with 340 additions and 50 deletions

115
app.py
View File

@@ -6,6 +6,8 @@ from bs4 import BeautifulSoup
from werkzeug.utils import secure_filename
import os
import uuid
from markupsafe import Markup
from jinja2 import filters
UPLOAD_FOLDER = 'static/upload/img' # 경로를 Flask 앱 루트 기준으로 수정
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
@@ -66,7 +68,7 @@ def connnect_db():
host='wxnasso.synology.me',
user='wixon5',
password='Wixon2022@!',
database='wixon',
database='test',
charset="utf8mb4",
cursorclass=pymysql.cursors.DictCursor, # DictCursor를 사용하여 딕셔너리 형태로 결과를 반환
init_command='SET SQL_SAFE_UPDATES = 0;',
@@ -92,8 +94,13 @@ def sql_execute(q, d, is_data=False, is_last_id=False):
@app.route('/')
def index():
# MySQL에서 모든 블로그 포스트를 가져옵니다.
query = "SELECT `title`, `thumbnail_img`, `contents` FROM `blog` WHERE `use_yn` = 'Y' ORDER BY `add_date` DESC;"
if 'user_info' in session: # 로그인된 사용자가 있을 경우
# 외부 공개 안된 글도 포함하여 모든 블로그 포스트를 가져옵니다.
query = "SELECT `id`, `title`, `thumbnail_img`, `contents` FROM `blog` WHERE `use_yn` = 'Y' ORDER BY `add_date` DESC;"
else: # 로그인된 사용자가 없을 경우
# 외부 공개된 블로그 포스트만 가져옵니다.
query = "SELECT `id`, `title`, `thumbnail_img`, `contents` FROM `blog` WHERE `use_yn` = 'Y' and `public_yn` = 'Y' ORDER BY `add_date` DESC;"
r, posts = sql_execute(query, (), is_data=True)
# `index.html` 템플릿으로 데이터를 전달합니다.
@@ -126,34 +133,122 @@ def logout():
return redirect(url_for('index'))
@app.route('/post/<int:post_id>')
def post(post_id):
# SQL 쿼리와 삽입할 데이터 설정
query = "SELECT blog.*, member.mb_name, member.mb_id FROM blog INNER JOIN member ON blog.user_id = member.mb_idx WHERE blog.id = %s"
data = (post_id,)
# Post를 데이터베이스에서 검색
result, fetched_data = sql_execute(query, data, is_data=True)
if result:
# 검색 성공시, 포스트 상세 페이지로 이동
post = fetched_data[0]
# 이전과 다음 포스트를 찾기
if 'user_info' in session: # 로그인된 사용자가 있을 경우
# 외부 공개 안된 글도 포함하여 모든 블로그 포스트를 가져옵니다.
prev_query = "SELECT blog.*, member.mb_name, member.mb_id FROM blog INNER JOIN member ON blog.user_id = member.mb_idx WHERE blog.add_date < %s AND blog.use_yn = 'Y' ORDER BY blog.add_date DESC LIMIT 1"
next_query = "SELECT blog.*, member.mb_name, member.mb_id FROM blog INNER JOIN member ON blog.user_id = member.mb_idx WHERE blog.add_date > %s AND blog.use_yn = 'Y' ORDER BY blog.add_date ASC LIMIT 1"
else: # 로그인된 사용자가 없을 경우
# 외부 공개된 블로그 포스트만 가져옵니다.
prev_query = "SELECT blog.*, member.mb_name, member.mb_id FROM blog INNER JOIN member ON blog.user_id = member.mb_idx WHERE blog.add_date < %s AND blog.public_yn = 'Y' AND blog.use_yn = 'Y' ORDER BY blog.add_date DESC LIMIT 1"
next_query = "SELECT blog.*, member.mb_name, member.mb_id FROM blog INNER JOIN member ON blog.user_id = member.mb_idx WHERE blog.add_date > %s AND blog.public_yn = 'Y' AND blog.use_yn = 'Y' ORDER BY blog.add_date ASC LIMIT 1"
prev_post = None
next_post = None
prev_result, prev_fetched_data = sql_execute(prev_query, (post['add_date'],), is_data=True)
next_result, next_fetched_data = sql_execute(next_query, (post['add_date'],), is_data=True)
if prev_result and prev_fetched_data:
prev_post = prev_fetched_data[0]
if next_result and next_fetched_data:
next_post = next_fetched_data[0]
return render_template('post.html', post=post, prev_post=prev_post, next_post=next_post)
else:
# 검색 실패시, 에러 메시지 반환
return "Failed to fetch the post", 500
@app.route('/edit_post/<int:post_id>', methods=['GET', 'POST'])
def edit_post(post_id):
if 'username' not in session or ('username' in session and session['username'] not in ['admin', 'wixon']):
flash('You are not allowed to edit this post.')
return redirect(url_for('index'))
if request.method == 'POST':
# 포스트 업데이트 로직
title = request.form.get('title')
category = request.form.get('category')
public_yn = 'Y' if request.form.get('public') == 'on' else 'N'
contents = request.form.get('contents')
query = "UPDATE blog SET title = %s, category = %s, public_yn = %s, contents = %s WHERE id = %s"
data = (title, category, public_yn, contents, post_id)
res = sql_execute(query, data)
if res:
flash('Post updated successfully.')
return redirect(url_for('post', post_id=post_id))
else:
flash('Failed to update the post.')
return redirect(url_for('edit_post', post_id=post_id))
else:
# 포스트 가져오기 로직
query = "SELECT * FROM blog WHERE id = %s"
data = (post_id,)
res, fetched_data = sql_execute(query, data, is_data=True)
if res and fetched_data:
return render_template('edit_post.html', post=fetched_data[0])
else:
flash('Failed to fetch the post.')
return redirect(url_for('index'))
@app.route('/write', methods=['GET', 'POST'])
def write():
if 'user_info' not in session:
flash("You need to login first.")
return redirect(url_for('login'))
if request.method == 'POST':
user_id = session['user_info']['mb_idx']
title = request.form['title']
category = request.form['category']
contents = request.form['contents']
is_public = 'Y' if request.form.get('public') == 'on' else 'N'
# 본문에서 첫 번째 이미지 추출
soup = BeautifulSoup(contents, 'html.parser')
first_image = soup.find('img')
thumbnail_img = first_image['src'] if first_image else None
# SQL 쿼리와 삽입할 데이터 설정
query = "INSERT INTO blog (title, category, contents, thumbnail_img, use_yn) VALUES (%s, %s, %s, %s, 'Y')"
data = (title, category, contents, thumbnail_img)
query = "INSERT INTO blog (user_id, title, category, contents, thumbnail_img, public_yn) VALUES (%s, %s, %s, %s, %s, %s)"
data = (user_id, title, category, contents, thumbnail_img, is_public)
# 새로운 글 저장
result, last_id = sql_execute(query, data, is_last_id=True)
if result:
# 저장 성공시, 인덱스 페이지로 리다이렉트
return redirect(url_for('index'))
else:
# 저장 실패시, 에러 메시지 반환
return "Failed to write post", 500
else:
return render_template('write.html')
@app.route('/blog/<int:id>', methods=['DELETE'])
def delete_post(id):
query = "UPDATE `blog` SET `use_yn` = 'N' WHERE `id` = %s;"
res = sql_execute(query, (id,))
if res:
return jsonify(success=True, message='Post deleted successfully'), 200
else:
return jsonify(success=False, message='Could not delete the post'), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8899)