0% found this document useful (0 votes)
16 views17 pages

Student Court Website App Code

The document is a Flask application for a Student Court website, featuring user authentication, case and rule management, and file uploads. It includes models for AdminUser, Case, Rule, and Member, along with routes for public and admin functionalities. The application allows for the creation, editing, and viewing of cases and rules, as well as the management of associated files and user roles.

Uploaded by

csiashlee1205
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views17 pages

Student Court Website App Code

The document is a Flask application for a Student Court website, featuring user authentication, case and rule management, and file uploads. It includes models for AdminUser, Case, Rule, and Member, along with routes for public and admin functionalities. The application allows for the creation, editing, and viewing of cases and rules, as well as the management of associated files and user roles.

Uploaded by

csiashlee1205
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

# app.

py - Student Court Website


from flask import Flask, render_template, request, redirect, url_for, flash,
send_from_directory
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, logout_user,
login_required, current_user
from [Link] import generate_password_hash, check_password_hash
from [Link] import secure_filename
from docx import Document
import os
import re
from datetime import datetime
from config import Config

app = Flask(__name__)
[Link].from_object(Config)

instance_path = [Link]([Link]([Link](__file__)),
'instance')
[Link](instance_path, exist_ok=True)

upload_base = [Link]['UPLOAD_FOLDER']
[Link]([Link](upload_base, 'cases'), exist_ok=True)
[Link]([Link](upload_base, 'rules'), exist_ok=True)
[Link]([Link](upload_base, 'members'), exist_ok=True)
[Link]([Link](upload_base, 'pdfs'), exist_ok=True)
[Link]([Link](upload_base, 'temp'), exist_ok=True)

db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = 'admin_login'

# Models
class AdminUser(UserMixin, [Link]):
__tablename__ = 'admin_users'
id = [Link]([Link], primary_key=True)
username = [Link]([Link](80), unique=True, nullable=False)
password_hash = [Link]([Link](200), nullable=False)
role = [Link]([Link](50), default='admin')
created_at = [Link]([Link], default=[Link])
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)

class Case([Link]):
__tablename__ = 'cases'
id = [Link]([Link], primary_key=True)
slug = [Link]([Link](200), unique=True, nullable=False)
title = [Link]([Link](200), nullable=False)
case_number = [Link]([Link](50))
category = [Link]([Link](100), nullable=False)
status = [Link]([Link](50), nullable=False, default='진행중')
date = [Link]([Link](50), nullable=False)
summary = [Link]([Link])
content_html = [Link]([Link])
verdict = [Link]([Link])
cover_image = [Link]([Link](200))
pdf_file = [Link]([Link](200))
word_file = [Link]([Link](200)) # 원본 Word 파일 저장
is_public = [Link]([Link], default=True)
is_pinned = [Link]([Link], default=False)
created_at = [Link]([Link], default=[Link])
updated_at = [Link]([Link], default=[Link],
onupdate=[Link])
files = [Link]('CaseFile', backref='case', lazy=True, cascade='all,
delete-orphan')

class CaseFile([Link]):
__tablename__ = 'case_files'
id = [Link]([Link], primary_key=True)
case_id = [Link]([Link], [Link]('[Link]'), nullable=False)
name = [Link]([Link](200), nullable=False)
file_path = [Link]([Link](300), nullable=False)
file_type = [Link]([Link](50), nullable=False)

class Rule([Link]):
__tablename__ = 'rules'
id = [Link]([Link], primary_key=True)
slug = [Link]([Link](200), unique=True, nullable=False)
title = [Link]([Link](200), nullable=False)
category = [Link]([Link](100), nullable=False)
status = [Link]([Link](50), nullable=False, default='시행중')
date = [Link]([Link](50), nullable=False)
summary = [Link]([Link])
content_html = [Link]([Link])
cover_image = [Link]([Link](200))
pdf_file = [Link]([Link](200))
word_file = [Link]([Link](200)) # 원본 Word 파일 저장
is_pinned = [Link]([Link], default=False)
created_at = [Link]([Link], default=[Link])
updated_at = [Link]([Link], default=[Link],
onupdate=[Link])
files = [Link]('RuleFile', backref='rule', lazy=True, cascade='all,
delete-orphan')

class RuleFile([Link]):
__tablename__ = 'rule_files'
id = [Link]([Link], primary_key=True)
rule_id = [Link]([Link], [Link]('[Link]'), nullable=False)
name = [Link]([Link](200), nullable=False)
file_path = [Link]([Link](300), nullable=False)
file_type = [Link]([Link](50), nullable=False)

class Member([Link]):
__tablename__ = 'members'
id = [Link]([Link], primary_key=True)
name = [Link]([Link](100), nullable=False)
role = [Link]([Link](50), nullable=False)
description = [Link]([Link])
photo = [Link]([Link](255))
order = [Link]([Link], default=0)
is_active = [Link]([Link], default=True)
created_at = [Link]([Link], default=[Link])

# Helper Functions
@login_manager.user_loader
def load_user(user_id):
return [Link](int(user_id))

def allowed_file(filename):
if not filename:
return False
return '.' in filename and [Link]('.', 1)[1].lower() in
[Link]['ALLOWED_EXTENSIONS']

def create_slug(title):
from [Link] import quote
import uuid
slug = [Link]()
slug = [Link](r'[^\w\s-]', '', slug)
slug = [Link](r'[\s_]+', '-', slug)
slug = [Link]('-')
if not slug:
slug = str(uuid.uuid4())[:8]
slug = quote(slug, safe='-')
return slug

def extract_word_content(docx_path, slug, upload_subfolder='rules'):


"""Extract content from Word document"""
doc = Document(docx_path)
html_parts = []
image_counter = 0
upload_dir = [Link]([Link]['UPLOAD_FOLDER'], upload_subfolder)
[Link](upload_dir, exist_ok=True)

image_rels = {}
for rel in [Link]():
if "image" in rel.target_ref:
image_counter += 1
img_ext = rel.target_ref.split('.')[-1].lower()
if img_ext not in ['png', 'jpg', 'jpeg', 'gif', 'webp']:
img_ext = 'png'
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
img_filename = f"{slug}_img_{timestamp}_{image_counter}.{img_ext}"
img_path = [Link](upload_dir, img_filename)
try:
with open(img_path, 'wb') as f:
[Link](rel.target_part.blob)
img_url = f"/uploads/{upload_subfolder}/{img_filename}"
image_rels[[Link]] = img_url
except:
continue

for element in [Link]:


if [Link]('p'):
para = next((p for p in [Link] if p._element == element), None)
if para:
for run in [Link]:
for drawing in
run._element.findall('.//{[Link]
main}drawing'):
for blip in
[Link]('.//{[Link]
embed_id =
[Link]('{[Link]
d')
if embed_id and embed_id in image_rels:
html_parts.append(f'<p class="image-container"><img
src="{image_rels[embed_id]}" class="content-image"></p>')
text = [Link]()
if text:
style_name = [Link]() if [Link] else ''
if 'heading 1' in style_name or 'title' in style_name:
html_parts.append(f'<h1>{text}</h1>')
elif 'heading 2' in style_name:
html_parts.append(f'<h2>{text}</h2>')
elif 'heading 3' in style_name:
html_parts.append(f'<h3>{text}</h3>')
else:
html_parts.append(f'<p>{text}</p>')
elif [Link]('tbl'):
html_parts.append('<table class="word-table"><tbody>')
table = next((t for t in [Link] if t._element == element), None)
if table:
for row in [Link]:
html_parts.append('<tr>')
for cell in [Link]:
html_parts.append(f'<td>{[Link]}</td>')
html_parts.append('</tr>')
html_parts.append('</tbody></table>')

return '\n'.join(html_parts)

# Public Routes
@[Link]('/')
def home():
recent_cases =
[Link].filter_by(is_public=True).order_by(Case.created_at.desc()).limit(3).all(
)
recent_rules = [Link].order_by(Rule.created_at.desc()).limit(3).all()
pinned_rules =
[Link].filter_by(is_pinned=True).order_by(Rule.created_at.desc()).limit(2).all(
)
pinned_cases = [Link].filter_by(is_public=True,
is_pinned=True).order_by(Case.created_at.desc()).limit(3).all()
return render_template('[Link]', recent_cases=recent_cases,
recent_rules=recent_rules, pinned_rules=pinned_rules, pinned_cases=pinned_cases)

@[Link]('/cases')
def cases():
all_cases =
[Link].filter_by(is_public=True).order_by(Case.is_pinned.desc(),
Case.created_at.desc()).all()
categories = list(set([[Link] for c in all_cases if [Link]]))
[Link]()
return render_template('[Link]', cases=all_cases, categories=categories)

@[Link]('/cases/<slug>')
def case_detail(slug):
case = [Link].filter_by(slug=slug, is_public=True).first_or_404()
return render_template('case_detail.html', case=case)

@[Link]('/rules')
def rules():
all_rules = [Link].order_by(Rule.is_pinned.desc(),
Rule.created_at.desc()).all()
pinned_rules =
[Link].filter_by(is_pinned=True).order_by(Rule.created_at.desc()).all()
categories = list(set([[Link] for r in all_rules if [Link]]))
[Link]()
return render_template('[Link]', rules=all_rules,
pinned_rules=pinned_rules, categories=categories)

@[Link]('/rules/<slug>')
def rule_detail(slug):
rule = [Link].filter_by(slug=slug).first_or_404()
return render_template('rule_detail.html', rule=rule)

@[Link]('/about')
def about():
members = [Link].filter_by(is_active=True).order_by([Link],
[Link]).all()
return render_template('[Link]', members=members)

@[Link]('/contact')
def contact():
return render_template('[Link]')

@[Link]('/uploads/<path:filename>')
def serve_upload(filename):
return send_from_directory([Link]['UPLOAD_FOLDER'], filename)

# Admin Routes
@[Link]('/admin')
def admin_redirect():
return redirect(url_for('admin_login'))

@[Link]('/admin/login', methods=['GET', 'POST'])


def admin_login():
if current_user.is_authenticated:
return redirect(url_for('admin_dashboard'))
if [Link] == 'POST':
username = [Link]('username')
password = [Link]('password')
user = [Link].filter_by(username=username).first()
if user and user.check_password(password):
login_user(user)
flash('로그인되었습니다!', 'success')
return redirect(url_for('admin_dashboard'))
else:
flash('아이디 또는 비밀번호가 올바르지 않습니다', 'error')
return render_template('admin/[Link]')

@[Link]('/admin/logout')
@login_required
def admin_logout():
logout_user()
flash('로그아웃되었습니다', 'success')
return redirect(url_for('home'))

@[Link]('/admin/dashboard')
@login_required
def admin_dashboard():
cases = [Link].order_by(Case.created_at.desc()).all()
rules = [Link].order_by(Rule.created_at.desc()).all()
members = [Link].filter_by(is_active=True).order_by([Link],
[Link]).all()
return render_template('admin/[Link]', cases=cases, rules=rules,
members=members)

# Case Admin
@[Link]('/admin/cases/new', methods=['GET', 'POST'])
@login_required
def admin_new_case():
if [Link] == 'POST':
try:
title = [Link]('title')
category = [Link]('category')
status = [Link]('status', '진행중')
case_number = [Link]('case_number')
date = [Link]('date')
summary = [Link]('summary')
verdict = [Link]('verdict')
slug = create_slug(title)
is_public = 'is_public' in [Link]
is_pinned = 'is_pinned' in [Link]

base_slug = slug
counter = 1
while [Link].filter_by(slug=slug).first():
slug = f"{base_slug}-{counter}"
counter += 1

cover_image = None
if 'cover_image' in [Link]:
file = [Link]['cover_image']
if file and [Link] and allowed_file([Link]):
filename = secure_filename([Link])
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
filename = f"{slug}_cover_{timestamp}_{filename}"
filepath = [Link]([Link]['UPLOAD_FOLDER'], 'cases',
filename)
[Link](filepath)
cover_image = f'cases/{filename}'

content_html = ''
pdf_file = None
word_file = None
word_uploaded = False

if 'word_file' in [Link]:
doc_file = [Link]['word_file']
if doc_file and doc_file.filename:
file_ext = [Link](doc_file.filename)[1].lower()
timestamp = [Link]().strftime('%Y%m%d%H%M%S')

if file_ext == '.pdf':
pdf_filename =
secure_filename(f"{slug}_pdf_{timestamp}.pdf")
pdf_path = [Link]([Link]['UPLOAD_FOLDER'],
'pdfs', pdf_filename)
doc_file.save(pdf_path)
pdf_file = f'pdfs/{pdf_filename}'
elif file_ext in ['.docx', '.doc']:
# Word 파일 저장
word_filename = secure_filename(f"{slug}_word_{timestamp}
{file_ext}")
word_path = [Link]([Link]['UPLOAD_FOLDER'],
'cases', word_filename)
doc_file.save(word_path)
word_file = f'cases/{word_filename}'
# Word 내용 변환
content_html = extract_word_content(word_path, slug,
'cases')
word_uploaded = True

if not content_html and not pdf_file:


editor_content = [Link]('content')
if editor_content:
content_html = editor_content

case = Case(slug=slug, title=title, case_number=case_number,


category=category,
status=status, date=date, summary=summary,
content_html=content_html,
verdict=verdict, cover_image=cover_image, pdf_file=pdf_file,
word_file=word_file, is_public=is_public,
is_pinned=is_pinned)
[Link](case)
[Link]()

if 'additional_files' in [Link]:
files = [Link]('additional_files')
for file in files:
if file and [Link] and allowed_file([Link]):
filename = secure_filename([Link])
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
filename = f"{slug}_{timestamp}_{filename}"
filepath = [Link]([Link]['UPLOAD_FOLDER'],
'cases', filename)
[Link](filepath)
f_ext = [Link]('.', 1)[1].lower()
case_file = CaseFile(case_id=[Link], name=[Link],
file_path=f'cases/{filename}', file_type=f_ext)
[Link](case_file)

[Link]()

# Word 파일 업로드 시 자동으로 수정 페이지로 이동 (에디터에서 확인/수정 가능)


if word_uploaded:
flash('Word 문서가 변환되었습니다. 내용을 확인하세요.', 'success')
return redirect(url_for('admin_edit_case', id=[Link]))

flash('재판 기록이 등록되었습니다!', 'success')


return redirect(url_for('admin_dashboard'))
except Exception as e:
[Link]()
flash(f'오류가 발생했습니다: {str(e)}', 'error')
return redirect(url_for('admin_new_case'))

return render_template('admin/case_form.html', case=None)


@[Link]('/admin/cases/<int:id>/edit', methods=['GET', 'POST'])
@login_required
def admin_edit_case(id):
case = [Link].get_or_404(id)

if [Link] == 'POST':
try:
[Link] = [Link]('title')
[Link] = [Link]('category')
[Link] = [Link]('status', '진행중')
case.case_number = [Link]('case_number')
[Link] = [Link]('date')
[Link] = [Link]('summary')
[Link] = [Link]('verdict')
case.is_public = 'is_public' in [Link]
case.is_pinned = 'is_pinned' in [Link]

new_slug = create_slug([Link])
if new_slug != [Link]:
base_slug = new_slug
counter = 1
while [Link]([Link] == new_slug, [Link] !=
[Link]).first():
new_slug = f"{base_slug}-{counter}"
counter += 1
[Link] = new_slug

if [Link]('remove_cover_image') == 'true' and


case.cover_image:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
case.cover_image)
if [Link](old_path):
[Link](old_path)
case.cover_image = None

if 'cover_image' in [Link]:
file = [Link]['cover_image']
if file and [Link] and allowed_file([Link]):
if case.cover_image:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
case.cover_image)
if [Link](old_path):
[Link](old_path)
filename = secure_filename([Link])
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
filename = f"{[Link]}_cover_{timestamp}_{filename}"
filepath = [Link]([Link]['UPLOAD_FOLDER'], 'cases',
filename)
[Link](filepath)
case.cover_image = f'cases/{filename}'

# PDF/Word 삭제
if [Link]('remove_doc') == 'true':
if case.pdf_file:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
case.pdf_file)
if [Link](old_path):
[Link](old_path)
case.pdf_file = None
if case.word_file:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
case.word_file)
if [Link](old_path):
[Link](old_path)
case.word_file = None

word_uploaded = False
if 'word_file' in [Link]:
doc_file = [Link]['word_file']
if doc_file and doc_file.filename:
file_ext = [Link](doc_file.filename)[1].lower()
timestamp = [Link]().strftime('%Y%m%d%H%M%S')

# 기존 파일 삭제
if case.pdf_file:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
case.pdf_file)
if [Link](old_path):
[Link](old_path)
case.pdf_file = None
if case.word_file:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
case.word_file)
if [Link](old_path):
[Link](old_path)
case.word_file = None

if file_ext == '.pdf':
pdf_filename =
secure_filename(f"{[Link]}_pdf_{timestamp}.pdf")
pdf_path = [Link]([Link]['UPLOAD_FOLDER'],
'pdfs', pdf_filename)
doc_file.save(pdf_path)
case.pdf_file = f'pdfs/{pdf_filename}'
elif file_ext in ['.docx', '.doc']:
word_filename =
secure_filename(f"{[Link]}_word_{timestamp}{file_ext}")
word_path = [Link]([Link]['UPLOAD_FOLDER'],
'cases', word_filename)
doc_file.save(word_path)
case.word_file = f'cases/{word_filename}'
content_html = extract_word_content(word_path, [Link],
'cases')
if content_html:
case.content_html = content_html
word_uploaded = True

if not word_uploaded:
content = [Link]('content')
if content:
case.content_html = content

if [Link]('remove_files'):
file_ids = [Link]('remove_files').split(',')
for file_id in file_ids:
if file_id:
cfile = [Link](int(file_id))
if cfile and cfile.case_id == [Link]:
file_path = [Link]([Link]['UPLOAD_FOLDER'],
cfile.file_path)
if [Link](file_path):
[Link](file_path)
[Link](cfile)

if 'additional_files' in [Link]:
files = [Link]('additional_files')
for file in files:
if file and [Link] and allowed_file([Link]):
filename = secure_filename([Link])
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
filename = f"{[Link]}_{timestamp}_{filename}"
filepath = [Link]([Link]['UPLOAD_FOLDER'],
'cases', filename)
[Link](filepath)
f_ext = [Link]('.', 1)[1].lower()
case_file = CaseFile(case_id=[Link], name=[Link],
file_path=f'cases/{filename}', file_type=f_ext)
[Link](case_file)

case.updated_at = [Link]()
[Link]()

if word_uploaded:
flash('Word 문서가 변환되었습니다. 내용을 확인하세요.', 'success')
return redirect(url_for('admin_edit_case', id=id))

flash('재판 기록이 수정되었습니다!', 'success')


return redirect(url_for('admin_dashboard'))
except Exception as e:
[Link]()
flash(f'오류가 발생했습니다: {str(e)}', 'error')

return render_template('admin/case_form.html', case=case)

@[Link]('/admin/cases/<int:id>/delete', methods=['POST'])
@login_required
def admin_delete_case(id):
try:
case = [Link].get_or_404(id)
if case.pdf_file:
pdf_path = [Link]([Link]['UPLOAD_FOLDER'], case.pdf_file)
if [Link](pdf_path):
[Link](pdf_path)
if case.word_file:
word_path = [Link]([Link]['UPLOAD_FOLDER'], case.word_file)
if [Link](word_path):
[Link](word_path)
if case.cover_image:
cover_path = [Link]([Link]['UPLOAD_FOLDER'],
case.cover_image)
if [Link](cover_path):
[Link](cover_path)
[Link](case)
[Link]()
flash('재판 기록이 삭제되었습니다!', 'success')
except Exception as e:
[Link]()
flash(f'오류가 발생했습니다: {str(e)}', 'error')
return redirect(url_for('admin_dashboard'))

# Rule Admin
@[Link]('/admin/rules/new', methods=['GET', 'POST'])
@login_required
def admin_new_rule():
if [Link] == 'POST':
try:
title = [Link]('title')
category = [Link]('category')
status = [Link]('status', '시행중')
date = [Link]('date')
summary = [Link]('summary', '')
is_pinned = 'is_pinned' in [Link]
slug = create_slug(title)

base_slug = slug
counter = 1
while [Link].filter_by(slug=slug).first():
slug = f"{base_slug}-{counter}"
counter += 1

cover_image = None
if 'cover_image' in [Link]:
file = [Link]['cover_image']
if file and [Link] and allowed_file([Link]):
filename = secure_filename([Link])
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
filename = f"{slug}_cover_{timestamp}_{filename}"
filepath = [Link]([Link]['UPLOAD_FOLDER'], 'rules',
filename)
[Link](filepath)
cover_image = f'rules/{filename}'

content_html = ''
pdf_file = None
word_file = None
word_uploaded = False

if 'word_file' in [Link]:
doc_file = [Link]['word_file']
if doc_file and doc_file.filename:
file_ext = [Link](doc_file.filename)[1].lower()
timestamp = [Link]().strftime('%Y%m%d%H%M%S')

if file_ext == '.pdf':
pdf_filename =
secure_filename(f"{slug}_pdf_{timestamp}.pdf")
pdf_path = [Link]([Link]['UPLOAD_FOLDER'],
'pdfs', pdf_filename)
doc_file.save(pdf_path)
pdf_file = f'pdfs/{pdf_filename}'
elif file_ext in ['.docx', '.doc']:
word_filename = secure_filename(f"{slug}_word_{timestamp}
{file_ext}")
word_path = [Link]([Link]['UPLOAD_FOLDER'],
'rules', word_filename)
doc_file.save(word_path)
word_file = f'rules/{word_filename}'
content_html = extract_word_content(word_path, slug,
'rules')
word_uploaded = True

if not content_html and not pdf_file:


editor_content = [Link]('content')
if editor_content:
content_html = editor_content

rule = Rule(slug=slug, title=title, category=category, status=status,


date=date,
summary=summary, content_html=content_html,
cover_image=cover_image,
pdf_file=pdf_file, word_file=word_file, is_pinned=is_pinned)
[Link](rule)
[Link]()

if 'additional_files' in [Link]:
files = [Link]('additional_files')
for file in files:
if file and [Link] and allowed_file([Link]):
filename = secure_filename([Link])
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
filename = f"{slug}_{timestamp}_{filename}"
filepath = [Link]([Link]['UPLOAD_FOLDER'],
'rules', filename)
[Link](filepath)
f_ext = [Link]('.', 1)[1].lower()
rule_file = RuleFile(rule_id=[Link], name=[Link],
file_path=f'rules/{filename}', file_type=f_ext)
[Link](rule_file)

[Link]()

if word_uploaded:
flash('Word 문서가 변환되었습니다. 내용을 확인하세요.', 'success')
return redirect(url_for('admin_edit_rule', id=[Link]))

flash('규정/공지가 등록되었습니다!', 'success')


return redirect(url_for('admin_dashboard'))
except Exception as e:
[Link]()
flash(f'오류가 발생했습니다: {str(e)}', 'error')
return redirect(url_for('admin_new_rule'))

return render_template('admin/rule_form.html', rule=None)

@[Link]('/admin/rules/<int:id>/edit', methods=['GET', 'POST'])


@login_required
def admin_edit_rule(id):
rule = [Link].get_or_404(id)

if [Link] == 'POST':
try:
[Link] = [Link]('title')
[Link] = [Link]('category')
[Link] = [Link]('status', '시행중')
[Link] = [Link]('date')
[Link] = [Link]('summary', '')
rule.is_pinned = 'is_pinned' in [Link]

new_slug = create_slug([Link])
if new_slug != [Link]:
base_slug = new_slug
counter = 1
while [Link]([Link] == new_slug, [Link] !=
[Link]).first():
new_slug = f"{base_slug}-{counter}"
counter += 1
[Link] = new_slug

if [Link]('remove_cover_image') == 'true' and


rule.cover_image:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
rule.cover_image)
if [Link](old_path):
[Link](old_path)
rule.cover_image = None

if 'cover_image' in [Link]:
file = [Link]['cover_image']
if file and [Link] and allowed_file([Link]):
if rule.cover_image:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
rule.cover_image)
if [Link](old_path):
[Link](old_path)
filename = secure_filename([Link])
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
filename = f"{[Link]}_cover_{timestamp}_{filename}"
filepath = [Link]([Link]['UPLOAD_FOLDER'], 'rules',
filename)
[Link](filepath)
rule.cover_image = f'rules/{filename}'

# PDF/Word 삭제
if [Link]('remove_doc') == 'true':
if rule.pdf_file:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
rule.pdf_file)
if [Link](old_path):
[Link](old_path)
rule.pdf_file = None
if rule.word_file:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
rule.word_file)
if [Link](old_path):
[Link](old_path)
rule.word_file = None

word_uploaded = False
if 'word_file' in [Link]:
doc_file = [Link]['word_file']
if doc_file and doc_file.filename:
file_ext = [Link](doc_file.filename)[1].lower()
timestamp = [Link]().strftime('%Y%m%d%H%M%S')
if rule.pdf_file:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
rule.pdf_file)
if [Link](old_path):
[Link](old_path)
rule.pdf_file = None
if rule.word_file:
old_path = [Link]([Link]['UPLOAD_FOLDER'],
rule.word_file)
if [Link](old_path):
[Link](old_path)
rule.word_file = None

if file_ext == '.pdf':
pdf_filename =
secure_filename(f"{[Link]}_pdf_{timestamp}.pdf")
pdf_path = [Link]([Link]['UPLOAD_FOLDER'],
'pdfs', pdf_filename)
doc_file.save(pdf_path)
rule.pdf_file = f'pdfs/{pdf_filename}'
elif file_ext in ['.docx', '.doc']:
word_filename =
secure_filename(f"{[Link]}_word_{timestamp}{file_ext}")
word_path = [Link]([Link]['UPLOAD_FOLDER'],
'rules', word_filename)
doc_file.save(word_path)
rule.word_file = f'rules/{word_filename}'
content_html = extract_word_content(word_path, [Link],
'rules')
if content_html:
rule.content_html = content_html
word_uploaded = True

if not word_uploaded:
content = [Link]('content')
if content:
rule.content_html = content

if [Link]('remove_files'):
file_ids = [Link]('remove_files').split(',')
for file_id in file_ids:
if file_id:
rfile = [Link](int(file_id))
if rfile and rfile.rule_id == [Link]:
file_path = [Link]([Link]['UPLOAD_FOLDER'],
rfile.file_path)
if [Link](file_path):
[Link](file_path)
[Link](rfile)

if 'additional_files' in [Link]:
files = [Link]('additional_files')
for file in files:
if file and [Link] and allowed_file([Link]):
filename = secure_filename([Link])
timestamp = [Link]().strftime('%Y%m%d_%H%M%S')
filename = f"{[Link]}_{timestamp}_{filename}"
filepath = [Link]([Link]['UPLOAD_FOLDER'],
'rules', filename)
[Link](filepath)
f_ext = [Link]('.', 1)[1].lower()
rule_file = RuleFile(rule_id=[Link], name=[Link],
file_path=f'rules/{filename}', file_type=f_ext)
[Link](rule_file)

rule.updated_at = [Link]()
[Link]()

if word_uploaded:
flash('Word 문서가 변환되었습니다. 내용을 확인하세요.', 'success')
return redirect(url_for('admin_edit_rule', id=id))

flash('규정/공지가 수정되었습니다!', 'success')


return redirect(url_for('admin_dashboard'))
except Exception as e:
[Link]()
flash(f'오류가 발생했습니다: {str(e)}', 'error')

return render_template('admin/rule_form.html', rule=rule)

@[Link]('/admin/rules/<int:id>/delete', methods=['POST'])
@login_required
def admin_delete_rule(id):
try:
rule = [Link].get_or_404(id)
if rule.pdf_file:
pdf_path = [Link]([Link]['UPLOAD_FOLDER'], rule.pdf_file)
if [Link](pdf_path):
[Link](pdf_path)
if rule.word_file:
word_path = [Link]([Link]['UPLOAD_FOLDER'], rule.word_file)
if [Link](word_path):
[Link](word_path)
if rule.cover_image:
cover_path = [Link]([Link]['UPLOAD_FOLDER'],
rule.cover_image)
if [Link](cover_path):
[Link](cover_path)
[Link](rule)
[Link]()
flash('규정/공지가 삭제되었습니다!', 'success')
except Exception as e:
[Link]()
flash(f'오류가 발생했습니다: {str(e)}', 'error')
return redirect(url_for('admin_dashboard'))

# Member Admin
@[Link]('/admin/members/new', methods=['GET', 'POST'])
@login_required
def admin_new_member():
if [Link] == 'POST':
name = [Link]('name')
role = [Link]('role')
description = [Link]('description', '')
order = int([Link]('order', 0))
member = Member(name=name, role=role, description=description, order=order)
photo = [Link]('photo')
if photo and [Link]:
filename = secure_filename(f"member_{[Link]().strftime('%Y%m%d%H
%M%S')}_{[Link]}")
photo_path = [Link]([Link]['UPLOAD_FOLDER'], 'members',
filename)
[Link](photo_path)
[Link] = f"members/{filename}"
[Link](member)
[Link]()
flash('구성원이 등록되었습니다.', 'success')
return redirect(url_for('admin_dashboard'))
return render_template('admin/member_form.html', member=None)

@[Link]('/admin/members/<int:id>/edit', methods=['GET', 'POST'])


@login_required
def admin_edit_member(id):
member = [Link].get_or_404(id)
if [Link] == 'POST':
[Link] = [Link]('name')
[Link] = [Link]('role')
[Link] = [Link]('description', '')
[Link] = int([Link]('order', 0))
if [Link]('remove_photo') == 'true' and [Link]:
old_path = [Link]([Link]['UPLOAD_FOLDER'], [Link])
if [Link](old_path):
[Link](old_path)
[Link] = None
photo = [Link]('photo')
if photo and [Link]:
if [Link]:
old_path = [Link]([Link]['UPLOAD_FOLDER'], [Link])
if [Link](old_path):
[Link](old_path)
filename = secure_filename(f"member_{[Link]().strftime('%Y%m%d%H
%M%S')}_{[Link]}")
photo_path = [Link]([Link]['UPLOAD_FOLDER'], 'members',
filename)
[Link](photo_path)
[Link] = f"members/{filename}"
[Link]()
flash('구성원 정보가 수정되었습니다.', 'success')
return redirect(url_for('admin_dashboard'))
return render_template('admin/member_form.html', member=member)

@[Link]('/admin/members/<int:id>/delete', methods=['POST'])
@login_required
def admin_delete_member(id):
member = [Link].get_or_404(id)
if [Link]:
photo_path = [Link]([Link]['UPLOAD_FOLDER'], [Link])
if [Link](photo_path):
[Link](photo_path)
[Link](member)
[Link]()
flash('구성원이 삭제되었습니다.', 'success')
return redirect(url_for('admin_dashboard'))

# Init & Error Handlers


def init_db():
with app.app_context():
db.create_all()
admin =
[Link].filter_by(username=[Link]['ADMIN_USERNAME']).first()
if not admin:
admin = AdminUser(username=[Link]['ADMIN_USERNAME'], role='admin')
admin.set_password([Link]['ADMIN_PASSWORD'])
[Link](admin)
[Link]()

@[Link](404)
def page_not_found(e):
return render_template('[Link]'), 404

@[Link](500)
def internal_error(e):
[Link]()
return render_template('[Link]'), 500

@app.template_filter('datetime')
def format_datetime(value, format='%Y-%m-%d'):
if isinstance(value, str):
return value
return [Link](format)

if __name__ == '__main__':
init_db()
[Link](debug=True, host="[Link]", port=9900)

You might also like