160 lines
5.1 KiB
Python
160 lines
5.1 KiB
Python
|
|
from flask import Flask, render_template, request, redirect, url_for, flash, session
|
||
|
|
import pymysql
|
||
|
|
from flask import session, g, jsonify
|
||
|
|
import bcrypt
|
||
|
|
from bs4 import BeautifulSoup
|
||
|
|
from werkzeug.utils import secure_filename
|
||
|
|
import os
|
||
|
|
import uuid
|
||
|
|
|
||
|
|
UPLOAD_FOLDER = 'static/upload/img' # 경로를 Flask 앱 루트 기준으로 수정
|
||
|
|
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
|
||
|
|
|
||
|
|
app = Flask(__name__)
|
||
|
|
app.secret_key = 'your secret key'
|
||
|
|
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
||
|
|
|
||
|
|
|
||
|
|
@app.before_request
|
||
|
|
def load_user():
|
||
|
|
if 'user_info' in session:
|
||
|
|
g.is_login = True
|
||
|
|
g.user_info = session['user_info']
|
||
|
|
|
||
|
|
|
||
|
|
def allowed_file(filename):
|
||
|
|
return '.' in filename and \
|
||
|
|
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||
|
|
|
||
|
|
|
||
|
|
@app.route('/upload_image', methods=['POST'])
|
||
|
|
def upload_image():
|
||
|
|
if 'file' not in request.files:
|
||
|
|
return jsonify(success=False, message='No file part'), 400
|
||
|
|
|
||
|
|
file = request.files['file']
|
||
|
|
|
||
|
|
if file.filename == '':
|
||
|
|
return jsonify(success=False, message='No selected file'), 400
|
||
|
|
|
||
|
|
if file and allowed_file(file.filename):
|
||
|
|
# Secure the filename and keep its extension
|
||
|
|
filename = secure_filename(file.filename)
|
||
|
|
ext = filename.rsplit('.', 1)[1].lower()
|
||
|
|
|
||
|
|
# Generate a random filename using uuid4
|
||
|
|
random_filename = f'{uuid.uuid4().hex}.{ext}'
|
||
|
|
|
||
|
|
file_path = os.path.join(app.config['UPLOAD_FOLDER'], random_filename)
|
||
|
|
|
||
|
|
# Create directories if not exist
|
||
|
|
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
||
|
|
|
||
|
|
file.save(file_path)
|
||
|
|
|
||
|
|
# Generate the URL of the saved image file
|
||
|
|
file_url = url_for('static', filename='upload/img/' + random_filename)
|
||
|
|
|
||
|
|
return jsonify(success=True, fileUrl=file_url), 200
|
||
|
|
|
||
|
|
return jsonify(success=False, message='File not allowed'), 400
|
||
|
|
|
||
|
|
|
||
|
|
# MySQL 데이터베이스 연결 설정
|
||
|
|
def connnect_db():
|
||
|
|
return pymysql.connect(
|
||
|
|
host='wxnasso.synology.me',
|
||
|
|
user='wixon5',
|
||
|
|
password='Wixon2022@!',
|
||
|
|
database='wixon',
|
||
|
|
charset="utf8mb4",
|
||
|
|
cursorclass=pymysql.cursors.DictCursor, # DictCursor를 사용하여 딕셔너리 형태로 결과를 반환
|
||
|
|
init_command='SET SQL_SAFE_UPDATES = 0;',
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def sql_execute(q, d, is_data=False, is_last_id=False):
|
||
|
|
data = None
|
||
|
|
last_id = None
|
||
|
|
with connnect_db().cursor(pymysql.cursors.DictCursor) as cursor:
|
||
|
|
try:
|
||
|
|
res = cursor.execute(q, d)
|
||
|
|
data = cursor.fetchall() if is_data else None
|
||
|
|
last_id = cursor.lastrowid if cursor.lastrowid != 0 else None
|
||
|
|
cursor.connection.commit()
|
||
|
|
except Exception as e:
|
||
|
|
print(e)
|
||
|
|
cursor.connection.rollback()
|
||
|
|
res = False
|
||
|
|
|
||
|
|
return (res, last_id if is_last_id else data) if is_data or is_last_id else res
|
||
|
|
|
||
|
|
|
||
|
|
@app.route('/')
|
||
|
|
def index():
|
||
|
|
# MySQL에서 모든 블로그 포스트를 가져옵니다.
|
||
|
|
query = "SELECT `title`, `thumbnail_img`, `contents` FROM `blog` WHERE `use_yn` = 'Y' ORDER BY `add_date` DESC;"
|
||
|
|
r, posts = sql_execute(query, (), is_data=True)
|
||
|
|
|
||
|
|
# `index.html` 템플릿으로 데이터를 전달합니다.
|
||
|
|
return render_template('index.html', posts=posts)
|
||
|
|
|
||
|
|
|
||
|
|
@app.route('/login', methods=['GET', 'POST'])
|
||
|
|
def login():
|
||
|
|
if request.method == 'POST':
|
||
|
|
username = request.form.get('username')
|
||
|
|
password = request.form.get('password').encode('utf-8')
|
||
|
|
|
||
|
|
# DB에서 사용자 정보 가져오기
|
||
|
|
res, user = sql_execute("SELECT * FROM member WHERE mb_id=%s", (username,), is_data=True)
|
||
|
|
if res and user and bcrypt.checkpw(password, user[0]['mb_passwd'].encode('utf-8')):
|
||
|
|
session['username'] = username
|
||
|
|
session['user_info'] = user[0]
|
||
|
|
return redirect(url_for('index'))
|
||
|
|
else:
|
||
|
|
flash('Username or password is incorrect')
|
||
|
|
return render_template('login.html')
|
||
|
|
|
||
|
|
|
||
|
|
@app.route('/logout')
|
||
|
|
def logout():
|
||
|
|
session.clear()
|
||
|
|
g.is_login = False
|
||
|
|
g.user_info = None
|
||
|
|
|
||
|
|
return redirect(url_for('index'))
|
||
|
|
|
||
|
|
|
||
|
|
@app.route('/write', methods=['GET', 'POST'])
|
||
|
|
def write():
|
||
|
|
if request.method == 'POST':
|
||
|
|
title = request.form['title']
|
||
|
|
category = request.form['category']
|
||
|
|
contents = request.form['contents']
|
||
|
|
|
||
|
|
# 본문에서 첫 번째 이미지 추출
|
||
|
|
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)
|
||
|
|
|
||
|
|
# 새로운 글 저장
|
||
|
|
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')
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
app.run(host='0.0.0.0', port=8899)
|