feat: configure lottery events in private chat
This commit is contained in:
+3
-3
@@ -292,9 +292,9 @@ async def cmd_help(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
"✅ /checkin - 每日签到\n"
|
||||
"🎮 /trivia - 知识答题\n"
|
||||
"🏆 /rank - 查看积分排行\n"
|
||||
"🎁 /lottery - 发起群内抽奖\n"
|
||||
" 格式:/lottery 奖品 | 参与条件 | 结束条件\n"
|
||||
" 示例:/lottery 月卡一张 | all | people:3\n"
|
||||
"🎁 /lottery - 发起群内抽奖,进入私聊设置奖品和条件\n"
|
||||
" 私聊格式:奖品 | 参与条件 | 结束条件\n"
|
||||
" 示例:月卡一张 | all | people:3\n"
|
||||
"🔗 /bind - 绑定账号\n\n"
|
||||
"管理员操作:\n"
|
||||
"🌙 /night on/off - 开启/关闭夜间模式\n"
|
||||
|
||||
+98
-41
@@ -2,6 +2,8 @@
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
import config
|
||||
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update
|
||||
from telegram.ext import ApplicationHandlerStop, CallbackQueryHandler, ContextTypes, CommandHandler, MessageHandler, filters
|
||||
|
||||
@@ -182,46 +184,60 @@ async def schedule_lottery_draw(context: ContextTypes.DEFAULT_TYPE, event_id: in
|
||||
asyncio.create_task(_run())
|
||||
|
||||
|
||||
async def create_lottery_from_text(update: Update, context: ContextTypes.DEFAULT_TYPE, spec_text: str):
|
||||
async def create_lottery_from_text(update: Update, context: ContextTypes.DEFAULT_TYPE, spec_text: str, publish_chat_id: int | None = None):
|
||||
user = update.effective_user
|
||||
msg = update.effective_message
|
||||
spec = parse_lottery_spec(spec_text)
|
||||
target_chat_id = publish_chat_id or msg.chat_id
|
||||
event = await create_lottery_event(
|
||||
chat_id=msg.chat_id,
|
||||
chat_id=target_chat_id,
|
||||
creator_id=user.id,
|
||||
creator_name=user.username or user.first_name or str(user.id),
|
||||
spec=spec,
|
||||
)
|
||||
sent = await msg.reply_text(await build_lottery_text(event), reply_markup=lottery_keyboard(event.id))
|
||||
sent = await context.bot.send_message(
|
||||
chat_id=target_chat_id,
|
||||
text=await build_lottery_text(event),
|
||||
reply_markup=lottery_keyboard(event.id),
|
||||
)
|
||||
event.message_id = sent.message_id
|
||||
await event.save()
|
||||
if event.end_type == "minutes":
|
||||
await schedule_lottery_draw(context, event.id, event.end_value * 60)
|
||||
return sent
|
||||
return event
|
||||
|
||||
|
||||
async def send_lottery_private入口(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
me = await context.bot.get_me()
|
||||
bot_username = me.username
|
||||
target_chat_id = update.effective_chat.id
|
||||
url = f"https://t.me/{bot_username}?start=lottery_{target_chat_id}"
|
||||
keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("去私聊设置抽奖", url=url)]])
|
||||
text = (
|
||||
"🎁 发起群内抽奖\n"
|
||||
"为了避免奖品和条件刷屏,请到 Bot 私聊界面设置。\n\n"
|
||||
f"👉 点击进入:{url}"
|
||||
)
|
||||
reply = await update.effective_message.reply_text(text, reply_markup=keyboard, disable_web_page_preview=True)
|
||||
asyncio.create_task(auto_delete(update.effective_message, seconds=60))
|
||||
asyncio.create_task(auto_delete(reply, seconds=60))
|
||||
return reply
|
||||
|
||||
|
||||
async def cmd_lottery(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
parts = (update.message.text or "").split(maxsplit=1)
|
||||
if len(parts) > 1:
|
||||
try:
|
||||
await create_lottery_from_text(update, context, parts[1])
|
||||
except Exception as e:
|
||||
reply = await update.message.reply_text(f"❌ 抽奖格式错误:{e}\n\n示例:/lottery 月卡一张 | all | people:3")
|
||||
asyncio.create_task(auto_delete(reply, seconds=90))
|
||||
else:
|
||||
context.user_data["awaiting_lottery_spec"] = True
|
||||
reply = await update.message.reply_text(
|
||||
"🎁 发起群内抽奖\n"
|
||||
"请发送:奖品 | 参与条件 | 结束条件\n\n"
|
||||
"示例:\n"
|
||||
"月卡一张 | all | people:3\n"
|
||||
"邀请码 | checkin | minutes:10\n"
|
||||
"徽章 | points:100 | people:5\n\n"
|
||||
"参与条件:all / checkin / points:N\n"
|
||||
"结束条件:people:N / minutes:N"
|
||||
)
|
||||
asyncio.create_task(auto_delete(reply, seconds=120))
|
||||
asyncio.create_task(auto_delete(update.message, seconds=60))
|
||||
if update.effective_chat.type != "private":
|
||||
await send_lottery_private入口(update, context)
|
||||
return
|
||||
|
||||
context.user_data["awaiting_lottery_spec"] = True
|
||||
context.user_data["lottery_target_chat_id"] = config.TG_CHAT_ID
|
||||
await update.message.reply_text(
|
||||
"🎁 发起群内抽奖\n"
|
||||
"请发送:奖品 | 参与条件 | 结束条件\n\n"
|
||||
"示例:月卡一张 | all | people:3\n"
|
||||
"参与条件:all / checkin / points:N\n"
|
||||
"结束条件:people:N / minutes:N"
|
||||
)
|
||||
|
||||
|
||||
async def cmd_shop(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
@@ -271,14 +287,19 @@ async def handle_panel_callback(update: Update, context: ContextTypes.DEFAULT_TY
|
||||
result = await daily_checkin(user.id, user.username or user.first_name or str(user.id))
|
||||
text = "❌ 你今天已经签到过了" if not result["ok"] else f"✅ 签到成功!奖励 +{result['bonus']} 分,连续 {result['streak']} 天"
|
||||
elif action == "lottery":
|
||||
context.user_data["awaiting_lottery_spec"] = True
|
||||
text = (
|
||||
me = await context.bot.get_me()
|
||||
url = f"https://t.me/{me.username}?start=lottery_{query.message.chat_id}"
|
||||
keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("去私聊设置抽奖", url=url)]])
|
||||
await query.edit_message_text(
|
||||
"🎁 发起群内抽奖\n"
|
||||
"请在群里发送:奖品 | 参与条件 | 结束条件\n\n"
|
||||
"示例:月卡一张 | all | people:3\n"
|
||||
"参与条件:all / checkin / points:N\n"
|
||||
"结束条件:people:N / minutes:N"
|
||||
"请到 Bot 私聊界面设置奖品、参与条件和结束条件。\n\n"
|
||||
f"👉 点击进入:{url}\n\n"
|
||||
"⏱️ 60 秒无操作后自动消失。",
|
||||
reply_markup=keyboard,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
schedule_panel_idle_delete(context, query.message)
|
||||
return
|
||||
elif action == "shop":
|
||||
summary = await get_scores_summary(user.id)
|
||||
text = f"🛒 积分商城\n当前总积分:{summary['total']} 分\n" + "\n".join([f"{k}. {v['name']} — {v['cost']} 分" for k, v in SHOP_ITEMS.items()]) + "\n\n购买请发送 /buy 商品编号"
|
||||
@@ -301,15 +322,6 @@ async def handle_trivia_answer(update: Update, context: ContextTypes.DEFAULT_TYP
|
||||
if not msg or not msg.text or not user or user.is_bot:
|
||||
return
|
||||
|
||||
if context.user_data.get("awaiting_lottery_spec"):
|
||||
try:
|
||||
await create_lottery_from_text(update, context, msg.text.strip())
|
||||
context.user_data.pop("awaiting_lottery_spec", None)
|
||||
asyncio.create_task(auto_delete(msg, seconds=60))
|
||||
except Exception as e:
|
||||
reply = await msg.reply_text(f"❌ 抽奖格式错误:{e}\n请重新发送,或发送 /panel 重新开始。")
|
||||
asyncio.create_task(auto_delete(reply, seconds=90))
|
||||
raise ApplicationHandlerStop
|
||||
|
||||
correct_answer = context.user_data.get("trivia_answer")
|
||||
options = context.user_data.get("trivia_options") or []
|
||||
@@ -376,6 +388,49 @@ async def handle_lottery_callback(update: Update, context: ContextTypes.DEFAULT_
|
||||
await query.answer(f"参与成功,当前 {result['count']} 人")
|
||||
|
||||
|
||||
async def cmd_lottery_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
if update.effective_chat.type != "private" or not context.args:
|
||||
return
|
||||
arg = context.args[0]
|
||||
if not arg.startswith("lottery_"):
|
||||
return
|
||||
try:
|
||||
target_chat_id = int(arg.split("_", 1)[1])
|
||||
except Exception:
|
||||
target_chat_id = config.TG_CHAT_ID
|
||||
context.user_data["awaiting_lottery_spec"] = True
|
||||
context.user_data["lottery_target_chat_id"] = target_chat_id
|
||||
await update.message.reply_text(
|
||||
"🎁 发起群内抽奖\n"
|
||||
"请发送:奖品 | 参与条件 | 结束条件\n\n"
|
||||
"示例:月卡一张 | all | people:3\n"
|
||||
"参与条件:all / checkin / points:N\n"
|
||||
"结束条件:people:N / minutes:N"
|
||||
)
|
||||
|
||||
|
||||
async def handle_private_lottery_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
if update.effective_chat.type != "private" or not context.user_data.get("awaiting_lottery_spec"):
|
||||
return
|
||||
try:
|
||||
target_chat_id = int(context.user_data.get("lottery_target_chat_id") or config.TG_CHAT_ID)
|
||||
event = await create_lottery_from_text(update, context, update.message.text.strip(), publish_chat_id=target_chat_id)
|
||||
context.user_data.pop("awaiting_lottery_spec", None)
|
||||
context.user_data.pop("lottery_target_chat_id", None)
|
||||
await update.message.reply_text(
|
||||
"✅ 抽奖活动已发布到群里\n"
|
||||
f"🎯 奖品:{event.prize}\n"
|
||||
f"✅ 参与条件:{await lottery_condition_text(event)}\n"
|
||||
f"⏱️ 结束条件:{await lottery_end_text(event)}"
|
||||
)
|
||||
except Exception as e:
|
||||
await update.message.reply_text(
|
||||
f"❌ 抽奖格式错误:{e}\n\n"
|
||||
"请重新发送:奖品 | 参与条件 | 结束条件\n"
|
||||
"示例:月卡一张 | all | people:3"
|
||||
)
|
||||
|
||||
|
||||
async def auto_delete(message, seconds=60):
|
||||
try:
|
||||
await asyncio.sleep(seconds)
|
||||
@@ -389,11 +444,13 @@ def register_fun(app):
|
||||
app.add_handler(CommandHandler("trivia", cmd_trivia, filters.ChatType.GROUPS))
|
||||
app.add_handler(CommandHandler("score", cmd_score, filters.ChatType.GROUPS))
|
||||
app.add_handler(CommandHandler("rank", cmd_rank, filters.ChatType.GROUPS))
|
||||
app.add_handler(CommandHandler("lottery", cmd_lottery, filters.ChatType.GROUPS))
|
||||
app.add_handler(CommandHandler("lottery", cmd_lottery))
|
||||
app.add_handler(CommandHandler("shop", cmd_shop, filters.ChatType.GROUPS))
|
||||
app.add_handler(CommandHandler("buy", cmd_buy, filters.ChatType.GROUPS))
|
||||
app.add_handler(CommandHandler("panel", cmd_panel, filters.ChatType.GROUPS))
|
||||
app.add_handler(CommandHandler("start", cmd_lottery_start, filters.ChatType.PRIVATE), group=1)
|
||||
app.add_handler(CallbackQueryHandler(handle_panel_callback, pattern=r"^panel:"))
|
||||
app.add_handler(CallbackQueryHandler(handle_lottery_callback, pattern=r"^lottery:"))
|
||||
app.add_handler(MessageHandler(filters.TEXT & filters.ChatType.PRIVATE & ~filters.COMMAND, handle_private_lottery_text), group=1)
|
||||
app.add_handler(MessageHandler(filters.TEXT & filters.ChatType.GROUPS & ~filters.COMMAND, handle_trivia_answer), group=-1)
|
||||
app.add_handler(MessageHandler(filters.TEXT & filters.ChatType.GROUPS, handle_trigger), group=2)
|
||||
|
||||
Reference in New Issue
Block a user