first commit
This commit is contained in:
2
utils/__init__.py
Normal file
2
utils/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# Utils package
|
||||
|
||||
66
utils/google_drive.py
Normal file
66
utils/google_drive.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import os
|
||||
from google.oauth2.credentials import Credentials
|
||||
from google_auth_oauthlib.flow import InstalledAppFlow
|
||||
from google.auth.transport.requests import Request
|
||||
from googleapiclient.discovery import build
|
||||
from googleapiclient.http import MediaFileUpload
|
||||
import pickle
|
||||
|
||||
SCOPES = ['https://www.googleapis.com/auth/drive.file']
|
||||
|
||||
class GoogleDriveUploader:
|
||||
def __init__(self, credentials_file, token_file):
|
||||
self.credentials_file = credentials_file
|
||||
self.token_file = token_file
|
||||
self.service = None
|
||||
self._authenticate()
|
||||
|
||||
def _authenticate(self):
|
||||
"""구글 드라이브 인증"""
|
||||
creds = None
|
||||
|
||||
# 기존 토큰 파일이 있으면 로드
|
||||
if os.path.exists(self.token_file):
|
||||
with open(self.token_file, 'rb') as token:
|
||||
creds = pickle.load(token)
|
||||
|
||||
# 유효한 인증 정보가 없으면 새로 인증
|
||||
if not creds or not creds.valid:
|
||||
if creds and creds.expired and creds.refresh_token:
|
||||
creds.refresh(Request())
|
||||
else:
|
||||
if not os.path.exists(self.credentials_file):
|
||||
raise FileNotFoundError(
|
||||
f"구글 드라이브 인증 파일을 찾을 수 없습니다: {self.credentials_file}\n"
|
||||
"Google Cloud Console에서 OAuth 2.0 클라이언트 ID를 다운로드하여 "
|
||||
"credentials.json으로 저장해주세요."
|
||||
)
|
||||
flow = InstalledAppFlow.from_client_secrets_file(
|
||||
self.credentials_file, SCOPES)
|
||||
creds = flow.run_local_server(port=0)
|
||||
|
||||
# 토큰 저장
|
||||
with open(self.token_file, 'wb') as token:
|
||||
pickle.dump(creds, token)
|
||||
|
||||
self.service = build('drive', 'v3', credentials=creds)
|
||||
|
||||
def upload_file(self, file_path, file_name, folder_id=None):
|
||||
"""파일을 구글 드라이브에 업로드"""
|
||||
if not self.service:
|
||||
raise Exception("구글 드라이브 서비스가 초기화되지 않았습니다.")
|
||||
|
||||
file_metadata = {'name': file_name}
|
||||
if folder_id:
|
||||
file_metadata['parents'] = [folder_id]
|
||||
|
||||
media = MediaFileUpload(file_path, mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document')
|
||||
|
||||
file = self.service.files().create(
|
||||
body=file_metadata,
|
||||
media_body=media,
|
||||
fields='id'
|
||||
).execute()
|
||||
|
||||
return file.get('id')
|
||||
|
||||
118
utils/word_processor.py
Normal file
118
utils/word_processor.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from docx import Document
|
||||
from docx.shared import Pt
|
||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
class WordProcessor:
|
||||
def __init__(self, template_dir):
|
||||
self.template_dir = template_dir
|
||||
self.output_dir = 'output'
|
||||
os.makedirs(self.output_dir, exist_ok=True)
|
||||
|
||||
def generate_document(self, data, cult_name='기타'):
|
||||
"""데이터를 워드 문서로 생성"""
|
||||
# 템플릿 파일 경로
|
||||
template_file = os.path.join(self.template_dir, f'{cult_name}_template.docx')
|
||||
|
||||
# 템플릿이 없으면 기본 템플릿 사용
|
||||
if not os.path.exists(template_file):
|
||||
template_file = os.path.join(self.template_dir, 'default_template.docx')
|
||||
|
||||
# 템플릿이 있으면 사용, 없으면 새 문서 생성
|
||||
if os.path.exists(template_file):
|
||||
doc = Document(template_file)
|
||||
else:
|
||||
doc = Document()
|
||||
self._create_default_template(doc)
|
||||
|
||||
# 데이터 채우기
|
||||
self._fill_document(doc, data)
|
||||
|
||||
# 출력 파일명
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
name = data.get('basic_info', {}).get('name', '무명')
|
||||
output_filename = f'교리점검표_{name}_{timestamp}.docx'
|
||||
output_path = os.path.join(self.output_dir, output_filename)
|
||||
|
||||
doc.save(output_path)
|
||||
return output_path
|
||||
|
||||
def _create_default_template(self, doc):
|
||||
"""기본 템플릿 생성"""
|
||||
# 제목
|
||||
title = doc.add_heading('이단 탈퇴자 교리점검표', 0)
|
||||
title.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
|
||||
# 기본 정보 섹션
|
||||
doc.add_heading('1. 기본 정보', level=1)
|
||||
doc.add_paragraph('이름: {name}')
|
||||
doc.add_paragraph('교구: {district}')
|
||||
doc.add_paragraph('이단교단: {cult}')
|
||||
|
||||
# 기독교대한감리회 신앙고백
|
||||
doc.add_heading('2. 기독교대한감리회 신앙고백 교리 점검', level=1)
|
||||
doc.add_paragraph('{methodist_doctrine}')
|
||||
|
||||
# 이단 일반 교리 점검
|
||||
doc.add_heading('3. 이단 일반 교리 점검', level=1)
|
||||
doc.add_paragraph('{general_cult_doctrine}')
|
||||
|
||||
# 출신 이단별 교리 점검
|
||||
doc.add_heading('4. 출신 이단별 교리 점검', level=1)
|
||||
doc.add_paragraph('{specific_cult_doctrine}')
|
||||
|
||||
# 간증문
|
||||
doc.add_heading('5. 간증문', level=1)
|
||||
doc.add_paragraph('{testimony}')
|
||||
|
||||
doc.add_paragraph('')
|
||||
doc.add_paragraph(f'작성일: {datetime.now().strftime("%Y년 %m월 %d일")}')
|
||||
|
||||
def _fill_document(self, doc, data):
|
||||
"""문서에 데이터 채우기"""
|
||||
basic_info = data.get('basic_info', {})
|
||||
methodist = data.get('methodist_doctrine', {})
|
||||
general = data.get('general_cult_doctrine', {})
|
||||
specific = data.get('specific_cult_doctrine', {})
|
||||
testimony = data.get('testimony', {})
|
||||
|
||||
# 모든 단락을 순회하며 플레이스홀더 교체
|
||||
replacements = {
|
||||
'{name}': basic_info.get('name', ''),
|
||||
'{district}': basic_info.get('district', ''),
|
||||
'{cult}': basic_info.get('cult', ''),
|
||||
'{methodist_doctrine}': self._format_answers(methodist),
|
||||
'{general_cult_doctrine}': self._format_answers(general),
|
||||
'{specific_cult_doctrine}': self._format_answers(specific),
|
||||
'{testimony}': testimony.get('content', '')
|
||||
}
|
||||
|
||||
for paragraph in doc.paragraphs:
|
||||
for key, value in replacements.items():
|
||||
if key in paragraph.text:
|
||||
paragraph.text = paragraph.text.replace(key, str(value))
|
||||
|
||||
# 테이블도 처리
|
||||
for table in doc.tables:
|
||||
for row in table.rows:
|
||||
for cell in row.cells:
|
||||
for key, value in replacements.items():
|
||||
if key in cell.text:
|
||||
cell.text = cell.text.replace(key, str(value))
|
||||
|
||||
def _format_answers(self, answers_dict):
|
||||
"""답변 딕셔너리를 텍스트로 포맷팅"""
|
||||
if not answers_dict:
|
||||
return '답변 없음'
|
||||
|
||||
result = []
|
||||
for key, value in answers_dict.items():
|
||||
if isinstance(value, dict):
|
||||
# 중첩된 구조 처리
|
||||
result.append(f"{key}: {self._format_answers(value)}")
|
||||
else:
|
||||
result.append(f"{key}: {value}")
|
||||
|
||||
return '\n'.join(result)
|
||||
|
||||
Reference in New Issue
Block a user