Skip to content
Snippets Groups Projects
Select Git revision
  • 7c24a7ec71afb469aa63c634a70007822ff69b1f
  • devel default
  • master
  • fo
  • jirka/typing
  • fo-base
  • mj/submit-images
  • jk/issue-96
  • jk/issue-196
  • honza/add-contestant
  • honza/mr7
  • honza/mrf
  • honza/mrd
  • honza/mra
  • honza/mr6
  • honza/submit-images
  • honza/kolo-vs-soutez
  • jh-stress-test-wip
  • shorten-schools
19 results

org_score.py

Blame
    • Jiří Setnička's avatar
      7c24a7ec
      Výsledková listina upravena pro dělená kola · 7c24a7ec
      Jiří Setnička authored
      Pro dělená kola výsledkovka agreguje všechny úlohy z kol ve skupině.
      
      Při zobrazení na webu je potřeba správně odkazovat na patřičné contesty:
      * Proklik na účastníky zůstává ve stejném kole
      * Proklik na záhlaví úlohy může vést i do jiného kola skupiny
      * Proklik na submit může vést i do jiného kola skupiny
      
      Issue #178
      7c24a7ec
      History
      Výsledková listina upravena pro dělená kola
      Jiří Setnička authored
      Pro dělená kola výsledkovka agreguje všechny úlohy z kol ve skupině.
      
      Při zobrazení na webu je potřeba správně odkazovat na patřičné contesty:
      * Proklik na účastníky zůstává ve stejném kole
      * Proklik na záhlaví úlohy může vést i do jiného kola skupiny
      * Proklik na submit může vést i do jiného kola skupiny
      
      Issue #178
    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)