feat: pending 글 카테고리 변경 기능 추가

- /setcorner <번호> <카테고리>: 커맨드로 변경
- /pending 버튼에 🏷 카테고리 변경 버튼 추가 → 클릭 시 9개 카테고리 선택 버튼 표시

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
JOUNGWOOK KWON
2026-03-30 17:13:40 +09:00
parent 8c66d9b9e0
commit 0e72e6de88

View File

@@ -1163,6 +1163,9 @@ async def cmd_pending(update: Update, context: ContextTypes.DEFAULT_TYPE):
[
InlineKeyboardButton("✅ 승인 발행", callback_data=f"approve:{filename}"),
InlineKeyboardButton("🗑 거부", callback_data=f"reject:{filename}"),
],
[
InlineKeyboardButton("🏷 카테고리 변경", callback_data=f"setcorner:{filename}"),
]
])
await update.message.reply_text(
@@ -1170,12 +1173,59 @@ async def cmd_pending(update: Update, context: ContextTypes.DEFAULT_TYPE):
f"<b>{title}</b>\n"
f"코너: {corner}\n"
f"사유: {reason}\n\n"
f"{body_preview}...",
f"{body_preview}...\n\n"
f"카테고리 변경: /setcorner {i} 재테크",
parse_mode='HTML',
reply_markup=keyboard,
)
async def cmd_setcorner(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""/setcorner <번호> <카테고리> — pending 글 카테고리 변경"""
VALID_CORNERS = {"AI인사이트", "여행맛집", "스타트업", "TV로보는세상", "제품리뷰", "생활꿀팁", "건강정보", "재테크", "팩트체크"}
args = context.args
if len(args) < 2:
await update.message.reply_text(
"사용법: /setcorner <번호> <카테고리>\n"
"예: /setcorner 1 재테크\n"
f"카테고리: {', '.join(sorted(VALID_CORNERS))}"
)
return
sys.path.insert(0, str(BASE_DIR / 'bots'))
import publisher_bot
pending = publisher_bot.get_pending_list()
if not pending:
await update.message.reply_text("대기 글이 없습니다.")
return
try:
idx = int(args[0]) - 1
except ValueError:
await update.message.reply_text("❌ 번호를 숫자로 입력하세요.")
return
if not (0 <= idx < len(pending)):
await update.message.reply_text(f"❌ 1~{len(pending)} 사이 번호를 입력하세요.")
return
new_corner = args[1]
if new_corner not in VALID_CORNERS:
await update.message.reply_text(f"❌ 유효하지 않은 카테고리입니다.\n사용 가능: {', '.join(sorted(VALID_CORNERS))}")
return
filepath = pending[idx].get('_filepath', '')
if not filepath or not Path(filepath).exists():
await update.message.reply_text("❌ 파일을 찾을 수 없습니다.")
return
# 파일 수정
article = json.loads(Path(filepath).read_text(encoding='utf-8'))
old_corner = article.get('corner', '')
article['corner'] = new_corner
Path(filepath).write_text(json.dumps(article, ensure_ascii=False, indent=2), encoding='utf-8')
await update.message.reply_text(
f"✅ 카테고리 변경 완료!\n"
f"제목: {article.get('title','')[:50]}\n"
f"{old_corner}{new_corner}\n\n"
f"👉 /pending 으로 승인하세요."
)
async def cmd_approve(update: Update, context: ContextTypes.DEFAULT_TYPE):
sys.path.insert(0, str(BASE_DIR / 'bots'))
import publisher_bot
@@ -1235,6 +1285,34 @@ async def callback_approve_reject(update: Update, context: ContextTypes.DEFAULT_
elif action == 'reject':
publisher_bot.reject_pending(str(filepath))
await query.edit_message_text(f"🗑 거부 완료\n\n{query.message.text_html or query.message.text}", parse_mode='HTML')
elif action == 'setcorner':
VALID_CORNERS = ["AI인사이트", "여행맛집", "스타트업", "TV로보는세상", "제품리뷰", "생활꿀팁", "건강정보", "재테크", "팩트체크"]
# 카테고리 선택 버튼 표시
buttons = [[InlineKeyboardButton(c, callback_data=f"docorner:{filename}:{c}")] for c in VALID_CORNERS]
await query.edit_message_reply_markup(reply_markup=InlineKeyboardMarkup(buttons))
elif action == 'docorner':
# filename:corner 형태로 파싱
parts = filename.split(':', 1)
real_filename = parts[0]
new_corner = parts[1] if len(parts) > 1 else ''
real_filepath = pending_dir / real_filename
if real_filepath.exists() and new_corner:
article = json.loads(real_filepath.read_text(encoding='utf-8'))
old_corner = article.get('corner', '')
article['corner'] = new_corner
real_filepath.write_text(json.dumps(article, ensure_ascii=False, indent=2), encoding='utf-8')
# 원래 버튼으로 복원
keyboard = InlineKeyboardMarkup([
[
InlineKeyboardButton("✅ 승인 발행", callback_data=f"approve:{real_filename}"),
InlineKeyboardButton("🗑 거부", callback_data=f"reject:{real_filename}"),
],
[InlineKeyboardButton("🏷 카테고리 변경", callback_data=f"setcorner:{real_filename}")]
])
await query.edit_message_text(
f"🏷 카테고리 변경: {old_corner}{new_corner}\n{article.get('title','')[:50]}",
reply_markup=keyboard
)
async def cmd_report(update: Update, context: ContextTypes.DEFAULT_TYPE):
@@ -1723,7 +1801,8 @@ async def main():
app.add_handler(CommandHandler('approve', cmd_approve))
app.add_handler(CommandHandler('reject', cmd_reject))
app.add_handler(CommandHandler('pending', cmd_pending))
app.add_handler(CallbackQueryHandler(callback_approve_reject, pattern=r'^(approve|reject):'))
app.add_handler(CallbackQueryHandler(callback_approve_reject, pattern=r'^(approve|reject|setcorner|docorner):'))
app.add_handler(CommandHandler('setcorner', cmd_setcorner))
app.add_handler(CommandHandler('report', cmd_report))
app.add_handler(CommandHandler('idea', cmd_idea))
app.add_handler(CommandHandler('topic', cmd_topic))