Select Git revision
__init__.py
-
Martin Mareš authoredMartin Mareš authored
org_score.py 7.64 KiB
from flask import render_template, request, g
from flask.helpers import url_for
from typing import List, Optional
import werkzeug.exceptions
import mo
import mo.db as db
from mo.rights import Right
from mo.score import Score
from mo.web import app
from mo.web.table import Cell, CellLink, Column, Row, Table, cell_pion_link
class OrderCell(Cell):
place: int
span: int
continuation: bool
def __init__(self, place: int, span: int = 1, continuation: bool = False):
self.place = place
self.span = span
self.continuation = continuation
def __str__(self) -> str:
if self.span == 1:
return f"{self.place}."
else:
return f"{self.place}.–{self.place + self.span - 1}."
def to_html(self) -> str:
if self.continuation:
return "" # covered by rowspan cell above this one
elif self.span == 1:
return f"<td>{self.__str__()}"
else:
return f"<td rowspan='{self.span}'>{self.__str__()}"
class SolPointsCell(Cell):
contest_id: int
user: db.User
sol: Optional[db.Solution]
def __init__(self, contest_id: int, user: db.User, sol: db.Solution):
self.contest_id = contest_id
self.user = user
self.sol = sol
def __str__(self) -> str:
if not self.sol:
return '–'
elif self.sol.points is None:
return '?'
return str(self.sol.points)
def to_html(self) -> str:
if not self.sol:
return '<td>–'
elif self.sol.points is None:
points = '<span class="unknown">?</span></a>'
else:
points = str(self.sol.points)
if self.sol.final_feedback_obj:
url = mo.web.util.org_paper_link(self.contest_id, None, self.user, self.sol.final_feedback_obj)
return f'<td><a href="{url}" title="Zobrazit finální opravu">{points}</a>'
elif self.sol.final_submit_obj:
url = mo.web.util.org_paper_link(self.contest_id, None, self.user, self.sol.final_submit_obj)
return f'<td><a href="{url}" title="Zobrazit finální řešení od účastníka">{points}</a>'
else:
return f'<td>{points}' # no paper no link
@app.route('/org/contest/r/<int:round_id>/score')
@app.route('/org/contest/c/<int:contest_id>/score')
def org_score(round_id: Optional[int] = None, contest_id: Optional[int] = None):
if round_id is None and contest_id is None:
raise werkzeug.exceptions.BadRequest()
if round_id is not None and contest_id is not None:
raise werkzeug.exceptions.BadRequest()
format = request.args.get('format', "")
sess = db.get_session()
if round_id:
contest = None
round = sess.query(db.Round).get(round_id)
if not round:
raise werkzeug.exceptions.NotFound()
rr = g.gatekeeper.rights_for_round(round, True)
else:
contest = sess.query(db.Contest).get(contest_id)
if not contest:
raise werkzeug.exceptions.NotFound()
round = contest.round
rr = g.gatekeeper.rights_for_contest(contest)
if not rr.have_right(Right.view_submits):
raise werkzeug.exceptions.Forbidden()
score = Score(round, contest)
tasks = score.get_tasks()
results = score.get_sorted_results()
messages = score.get_messages()
# Pro tvorbu odkazů na správné contesty ve výsledkovkách dělených kol
all_subcontests: List[db.Contest] = sess.query(db.Contest).filter(
db.Contest.round_id.in_(
sess.query(db.Round.round_id).filter_by(master_round_id=round.master_round_id)
)
).all()
subcontest_id_map = {}
for subcontest in all_subcontests:
subcontest_id_map[(subcontest.round_id, subcontest.master_contest_id)] = subcontest.contest_id
# Construct columns
is_export = (format != "")
columns = []
columns.append(Column(key='order', name='poradi', title='Pořadí'))
if is_export:
columns.append(Column(key='winner', name='vitez'))
columns.append(Column(key='successful', name='uspesny_resitel'))
columns.append(Column(key='participant', name='ucastnik', title='Účastník'))
if is_export:
columns.append(Column(key='email', name='email'))
if not contest_id:
columns.append(Column(key='contest', name='oblast', title='Soutěžní oblast'))
if is_export:
columns.append(Column(key='pion_place', name='soutezni_misto'))
columns.append(Column(key='school', name='skola', title='Škola'))
columns.append(Column(key='grade', name='rocnik', title='Ročník'))
if is_export:
columns.append(Column(key='birth_year', name='rok_narozeni'))
for task in tasks:
title = task.code
if contest_id:
local_ct_id = subcontest_id_map[(task.round_id, contest.master_contest_id)]
title = '<a href="{}">{}</a>'.format(
url_for('org_contest_task', contest_id=local_ct_id, task_id=task.task_id),
task.code
)
if rr.can_edit_points(round):
title += ' <a href="{}" title="Editovat body" class="icon">✎</a>'.format(
url_for('org_contest_task_points', contest_id=local_ct_id, task_id=task.task_id),
)
columns.append(Column(key=f'task_{task.task_id}', name=task.code, title=title))
columns.append(Column(key='total_points', name='celkove_body', title='Celkové body'))
# columns.append(Column(key='order_key', name='order_key', title='Třídící klíč'))
# Construct rows
table_rows = []
for result in results:
user, pant, pion = result.user, result.pant, result.pion
school = pant.school_place
local_pion_ct_id = subcontest_id_map[(round.round_id, pion.contest_id)]
row = Row(keys={
'order': OrderCell(result.order.place, result.order.span, result.order.continuation),
'winner': 'ano' if result.winner else '',
'successful': 'ano' if result.successful else '',
'user': user,
'email': user.email,
'participant': cell_pion_link(user, local_pion_ct_id, user.full_name()),
'contest': CellLink(pion.contest.place.name, url_for('org_contest', id=pion.contest_id)),
'pion_place': pion.place.name,
'school': CellLink(school.name, url_for('org_place', id=school.place_id)),
'grade': pant.grade,
'total_points': result.get_total_points(),
'birth_year': pant.birth_year,
'order_key': result._order_key,
})
sols = result.get_sols_map()
for task in tasks:
local_sol_ct_id = subcontest_id_map[(task.round_id, pion.contest_id)]
row.keys[f'task_{task.task_id}'] = SolPointsCell(
contest_id=local_sol_ct_id, user=user, sol=sols.get(task.task_id)
)
if result.winner:
row.html_attr = {"class": "winner", "title": "Vítěz"}
elif result.successful:
row.html_attr = {"class": "successful", "title": "Úspěšný řešitel"}
table_rows.append(row)
filename = f"vysledky_{round.year}-{round.category}-{round.level}"
if contest_id:
filename += f"_oblast_{contest.place.code or contest.place.place_id}"
table = Table(
table_class="data full center",
columns=columns,
rows=table_rows,
filename=filename,
)
if format == "":
return render_template(
'org_score.html',
contest=contest, round=round, tasks=tasks,
table=table, messages=messages,
)
else:
return table.send_as(format)