Dbu-central-bot / app /bot /delivery.py
cipher-attacks's picture
track join-step blocker
d925e38
Raw History Blame Contribute Delete
3.28 kB
"""Sending things to a student from anywhere (button, deep link, after onboarding)."""
import logging
from aiogram import Bot
from aiogram.exceptions import TelegramBadRequest
from sqlalchemy.ext.asyncio import AsyncSession
from app.bot.keyboards import library as lib_kb
from app.bot.keyboards.common import share_kb
from app.core import season
from app.core.i18n import t
from app.db.models import ActivityEvent, Material, User
from app.db.repos import library as repo
from app.services import growth
from app.services import library as lib
from app.services import xp as xp_service
log = logging.getLogger(__name__)
async def _maybe_ask_to_share(bot: Bot, user: User, chat_id: int) -> None:
"""At the moment a student just got something useful, suggest sharing: at most once a day,
never on their first day."""
today = season.day_key()
if (user.active_days or 0) < 2 or user.share_prompt_day == today:
return
user.share_prompt_day = today
me = await bot.me()
link = growth.deep_link(me.username, str(user.id)) # their personal referral link
url = growth.share_url(link, t(user.lang, "share_text"))
try:
await bot.send_message(chat_id, t(user.lang, "share_prompt"), reply_markup=share_kb(user.lang, url))
except Exception as exc:
log.info("Could not send the share nudge: %r", exc)
async def deliver_material(bot: Bot, session: AsyncSession, user: User, material: Material, chat_id: int) -> bool:
course = await repo.get_course(session, material.course_id) if material.course_id else None
try:
await lib.send_material(bot, chat_id, material, course)
except TelegramBadRequest:
return False
material.downloads = (material.downloads or 0) + 1
session.add(ActivityEvent(user_id=user.id, kind="download", ref=str(material.id), n=1))
res = await xp_service.award(session, user, "download", 1, ref=f"{material.id}:{season.day_key()}")
if res.leveled_up:
await xp_service.announce_level(bot, user, res.new_level)
await _maybe_ask_to_share(bot, user, chat_id)
return True
async def deliver_link(bot: Bot, session: AsyncSession, user: User, chat_id: int, kind: str, value: str) -> bool:
"""Open what a shared link points at (a course or one file). False = nothing to show."""
if kind == "course":
course, counts = await lib.kinds_of(session, int(value))
if course and any(counts.values()):
await bot.send_message(
chat_id, t(user.lang, "lib_kinds", course=course.name), reply_markup=lib_kb.kinds(user.lang, course.id, counts)
)
return True
elif kind == "file":
material = await repo.get_material(session, int(value))
if material and material.file_id and material.status == "ok":
return await deliver_material(bot, session, user, material, chat_id)
return False
async def deliver_pending(bot: Bot, session: AsyncSession, user: User, chat_id: int) -> None:
"""The link someone opened before they had joined / finished onboarding."""
if not user.pending_link:
return
kind, value = growth.parse_start_payload(user.pending_link)
user.pending_link = None
await deliver_link(bot, session, user, chat_id, kind, value)