sharing channels and more
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2025-09-06 14:56:46 +09:00
parent 18f91bbd40
commit 506acfcde5
2 changed files with 52 additions and 15 deletions

View File

@@ -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,14 +114,21 @@ 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}"
await q.edit_message_text( bot_username = await _get_bot_username(context)
"Ссылка для выдачи доступа к каналу:\n" deep_link = f"https://t.me/{bot_username}?start={payload}"
f"`https://t.me/<YOUR_BOT_USERNAME>?start={payload}`\n\n"
"Передайте её коллеге. Срок действия — " # Кнопка для удобства
+ ("не ограничен." if ttl_days is None else f"{ttl_days} дней."), kb = InlineKeyboardMarkup([[InlineKeyboardButton("Открыть ссылку", url=deep_link)]])
parse_mode="Markdown",
) await q.edit_message_text(
return ConversationHandler.END "Ссылка для предоставления доступа к каналу:\n"
f"`{deep_link}`\n\n"
"Передайте её коллеге. Срок действия — "
+ ("не ограничен." if ttl_days is None else f"{ttl_days} дней."),
parse_mode="Markdown",
reply_markup=kb,
)
return ConversationHandler.END
share_channel_conv = ConversationHandler( share_channel_conv = ConversationHandler(
entry_points=[CommandHandler("share_channel", share_channel_start)], entry_points=[CommandHandler("share_channel", share_channel_start)],

12
main.py
View File

@@ -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)
@@ -130,7 +140,7 @@ def main():
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop) asyncio.set_event_loop(loop)
application.run_polling() application.run_polling()
if __name__ == "__main__": if __name__ == "__main__":
main() main()