From e5dcd6008c2ad0d11ec3041428f79cb1acc5bf76 Mon Sep 17 00:00:00 2001
From: Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz>
Date: Thu, 1 Jul 2021 23:24:16 +0200
Subject: [PATCH] =?UTF-8?q?Pokus=20o=20barven=C3=AD=20neaktivn=C3=ADch=20?=
 =?UTF-8?q?=C3=BA=C4=8Dt=C5=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 mo/db.py                                      |  3 ++
 mo/web/jinja.py                               |  6 +++
 mo/web/org_contest.py                         |  7 ++-
 mo/web/templates/org_contest_solutions.html   |  2 +-
 mo/web/templates/org_orgs.html                |  4 +-
 mo/web/templates/org_users.html               |  4 +-
 .../templates/parts/org_solution_table.html   |  2 +-
 mo/web/util.py                                | 17 +++++++
 static/mo.css                                 | 47 ++++++++++++++++---
 9 files changed, 76 insertions(+), 16 deletions(-)

diff --git a/mo/db.py b/mo/db.py
index 429a9302..b056e2f7 100644
--- a/mo/db.py
+++ b/mo/db.py
@@ -303,6 +303,9 @@ class User(Base):
     def name_sort_key(self) -> Tuple[str, str]:
         return (locale.strxfrm(self.last_name), locale.strxfrm(self.first_name))
 
+    def is_inactive(self) -> bool:
+        return self.password_hash == None
+
 
 class Contest(Base):
     __tablename__ = 'contests'
diff --git a/mo/web/jinja.py b/mo/web/jinja.py
index 59c744f1..760270c5 100644
--- a/mo/web/jinja.py
+++ b/mo/web/jinja.py
@@ -13,6 +13,7 @@ import mo.util_format as util_format
 from mo.web import app
 from mo.web.org_contest import contest_breadcrumbs
 from mo.web.org_place import place_breadcrumbs
+from mo.web.util import user_table_row_title, user_table_row_class
 
 # Konfigurace Jinjy
 
@@ -22,6 +23,11 @@ app.jinja_env.trim_blocks = True
 
 # Filtry definované v mo.util_format
 
+app.jinja_env.filters.update(user_table_row_title=user_table_row_title)
+app.jinja_env.filters.update(user_table_row_class=user_table_row_class)
+
+# Filtry definované v mo.web.utils
+
 app.jinja_env.filters.update(timeformat=util_format.timeformat)
 app.jinja_env.filters.update(inflected=util_format.inflect_number)
 app.jinja_env.filters.update(inflected_by=util_format.inflect_by_number)
diff --git a/mo/web/org_contest.py b/mo/web/org_contest.py
index fdebce5c..e33255d6 100644
--- a/mo/web/org_contest.py
+++ b/mo/web/org_contest.py
@@ -25,11 +25,11 @@ from mo.util_format import inflect_number, inflect_by_number
 from mo.web import app
 import mo.web.util
 from mo.web.util import MODecimalField, PagerForm
+from mo.web.util import user_table_row_class, user_table_row_title
 from mo.web.table import CellCheckbox, Table, Row, Column, cell_pion_link, cell_place_link, cell_email_link
 import wtforms.validators as validators
 from wtforms.widgets.html5 import NumberInput
 
-
 class ImportForm(FlaskForm):
     file = flask_wtf.file.FileField("Soubor", render_kw={'autofocus': True})
     typ = wtforms.SelectField(
@@ -551,9 +551,8 @@ def make_contestant_table(query: Query, round: db.Round, add_checkbox: bool = Fa
         html_attr = {
             'class': 'state-' + pion.state.name
         }
-        if u.is_test:
-            html_attr['class'] += ' testuser'
-            html_attr['title'] = 'Testovací uživatel'
+        html_attr['class'] += ' ' + user_table_row_class(u)
+        html_attr['title'] = user_table_row_title(u)
         rows.append(Row(
             keys={
                 'sort_key': u.sort_key(),
diff --git a/mo/web/templates/org_contest_solutions.html b/mo/web/templates/org_contest_solutions.html
index 7bda4f7c..efe1a74c 100644
--- a/mo/web/templates/org_contest_solutions.html
+++ b/mo/web/templates/org_contest_solutions.html
@@ -61,7 +61,7 @@ konkrétní úlohu. Symbol <span class="icon">🗐</span> značí, že existuje
 	</thead>
 	{% for pion in pions %}
 	{% set u = pion.user %}
-	<tr class="state-{{ pion.state.name }}{% if u.is_test %} testuser{% endif %}" {% if u.is_test %}title="Testovací uživatel"{% endif %}>
+	<tr class="state-{{ pion.state.name }} {{ user|user_table_row_class }}" title="{{ user|user_table_row_title }}">
 		<th>{{ u|pion_link(contest.contest_id) }}
 		<td>{{ pion.state.friendly_name() }}
 		{% set sum_points = [] %}
diff --git a/mo/web/templates/org_orgs.html b/mo/web/templates/org_orgs.html
index 52d30633..7d02f146 100644
--- a/mo/web/templates/org_orgs.html
+++ b/mo/web/templates/org_orgs.html
@@ -49,9 +49,9 @@
 		</tr>
 	</thead>
 {% for user in users %}
-	<tr>
+	<tr class="{{ user|user_table_row_class }}" title="{{ user|user_table_row_title }}">
 		<td>{{ user.first_name }}</td><td>{{ user.last_name }}</td>
-		<td>{{ user.email|mailto }}{% if user.password_hash == None %}<span class="user-inactive" title='Účet dosud nebyl aktivován'> *</span>{% endif %}</td>
+		<td>{{ user.email|mailto }}</td>
 		<td>{% if user.is_admin %}správce{% elif user.roles|count == 0 %}<i>žádná role</i>{% else %}
 			<ul>
 			{% for role in user.roles %}
diff --git a/mo/web/templates/org_users.html b/mo/web/templates/org_users.html
index df46553b..df9f4930 100644
--- a/mo/web/templates/org_users.html
+++ b/mo/web/templates/org_users.html
@@ -73,9 +73,9 @@
 		</tr>
 	</thead>
 {% for user in users %}
-	<tr{% if user.is_test %} class="testuser" title="Testovací uživatel"{% endif %}>
+	<tr class="{{ user|user_table_row_class }}" title="{{ user|user_table_row_title }}">
 		<td>{{ user.first_name }}</td><td>{{ user.last_name }}</td>
-		<td>{{ user.email|mailto }}{% if user.password_hash == None %}<span class="user-inactive" title='Účet dosud nebyl aktivován'> *</span>{% endif %}</td>
+		<td>{{ user.email|mailto }}</td>
 		<td>{% if user.participants|count == 0 %}<i>v žádném ročníku</i>{% else %}
 			<ul>
 			{% for participant in user.participants %}
diff --git a/mo/web/templates/parts/org_solution_table.html b/mo/web/templates/parts/org_solution_table.html
index 6223a92c..001b2982 100644
--- a/mo/web/templates/parts/org_solution_table.html
+++ b/mo/web/templates/parts/org_solution_table.html
@@ -35,7 +35,7 @@ finální (ve výchozím stavu poslední nahrané).{% elif sc.allow_upload_solut
 	{% set u = for_user or obj.user %}
 	{% set task = for_task or obj %}
 	{% if for_task %}
-	<tr class="state-{{ obj.state.name }}{% if u.is_test %} testuser{% endif %}" {% if u.is_test %}title="Testovací uživatel"{% endif %}>
+	<tr class="state-{{ obj.state.name }} {{ user|user_table_row_class }}" title="{{ user|user_table_row_title }}">
 	{% else %}
 	<tr>
 	{% endif %}
diff --git a/mo/web/util.py b/mo/web/util.py
index 4f10a68d..c9cecb9d 100644
--- a/mo/web/util.py
+++ b/mo/web/util.py
@@ -145,3 +145,20 @@ class MODecimalField(DecimalField):
                 d /= 10
 
         return super(MODecimalField, self)._value()
+
+
+def user_table_row_title(u: db.User) -> str:
+    r = []
+    if u.is_test:
+        r.append("Testovací uživatel")
+    if u.is_inactive():
+        r.append("Účet dosud nebyl aktivován")
+    return " | ".join(r)
+
+def user_table_row_class(u: db.User) -> str:
+    r = ["user"]
+    if u.is_test:
+        r.append("test")
+    if u.is_inactive():
+        r.append("inactive")
+    return "-".join(r)
diff --git a/static/mo.css b/static/mo.css
index 2de94b23..6a406cc4 100644
--- a/static/mo.css
+++ b/static/mo.css
@@ -114,7 +114,27 @@ table.data td.sol-warn {
 	background-color: #ffaaaa;
 }
 
-table tr.testuser {
+table.data tr.user {
+	opacity: 0.7;
+	background: repeating-linear-gradient(
+		45deg,
+		white,
+		white 10px,
+		white 10px,
+		white 20px
+	);
+}
+table.data tr.user-inactive {
+	opacity: 0.7;
+	background: repeating-linear-gradient(
+		45deg,
+		#fcc,
+		#fcc 10px,
+		white 10px,
+		white 20px
+	);
+}
+table.data tr.testuser {
 	opacity: 0.7;
 	background: repeating-linear-gradient(
 		45deg,
@@ -124,6 +144,26 @@ table tr.testuser {
 		#ddd 20px
 	);
 }
+table.data tr.user-test {
+	opacity: 0.7;
+	background: repeating-linear-gradient(
+		45deg,
+		white,
+		white 10px,
+		#ddd 10px,
+		#ddd 20px
+	);
+}
+table.data tr.user-test-inactive {
+	opacity: 0.7;
+	background: repeating-linear-gradient(
+		45deg,
+		#fcc,
+		#fcc 10px,
+		#ddd 10px,
+		#ddd 20px
+	);
+}
 table tr.state-disqualified, table tr.state-disqualified a:not(.btn) {
 	color: red;
 }
@@ -254,11 +294,6 @@ table.data tbody tr.job-failed:hover {
 	background-color: #a66;
 }
 
-/* Users */
-
-.user-inactive {
-	color: red;
-}
 
 /* Alerts */
 
-- 
GitLab