# Rozesílání e-mailových notifikací všeho druhu import datetime import email.message import email.headerregistry import subprocess import textwrap import urllib.parse import mo.db as db import mo.config as config from mo.util import logger def send_user_email(user: db.User, subject: str, body: str) -> bool: logger.info(f'Mail: "{subject}" -> {user.email}') mail_from = getattr(config, 'MAIL_FROM', None) if mail_from is None: logger.error('Mail: V configu chybí nastavení MAIL_FROM') return False msg = email.message.EmailMessage() msg['From'] = email.headerregistry.Address( display_name='Odevzdávací Systém MO', addr_spec=mail_from, ) msg['To'] = [ email.headerregistry.Address( display_name=user.full_name(), addr_spec=user.email, ) ] msg['Reply-To'] = email.headerregistry.Address( display_name='Správce OSMO', addr_spec=config.MAIL_CONTACT, ) msg['Subject'] = 'OSMO – ' + subject msg['Date'] = datetime.datetime.now() msg.set_content(body, cte='quoted-printable') mail_instead = getattr(config, 'MAIL_INSTEAD', None) if mail_instead is None: send_to = user.email else: send_to = mail_instead sm = subprocess.Popen( [ '/usr/sbin/sendmail', '-oi', '-f', mail_from, send_to, ], stdin=subprocess.PIPE, ) sm.communicate(msg.as_bytes()) if sm.returncode != 0: logger.error('Mail: Sendmail failed with return code {}'.format(sm.returncode)) return False return True def activate_url(token: str) -> str: return config.WEB_ROOT + 'acct/activate?' + urllib.parse.urlencode({'token': token}, safe=':') def confirm_url(type: str, token: str) -> str: return config.WEB_ROOT + f'acct/confirm/{type}?' + urllib.parse.urlencode({'token': token}, safe=':') def contestant_list_url(contest: db.Contest, registered_only: bool) -> str: url = config.WEB_ROOT + f'org/contest/c/{contest.contest_id}/ucastnici' if registered_only: url += '?participation_state=registered' return url def send_new_account_email(user: db.User, token: str) -> bool: return send_user_email(user, 'Založen nový účet', textwrap.dedent('''\ Vítejte! Právě Vám byl založen účet v Odevzdávacím systému Matematické olympiády. Nastavte si prosím heslo na následující stránce: {} Váš OSMO '''.format(activate_url(token)))) def send_password_reset_email(user: db.User, token: str) -> bool: return send_user_email(user, 'Obnova hesla', textwrap.dedent('''\ Někdo (pravděpodobně Vy) požádal o obnovení hesla k Vašemu účtu v Odevzdávacím systému Matematické olympiády. Heslo si můžete nastavit, případně požadavek zrušit, na následující stránce: {} Váš OSMO '''.format(confirm_url('p', token)))) def send_confirm_create_email(user: db.User, token: str) -> bool: return send_user_email(user, 'Založení účtu', textwrap.dedent('''\ Někdo (pravděpodobně Vy) požádal o založení účtu s touto e-mailovou adresou v Odevzdávacím systému Matematické olympiády. Pokud účet chcete založit, následujte tento odkaz: {} Váš OSMO '''.format(confirm_url('r', token)))) def send_confirm_change_email(user: db.User, token: str) -> bool: return send_user_email(user, 'Změna e-mailové adresy', textwrap.dedent('''\ Někdo (pravděpodobně Vy) požádal o nastavení e-mailové adresy k účtu v Odevzdávacím systému Matematické olympiády na tuto adresu. Pokud změnu chcete provést, následujte tento odkaz: {} Váš OSMO '''.format(confirm_url('e', token)))) def send_join_notify_email(dest: db.User, who: db.User, contest: db.Contest) -> bool: round = contest.round place = contest.place if contest.round.enroll_mode == db.RoundEnrollMode.confirm: confirm = 'Přihlášku je potřeba potvrdit v seznamu účastníků soutěže.' url = 'Přihlášky k potvrzení: ' + contestant_list_url(contest, True) else: confirm = 'Přihláška byla schválena automaticky.' url = 'Seznam účastníků: ' + contestant_list_url(contest, False) return send_user_email(dest, f'Nový účastník kategorie {round.category}', textwrap.dedent(f'''\ Nový účastník se přihlásil do MO v oblasti, kterou garantujete. Jméno: {who.full_name()} E-mail: {who.email} Kategorie: {round.category} Kolo: {round.name} Místo: {place.name} {confirm} {url} Váš OSMO '''))