diff --git a/bots/scheduler.py b/bots/scheduler.py index 6383fdc..fc126d3 100644 --- a/bots/scheduler.py +++ b/bots/scheduler.py @@ -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"{title}\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))