Python 64.6%
TypeScript 33.7%
CSS 0.8%
1"""Account activation and password recovery by e-mail.23- Invitation: the professor adds an address → a "choose your password" link (INVITE_TTL_DAYS).4- Forgot / first login: the student asks for a link from the sign-in page (RESET_TTL_MINUTES).5Both land on /mot-de-passe?token=… where the password is chosen and the session opened.6"""78from __future__ import annotations910from app.core.config import Settings11from app.models import User12from app.services import mail, users131415def password_link(settings: Settings, token: str) -> str:16 return f"{settings.APP_URL}/mot-de-passe?token={token}"171819async def invite_users(targets: list[User], settings: Settings) -> dict:20 """Create one invitation token per user, e-mail them (batch) and stamp invited_at."""21 if not targets:22 return {"sent": [], "failed": [], "links": {}}23 mails: list[mail.Mail] = []24 links: dict[str, str] = {}25 for u in targets:26 token = await users.create_magic_link(u.email, ttl_minutes=settings.INVITE_TTL_DAYS * 24 * 60,27 purpose="invite")28 link = password_link(settings, token)29 links[u.id] = link30 mails.append(mail.invitation_mail(u.email, link, u.display_name, settings.INVITE_TTL_DAYS,31 settings.TERM_LABEL))32 outcome = await mail.send_batch(settings, mails) if settings.mail_enabled else {}33 sent = [u for u in targets if outcome.get(u.email)]34 failed = [u for u in targets if not outcome.get(u.email)]35 await users.mark_invited([u.id for u in sent])36 return {"sent": [u.email for u in sent], "failed": [u.email for u in failed], "links": links}373839async def send_password_link(user: User, settings: Settings) -> tuple[bool, str]:40 """Forgot-password / first-login link. Returns (sent, link)."""41 first_time = not user.password_hash42 token = await users.create_magic_link(user.email, ttl_minutes=settings.RESET_TTL_MINUTES,43 purpose="reset")44 link = password_link(settings, token)45 sent = await mail.send(settings, mail.reset_mail(user.email, link, settings.RESET_TTL_MINUTES,46 first_time))47 return sent, link48