This commit is contained in:
@@ -9,6 +9,17 @@ from sqlalchemy import select
|
|||||||
from db import AsyncSessionLocal
|
from db import AsyncSessionLocal
|
||||||
from models import Channel, ChannelAccess, SCOPE_POST
|
from models import Channel, ChannelAccess, SCOPE_POST
|
||||||
from .permissions import get_or_create_admin, make_token, token_hash
|
from .permissions import get_or_create_admin, make_token, token_hash
|
||||||
|
from telegram.error import BadRequest
|
||||||
|
import os
|
||||||
|
from telegram import InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
|
||||||
|
async def _get_bot_username(context: ContextTypes.DEFAULT_TYPE) -> str:
|
||||||
|
# кэшируем, чтобы не дёргать get_me() каждый раз
|
||||||
|
uname = context.application.bot.username
|
||||||
|
if uname:
|
||||||
|
return uname
|
||||||
|
me = await context.bot.get_me()
|
||||||
|
return me.username
|
||||||
|
|
||||||
SELECT_CHANNEL, CONFIRM_INVITE = range(2)
|
SELECT_CHANNEL, CONFIRM_INVITE = range(2)
|
||||||
|
|
||||||
@@ -51,24 +62,32 @@ async def select_channel(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
|
|
||||||
async def confirm_invite(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def confirm_invite(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
q = update.callback_query
|
q = update.callback_query
|
||||||
if not q: return ConversationHandler.END
|
if not q:
|
||||||
|
return ConversationHandler.END
|
||||||
|
# Лёгкий ACK, чтобы исчез «часик» на кнопке
|
||||||
await q.answer()
|
await q.answer()
|
||||||
|
|
||||||
data = q.data
|
data = q.data
|
||||||
|
|
||||||
|
# --- настройки TTL (ничего не меняем в разметке, только сохраняем выбор) ---
|
||||||
if data.startswith("ttl_"):
|
if data.startswith("ttl_"):
|
||||||
context.user_data["ttl_days"] = {"ttl_7":7, "ttl_30":30, "ttl_inf":None}[data]
|
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)
|
# Нечего редактировать — markup не менялся. Просто остаёмся в состоянии.
|
||||||
return CONFIRM_INVITE
|
return CONFIRM_INVITE
|
||||||
|
|
||||||
|
# --- права: сейчас фиксировано SCOPE_POST, разметку не меняем ---
|
||||||
if data == "scope_post":
|
if data == "scope_post":
|
||||||
# пока фиксируем только POST
|
# если позже сделаешь тумблеры прав — тут можно перестраивать клавиатуру
|
||||||
await q.edit_message_reply_markup(reply_markup=q.message.reply_markup)
|
context.user_data["scopes"] = SCOPE_POST
|
||||||
return CONFIRM_INVITE
|
return CONFIRM_INVITE
|
||||||
|
|
||||||
|
# --- генерация ссылки приглашения ---
|
||||||
if data != "go":
|
if data != "go":
|
||||||
return CONFIRM_INVITE
|
return CONFIRM_INVITE
|
||||||
|
|
||||||
channel_id = context.user_data.get("share_channel_id")
|
channel_id = context.user_data.get("share_channel_id")
|
||||||
ttl_days = context.user_data.get("ttl_days")
|
ttl_days = context.user_data.get("ttl_days")
|
||||||
scopes = context.user_data.get("scopes")
|
scopes = context.user_data.get("scopes", SCOPE_POST)
|
||||||
|
|
||||||
async with AsyncSessionLocal() as session:
|
async with AsyncSessionLocal() as session:
|
||||||
me = await get_or_create_admin(session, update.effective_user.id)
|
me = await get_or_create_admin(session, update.effective_user.id)
|
||||||
@@ -78,6 +97,7 @@ async def confirm_invite(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
|
|
||||||
expires_at = None
|
expires_at = None
|
||||||
if ttl_days:
|
if ttl_days:
|
||||||
|
from datetime import datetime, timedelta
|
||||||
expires_at = datetime.utcnow() + timedelta(days=ttl_days)
|
expires_at = datetime.utcnow() + timedelta(days=ttl_days)
|
||||||
|
|
||||||
acc = ChannelAccess(
|
acc = ChannelAccess(
|
||||||
@@ -94,12 +114,19 @@ async def confirm_invite(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
invite_id = acc.id
|
invite_id = acc.id
|
||||||
|
|
||||||
payload = f"sch_{invite_id}_{token}"
|
payload = f"sch_{invite_id}_{token}"
|
||||||
|
bot_username = await _get_bot_username(context)
|
||||||
|
deep_link = f"https://t.me/{bot_username}?start={payload}"
|
||||||
|
|
||||||
|
# Кнопка для удобства
|
||||||
|
kb = InlineKeyboardMarkup([[InlineKeyboardButton("Открыть ссылку", url=deep_link)]])
|
||||||
|
|
||||||
await q.edit_message_text(
|
await q.edit_message_text(
|
||||||
"Ссылка для выдачи доступа к каналу:\n"
|
"Ссылка для предоставления доступа к каналу:\n"
|
||||||
f"`https://t.me/<YOUR_BOT_USERNAME>?start={payload}`\n\n"
|
f"`{deep_link}`\n\n"
|
||||||
"Передайте её коллеге. Срок действия — "
|
"Передайте её коллеге. Срок действия — "
|
||||||
+ ("не ограничен." if ttl_days is None else f"{ttl_days} дней."),
|
+ ("не ограничен." if ttl_days is None else f"{ttl_days} дней."),
|
||||||
parse_mode="Markdown",
|
parse_mode="Markdown",
|
||||||
|
reply_markup=kb,
|
||||||
)
|
)
|
||||||
return ConversationHandler.END
|
return ConversationHandler.END
|
||||||
|
|
||||||
|
|||||||
10
main.py
10
main.py
@@ -99,6 +99,16 @@ from handlers.edit_button import edit_button
|
|||||||
from handlers.del_button import del_button
|
from handlers.del_button import del_button
|
||||||
from handlers.share_channel import share_channel_conv
|
from handlers.share_channel import share_channel_conv
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from telegram.error import BadRequest
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
async def on_error(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
err = context.error
|
||||||
|
# подавляем шумные 400-е, когда контент/markup не меняется
|
||||||
|
if isinstance(err, BadRequest) and "Message is not modified" in str(err):
|
||||||
|
return
|
||||||
|
logger.exception("Unhandled exception", exc_info=err)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user