This commit is contained in:
113
handlers/share_channel.py
Normal file
113
handlers/share_channel.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# handlers/share_channel.py
|
||||
from datetime import datetime, timedelta
|
||||
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.ext import (
|
||||
ContextTypes, ConversationHandler, CommandHandler, CallbackQueryHandler
|
||||
)
|
||||
from sqlalchemy import select
|
||||
|
||||
from db import AsyncSessionLocal
|
||||
from models import Channel, ChannelAccess, SCOPE_POST
|
||||
from .permissions import get_or_create_admin, make_token, token_hash
|
||||
|
||||
SELECT_CHANNEL, CONFIRM_INVITE = range(2)
|
||||
|
||||
async def share_channel_start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
async with AsyncSessionLocal() as session:
|
||||
me = await get_or_create_admin(session, update.effective_user.id)
|
||||
q = await session.execute(select(Channel).where(Channel.admin_id == me.id))
|
||||
channels = q.scalars().all()
|
||||
|
||||
if not channels:
|
||||
if update.message:
|
||||
await update.message.reply_text("Нет каналов, которыми вы владеете.")
|
||||
return ConversationHandler.END
|
||||
|
||||
kb = [[InlineKeyboardButton(f"{c.name} ({c.link})", callback_data=f"sch_{c.id}")] for c in channels]
|
||||
rm = InlineKeyboardMarkup(kb)
|
||||
if update.message:
|
||||
await update.message.reply_text("Выберите канал для выдачи доступа:", reply_markup=rm)
|
||||
return SELECT_CHANNEL
|
||||
|
||||
async def select_channel(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
q = update.callback_query
|
||||
if not q: return ConversationHandler.END
|
||||
await q.answer()
|
||||
if not q.data.startswith("sch_"): return ConversationHandler.END
|
||||
channel_id = int(q.data.split("_")[1])
|
||||
context.user_data["share_channel_id"] = channel_id
|
||||
|
||||
kb = [
|
||||
[InlineKeyboardButton("Срок: 7 дней", callback_data="ttl_7"),
|
||||
InlineKeyboardButton("30 дней", callback_data="ttl_30"),
|
||||
InlineKeyboardButton("∞", callback_data="ttl_inf")],
|
||||
[InlineKeyboardButton("Выдать право постинга", callback_data="scope_post")],
|
||||
[InlineKeyboardButton("Сгенерировать ссылку", callback_data="go")],
|
||||
]
|
||||
await q.edit_message_text("Настройте приглашение:", reply_markup=InlineKeyboardMarkup(kb))
|
||||
context.user_data["ttl_days"] = 7
|
||||
context.user_data["scopes"] = SCOPE_POST
|
||||
return CONFIRM_INVITE
|
||||
|
||||
async def confirm_invite(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||
q = update.callback_query
|
||||
if not q: return ConversationHandler.END
|
||||
await q.answer()
|
||||
|
||||
data = q.data
|
||||
if data.startswith("ttl_"):
|
||||
context.user_data["ttl_days"] = {"ttl_7":7, "ttl_30":30, "ttl_inf":None}[data]
|
||||
await q.edit_message_reply_markup(reply_markup=q.message.reply_markup)
|
||||
return CONFIRM_INVITE
|
||||
if data == "scope_post":
|
||||
# пока фиксируем только POST
|
||||
await q.edit_message_reply_markup(reply_markup=q.message.reply_markup)
|
||||
return CONFIRM_INVITE
|
||||
if data != "go":
|
||||
return CONFIRM_INVITE
|
||||
|
||||
channel_id = context.user_data.get("share_channel_id")
|
||||
ttl_days = context.user_data.get("ttl_days")
|
||||
scopes = context.user_data.get("scopes")
|
||||
|
||||
async with AsyncSessionLocal() as session:
|
||||
me = await get_or_create_admin(session, update.effective_user.id)
|
||||
|
||||
token = make_token(9)
|
||||
thash = token_hash(token)
|
||||
|
||||
expires_at = None
|
||||
if ttl_days:
|
||||
expires_at = datetime.utcnow() + timedelta(days=ttl_days)
|
||||
|
||||
acc = ChannelAccess(
|
||||
channel_id=channel_id,
|
||||
invited_by_admin_id=me.id,
|
||||
token_hash=thash,
|
||||
scopes=scopes,
|
||||
status="pending",
|
||||
created_at=datetime.utcnow(),
|
||||
expires_at=expires_at,
|
||||
)
|
||||
session.add(acc)
|
||||
await session.commit()
|
||||
invite_id = acc.id
|
||||
|
||||
payload = f"sch_{invite_id}_{token}"
|
||||
await q.edit_message_text(
|
||||
"Ссылка для выдачи доступа к каналу:\n"
|
||||
f"`https://t.me/<YOUR_BOT_USERNAME>?start={payload}`\n\n"
|
||||
"Передайте её коллеге. Срок действия — "
|
||||
+ ("не ограничен." if ttl_days is None else f"{ttl_days} дней."),
|
||||
parse_mode="Markdown",
|
||||
)
|
||||
return ConversationHandler.END
|
||||
|
||||
share_channel_conv = ConversationHandler(
|
||||
entry_points=[CommandHandler("share_channel", share_channel_start)],
|
||||
states={
|
||||
SELECT_CHANNEL: [CallbackQueryHandler(select_channel, pattern="^sch_")],
|
||||
CONFIRM_INVITE: [CallbackQueryHandler(confirm_invite)],
|
||||
},
|
||||
fallbacks=[],
|
||||
)
|
||||
Reference in New Issue
Block a user