From 57c70632ef7f528fe2ae6b358cbc4d1565213a1b Mon Sep 17 00:00:00 2001
From: Martin Mares <mj@ucw.cz>
Date: Sat, 25 Sep 2021 15:43:48 +0200
Subject: [PATCH] =?UTF-8?q?Hierarchie:=20Organiz=C3=A1torsk=C3=A1=20hlavn?=
 =?UTF-8?q?=C3=AD=20str=C3=A1nka?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Kromě soutěží odkazuje i na hierarchické stránky kol, pokud jsem
garant vyšší úrovně, než je úroveň kola.
---
 mo/web/org.py                   | 61 ++++++++++++++++++---------------
 mo/web/templates/org_index.html | 36 ++++++++++++-------
 2 files changed, 58 insertions(+), 39 deletions(-)

diff --git a/mo/web/org.py b/mo/web/org.py
index a07d6261..4830309a 100644
--- a/mo/web/org.py
+++ b/mo/web/org.py
@@ -1,7 +1,8 @@
+from dataclasses import dataclass, field
 from flask import render_template, redirect, url_for, request, flash, g
 from sqlalchemy import and_, or_
 from sqlalchemy.orm import aliased, joinedload
-from typing import List, Set, Dict
+from typing import List, Set, Optional
 
 import mo.config as config
 import mo.db as db
@@ -12,6 +13,15 @@ from mo.web.jinja import user_url
 from mo.web.table import Table, Row, Column
 
 
+@dataclass
+class OrgOverview:
+    round: db.Round
+    place: db.Place
+    contest: Optional[db.Contest]
+    role_set: Set[db.RoleType] = field(default_factory=set)
+    role_list: List[db.RoleType] = field(default_factory=list)
+
+
 @app.route('/org/')
 def org_index():
     if 'place' in request.args:
@@ -33,36 +43,33 @@ def org_index():
             flash('ID uživatele musí být číslo', 'danger')
 
     sess = db.get_session()
-    ctr = (sess.query(db.Contest, db.UserRole)
-               .select_from(db.UserRole, db.Round, db.Contest)
-               .filter(and_(db.UserRole.user_id == g.user.user_id,
-                            or_(db.UserRole.category == None, db.UserRole.category == db.Round.category),
-                            or_(db.UserRole.year == None, db.UserRole.year == db.Round.year),
-                            or_(db.UserRole.seq == None, db.UserRole.seq == db.Round.seq),
-                            db.Round.year == config.CURRENT_YEAR,
-                            db.Contest.round_id == db.Round.round_id,
-                            db.Contest.place_id == db.UserRole.place_id))
-               .options(joinedload(db.Contest.place))
+    rcu = (sess.query(db.Round, db.Contest, db.UserRole)
+               .select_from(db.UserRole)
+               .join(db.Place)
+               .join(db.Round, and_(db.UserRole.user_id == g.user.user_id,
+                    or_(db.UserRole.category == None, db.UserRole.category == db.Round.category),
+                    or_(db.UserRole.year == None, db.UserRole.year == db.Round.year),
+                    or_(db.UserRole.seq == None, db.UserRole.seq == db.Round.seq),
+                    db.Place.level <= db.Round.level))
+               .outerjoin(db.Contest, and_(db.Contest.round_id == db.Round.round_id, db.Contest.place_id == db.UserRole.place_id))
+               .filter(db.Round.year == config.CURRENT_YEAR)
+               .options(joinedload(db.UserRole.place))
                .order_by(db.Round.level, db.Round.category, db.Round.seq, db.Round.part,
                          db.Contest.place_id, db.Contest.contest_id)
                .all())
 
-    # Pokud máme pro jednu soutěž více rolí, zkombinujeme je
-    contests: List[db.Contest] = []
-    contest_role_sets: Dict[db.Contest, Set[db.RoleType]] = {}
-    for ct, ur in ctr:
-        if len(contests) == 0 or contests[-1] != ct:
-            contests.append(ct)
-            contest_role_sets[ct.contest_id] = set()
-        contest_role_sets[ct.contest_id].add(ur.role)
-
-    # Role pro každou soutěž setřídíme podle důležitosti
-    contest_roles: Dict[db.Contest, List[db.RoleType]] = {
-        ct_id: sorted(list(contest_role_sets[ct_id]), key=lambda r: mo.rights.role_order_by_type[r])
-        for ct_id in contest_role_sets.keys()
-    }
-
-    return render_template('org_index.html', contests=contests, contest_roles=contest_roles, role_type_names=db.role_type_names)
+    overview: List[OrgOverview] = []
+    for r, ct, ur in rcu:
+        o = overview[-1] if overview else None
+        if not (o and o.round == r and o.place == ur.place):
+            o = OrgOverview(round=r, place=ur.place, contest=ct)
+            overview.append(o)
+        o.role_set.add(ur.role)
+
+    for o in overview:
+        o.role_list = sorted(o.role_set, key=lambda r: mo.rights.role_order_by_type[r])
+
+    return render_template('org_index.html', overview=overview, role_type_names=db.role_type_names)
 
 
 school_export_columns = (
diff --git a/mo/web/templates/org_index.html b/mo/web/templates/org_index.html
index 40cc4eac..8436ddc6 100644
--- a/mo/web/templates/org_index.html
+++ b/mo/web/templates/org_index.html
@@ -2,34 +2,46 @@
 {% block title %}Organizátorské rozhraní{% endblock %}
 {% block body %}
 
-{% if contests %}
+{% if overview %}
 
 <h3>Moje soutěže</h3>
 <table class="table table-bordered table-condensed greyhead">
 {% set curr = namespace(level=-1) %}
-	{% for c in contests %}
-		{% if curr.level != c.round.level %}
+	{% for o in overview %}
+		{% if curr.level != o.round.level %}
 		<thead><tr>
 			<th>ID
 			<th>Kategorie
 			<th>Kolo
-			<th>{{ c.round.get_level().name|capitalize }}
+			<th>{{ o.round.get_level().name|capitalize }}
 			<th>Stav
 			<th>Moje role
 			<th>Odkazy
 		</thead>
-		{% set curr.level = c.round.level %}
+		{% set curr.level = o.round.level %}
+		{% endif %}
+
+		{% if o.contest %}
+			{% set detail_url = url_for('org_contest', ct_id=o.contest.contest_id) %}
+		{% elif o.place.level == 0 %}
+			{% set detail_url = url_for('org_round', round_id=o.round.round_id) %}
+		{% else %}
+			{% set detail_url = url_for('org_round', round_id=o.round.round_id, hier_id=o.place.place_id) %}
 		{% endif %}
 
 		<tr>
-			<td><a href='{{ url_for('org_contest', ct_id=c.contest_id) }}'>{{ c.round.round_code() }}</a>
-			<td class="text-center"><b>{{ c.round.category }}</b>
-			<td>{{ c.round.name }}
-			<td>{{ c.place.name }}
-			<td class="rstate-{{c.state.name}}">{{ c.state.friendly_name() }}
-			<td>{% for r in contest_roles[c.contest_id] %}{{ role_type_names[r] }}{% if not loop.last %}<br>{% endif %}{% endfor %}
+			<td><a href='{{ detail_url }}'>{{ o.round.round_code() }}</a>
+			<td class="text-center"><b>{{ o.round.category }}</b>
+			<td>{{ o.round.name }}
+		{% if o.contest %}
+			<td>{{ o.place.name }}
+			<td class="rstate-{{o.contest.state.name}}">{{ o.contest.state.friendly_name() }}
+		{% else %}
+			<td><i>{{ o.place.name_locative() }}</i>
 			<td>
-				<a class="btn btn-xs btn-primary" href='{{ url_for('org_contest', ct_id=c.contest_id) }}'>Detail</a>
+		{% endif %}
+			<td>{% for r in o.role_list %}{{ role_type_names[r] }}{% if not loop.last %}<br>{% endif %}{% endfor %}
+			<td><a class="btn btn-xs btn-primary" href='{{ detail_url }}'>Detail</a>
 	{% endfor %}
 </table>
 
-- 
GitLab