Skip to content
Snippets Groups Projects

Sazba diplomů

Merged Martin Mareš requested to merge diplomy into devel
Compare and Show latest version
7 files
+ 55
25
Compare changes
  • Side-by-side
  • Inline

Files

+ 31
13
# Implementace jobů na posílání notifikací
# Implementace jobů na posílání notifikací při změně stavu soutěže
from enum import Enum, auto
from collections import defaultdict
from dataclasses import dataclass
from sqlalchemy import and_
from sqlalchemy.orm import joinedload
from typing import Optional, List, Tuple, Set, DefaultDict, Callable, Dict
from typing import Optional, List, Set, DefaultDict, Callable, Dict
import mo.db as db
import mo.email
@@ -34,6 +34,9 @@ def schedule_send_grading_info(round: db.Round, contests: Optional[List[db.Conte
if new_state not in [db.RoundState.graded, db.RoundState.closed]:
return False
if round.is_subround():
return False
the_job = TheJob()
job = the_job.create(db.JobType.send_grading_info, for_user)
job.description = f'E-maily účastníkům {round.round_code_short()}'
@@ -103,7 +106,7 @@ class NotifyStats:
if self.num_before > 0:
stats.append(inflect_number(self.num_before, 'odeslána', 'odeslány', 'odesláno') + ' dříve')
if self.num_skipped > 0:
stats.append(inflect_number(self.num_skipped, 'prázdný', 'prázdné', 'prázdných') + ' vynecháno')
stats.append(inflect_number(self.num_skipped, 'prázdná vynechána', 'prázdné vynechány', 'prázdných vynecháno'))
if self.num_dont_want > 0:
stats.append(inflect_number(self.num_dont_want, 'nechce', 'nechtějí', 'nechce'))
if self.num_failed > 0:
@@ -117,6 +120,7 @@ class Notifier:
round: db.Round
contest: db.Contest
new_state: db.RoundState
notify_teachers: bool
ct_notifies: Dict[int, NotifyUser]
teacher_notifies: Dict[int, NotifyUser]
@@ -129,14 +133,17 @@ class Notifier:
self.round = round
self.contest = contest
self.new_state = new_state
logger.debug(f'{self.the_job.log_prefix} Notifikace pro soutěž #{contest.contest_id} ({contest.place.name}), stav={new_state.name}')
self.notify_teachers = new_state == db.RoundState.closed and round.level < 4
logger.debug(f'{self.the_job.log_prefix} Notifikace pro soutěž #{contest.contest_id} ({contest.place.name}), stav={new_state.name} teachers={self.notify_teachers}')
def run(self) -> None:
self.load_users()
self.find_topics()
self.find_teachers() # FIXME: Jen někdy
if self.notify_teachers:
self.find_teachers()
self.ct_stats = self.notify(notifies=self.ct_notifies, email_key=f'{self.new_state.name}:{self.round.round_id}', sender=self.notify_contestant)
self.teacher_stats = self.notify(notifies=self.teacher_notifies, email_key=f't-{self.new_state.name}:{self.round.round_id}', sender=self.notify_teacher)
if self.notify_teachers:
self.teacher_stats = self.notify(notifies=self.teacher_notifies, email_key=f't-{self.new_state.name}:{self.round.round_id}', sender=self.notify_teacher)
def load_users(self) -> None:
sess = db.get_session()
@@ -156,7 +163,8 @@ class Notifier:
# Body a opravená řešení
sq = (sess.query(db.Solution)
.join(db.Task, db.Task.task_id == db.Solution.task_id)
.filter(db.Task.round_id == self.round.round_id,
.join(db.Round, db.Round.master_round_id == self.round.round_id)
.filter(db.Task.round_id == db.Round.round_id,
db.Solution.user_id.in_(self.ct_notifies.keys())))
for sol in sq.all():
nu = self.ct_notifies[sol.user_id]
@@ -199,6 +207,8 @@ class Notifier:
def notify(self, notifies: Dict[int, NotifyUser], email_key: str, sender: Callable[[NotifyUser], Optional[bool]]) -> NotifyStats:
stats = NotifyStats()
sess = db.get_session()
# Podobně jako u importů i zde budeme vytvářet malé transakce
sess.commit()
for nu in notifies.values():
@@ -241,7 +251,15 @@ class Notifier:
return None
items = [topic_to_item[topic] for topic in sorted(nu.topics, key=lambda topic: topic.value)]
return mo.email.send_grading_info_email(nu.user, self.round, self.contest, is_teacher, items)
return mo.email.send_grading_info_email(
dest=nu.user,
round=self.round,
contest=self.contest,
is_teacher=is_teacher,
new_state=self.new_state,
items=items,
)
@job_handler(db.JobType.send_grading_info)
@@ -256,8 +274,6 @@ def handle_send_grading_info(the_job: TheJob):
contest_ids = [x.as_int() for x in w['contest_ids'].array_values()]
new_state = db.RoundState[w['new_state'].as_str()]
# FIXME: Co když to někdo zavolá na sekundární kolo?
sess = db.get_session()
round = sess.query(db.Round).get(round_id)
if not round:
@@ -266,7 +282,7 @@ def handle_send_grading_info(the_job: TheJob):
ct_q = sess.query(db.Contest)
if contest_ids is None:
ct_q = ct_q.filter(db.Contest.round_id == round.master_round_id)
ct_q = ct_q.filter(db.Contest.round_id == round.round_id)
else:
ct_q = ct_q.filter(db.Contest.contest_id.in_(contest_ids))
ct_q = ct_q.options(joinedload(db.Contest.place))
@@ -280,7 +296,9 @@ def handle_send_grading_info(the_job: TheJob):
n = Notifier(the_job, round, ct, new_state)
n.run()
ct_stats.merge_from(n.ct_stats)
teacher_stats.merge_from(n.teacher_stats)
if n.notify_teachers:
teacher_stats.merge_from(n.teacher_stats)
job.result = ct_stats.format(is_teacher=False)
job.result += ', ' + teacher_stats.format(is_teacher=True)
if teacher_stats.num_total > 0:
job.result += ', ' + teacher_stats.format(is_teacher=True)
Loading