mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2024-11-26 23:27:08 +00:00
Compare commits
2 Commits
696863f6c3
...
620bbe7817
Author | SHA1 | Date | |
---|---|---|---|
|
620bbe7817 | ||
|
12205f953b |
@ -416,7 +416,7 @@ class Pool(models.Model):
|
||||
passage_pool = pool2
|
||||
passage_position = 1 + i // 2
|
||||
|
||||
defender = tds[line[0]].participation
|
||||
reporter = tds[line[0]].participation
|
||||
opponent = tds[line[1]].participation
|
||||
reviewer = tds[line[2]].participation
|
||||
observer = tds[line[3]].participation if self.size >= 4 and settings.TFJM_APP == "ETEAM" else None
|
||||
@ -426,11 +426,11 @@ class Pool(models.Model):
|
||||
pool=passage_pool,
|
||||
position=passage_position,
|
||||
solution_number=tds[line[0]].accepted,
|
||||
defender=defender,
|
||||
reporter=reporter,
|
||||
opponent=opponent,
|
||||
reviewer=reviewer,
|
||||
observer=observer,
|
||||
defender_penalties=tds[line[0]].penalty_int,
|
||||
reporter_penalties=tds[line[0]].penalty_int,
|
||||
)
|
||||
|
||||
# Update Google Sheets
|
||||
@ -549,7 +549,7 @@ class TeamDraw(models.Model):
|
||||
@property
|
||||
def penalty(self):
|
||||
"""
|
||||
The penalty multiplier on the defender oral, in percentage, which is a malus of 25% for each penalty.
|
||||
The penalty multiplier on the reporter oral, in percentage, which is a malus of 25% for each penalty.
|
||||
"""
|
||||
return 25 * self.penalty_int
|
||||
|
||||
|
@ -521,9 +521,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
teamTd.innerText = team
|
||||
teamTr.append(teamTd)
|
||||
|
||||
let defenderTd = document.createElement('td')
|
||||
defenderTd.classList.add('text-center')
|
||||
defenderTd.innerText = 'Déf'
|
||||
let reporterTd = document.createElement('td')
|
||||
reporterTd.classList.add('text-center')
|
||||
reporterTd.innerText = 'Déf'
|
||||
|
||||
let opponentTd = document.createElement('td')
|
||||
opponentTd.classList.add('text-center')
|
||||
@ -537,29 +537,29 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (poule.teams.length === 3) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
teamTr.append(defenderTd, reviewerTd, opponentTd)
|
||||
teamTr.append(reporterTd, reviewerTd, opponentTd)
|
||||
break
|
||||
case 1:
|
||||
teamTr.append(opponentTd, defenderTd, reviewerTd)
|
||||
teamTr.append(opponentTd, reporterTd, reviewerTd)
|
||||
break
|
||||
case 2:
|
||||
teamTr.append(reviewerTd, opponentTd, defenderTd)
|
||||
teamTr.append(reviewerTd, opponentTd, reporterTd)
|
||||
break
|
||||
}
|
||||
} else if (poule.teams.length === 4) {
|
||||
let emptyTd = document.createElement('td')
|
||||
switch (i) {
|
||||
case 0:
|
||||
teamTr.append(defenderTd, emptyTd, reviewerTd, opponentTd)
|
||||
teamTr.append(reporterTd, emptyTd, reviewerTd, opponentTd)
|
||||
break
|
||||
case 1:
|
||||
teamTr.append(opponentTd, defenderTd, emptyTd, reviewerTd)
|
||||
teamTr.append(opponentTd, reporterTd, emptyTd, reviewerTd)
|
||||
break
|
||||
case 2:
|
||||
teamTr.append(reviewerTd, opponentTd, defenderTd, emptyTd)
|
||||
teamTr.append(reviewerTd, opponentTd, reporterTd, emptyTd)
|
||||
break
|
||||
case 3:
|
||||
teamTr.append(emptyTd, reviewerTd, opponentTd, defenderTd)
|
||||
teamTr.append(emptyTd, reviewerTd, opponentTd, reporterTd)
|
||||
break
|
||||
}
|
||||
} else if (poule.teams.length === 5) {
|
||||
@ -567,19 +567,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
let emptyTd2 = document.createElement('td')
|
||||
switch (i) {
|
||||
case 0:
|
||||
teamTr.append(defenderTd, emptyTd, opponentTd, reviewerTd, emptyTd2)
|
||||
teamTr.append(reporterTd, emptyTd, opponentTd, reviewerTd, emptyTd2)
|
||||
break
|
||||
case 1:
|
||||
teamTr.append(emptyTd, defenderTd, reviewerTd, emptyTd2, opponentTd)
|
||||
teamTr.append(emptyTd, reporterTd, reviewerTd, emptyTd2, opponentTd)
|
||||
break
|
||||
case 2:
|
||||
teamTr.append(opponentTd, emptyTd, defenderTd, emptyTd2, reviewerTd)
|
||||
teamTr.append(opponentTd, emptyTd, reporterTd, emptyTd2, reviewerTd)
|
||||
break
|
||||
case 3:
|
||||
teamTr.append(reviewerTd, opponentTd, emptyTd, defenderTd, emptyTd2)
|
||||
teamTr.append(reviewerTd, opponentTd, emptyTd, reporterTd, emptyTd2)
|
||||
break
|
||||
case 4:
|
||||
teamTr.append(emptyTd, reviewerTd, emptyTd2, opponentTd, defenderTd)
|
||||
teamTr.append(emptyTd, reviewerTd, emptyTd2, opponentTd, reporterTd)
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -662,7 +662,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
let penaltyDiv = document.getElementById(`recap-${tid}-round-${round}-team-${team}-penalty`)
|
||||
if (rejected.length > problems_count - RECOMMENDED_SOLUTIONS_COUNT) {
|
||||
// If more than P - 5 problems were rejected, add a penalty of 25% of the coefficient of the oral defender
|
||||
// If more than P - 5 problems were rejected, add a penalty of 25% of the coefficient of the oral reporter
|
||||
// This is P - 6 for the ETEAM
|
||||
if (penaltyDiv === null) {
|
||||
penaltyDiv = document.createElement('div')
|
||||
|
@ -307,71 +307,71 @@
|
||||
<td class="text-center">{{ td.participation.team.trigram }}</td>
|
||||
{% if pool.size == 3 %}
|
||||
{% if forloop.counter == 1 %}
|
||||
<td class="text-center">Déf</td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
{% elif forloop.counter == 2 %}
|
||||
<td class="text-center">Opp</td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
{% elif forloop.counter == 3 %}
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
{% endif %}
|
||||
{% elif pool.size == 4 %}
|
||||
{% if forloop.counter == 1 %}
|
||||
<td class="text-center">Déf</td>
|
||||
<td></td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
{% elif forloop.counter == 2 %}
|
||||
<td class="text-center">Opp</td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td></td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
{% elif forloop.counter == 3 %}
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td></td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
{% elif forloop.counter == 4 %}
|
||||
<td></td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
{% endif %}
|
||||
{% elif pool.size == 5 %}
|
||||
{% if forloop.counter == 1 %}
|
||||
<td class="text-center">Déf</td>
|
||||
<td></td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td></td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center"></td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
{% elif forloop.counter == 2 %}
|
||||
<td></td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td></td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center"></td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
{% elif forloop.counter == 3 %}
|
||||
<td class="text-center">Opp</td>
|
||||
<td></td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td></td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center"></td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
{% elif forloop.counter == 4 %}
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td></td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td></td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
<td class="text-center"></td>
|
||||
{% elif forloop.counter == 5 %}
|
||||
<td></td>
|
||||
<td class="text-center">Rap</td>
|
||||
<td class="text-center">Opp</td>
|
||||
<td></td>
|
||||
<td class="text-center">Déf</td>
|
||||
<td class="text-center"></td>
|
||||
<td class="text-center">{% trans "Rev" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% trans "Opp" context "Role abbreviation" %}</td>
|
||||
<td class="text-center">{% if TFJM.APP == "ETEAM" %}{% trans "Obs" context "Role abbreviation" %}{% endif %}</td>
|
||||
<td class="text-center">{% trans "Rep" context "Role abbreviation" %}</td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</tr>
|
||||
|
@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: TFJM\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-07-06 10:16+0200\n"
|
||||
"POT-Creation-Date: 2024-07-06 22:07+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -79,7 +79,7 @@ msgstr "Type de permission nécessaire pour écrire un message dans un canal."
|
||||
#: chat/models.py:62 draw/admin.py:53 draw/admin.py:71 draw/admin.py:88
|
||||
#: draw/models.py:27 participation/admin.py:79 participation/admin.py:144
|
||||
#: participation/admin.py:176 participation/models.py:783
|
||||
#: participation/models.py:807 participation/models.py:1116
|
||||
#: participation/models.py:807 participation/models.py:1131
|
||||
#: registration/models.py:763
|
||||
#: registration/templates/registration/payment_form.html:53
|
||||
msgid "tournament"
|
||||
@ -95,7 +95,7 @@ msgstr ""
|
||||
|
||||
#: chat/models.py:73 draw/models.py:446 draw/models.py:473
|
||||
#: participation/admin.py:140 participation/admin.py:160
|
||||
#: participation/models.py:1651 participation/models.py:1660
|
||||
#: participation/models.py:1666 participation/models.py:1675
|
||||
#: participation/tables.py:84
|
||||
msgid "pool"
|
||||
msgstr "poule"
|
||||
@ -265,7 +265,7 @@ msgid "teams"
|
||||
msgstr "équipes"
|
||||
|
||||
#: draw/admin.py:92 draw/models.py:245 draw/models.py:465
|
||||
#: participation/models.py:1120
|
||||
#: participation/models.py:1135
|
||||
msgid "round"
|
||||
msgstr "tour"
|
||||
|
||||
@ -634,7 +634,7 @@ msgstr "Le numéro du tour doit être entre 1 et {nb}."
|
||||
msgid "rounds"
|
||||
msgstr "tours"
|
||||
|
||||
#: draw/models.py:268 participation/models.py:1128
|
||||
#: draw/models.py:268 participation/models.py:1143
|
||||
msgid "letter"
|
||||
msgstr "lettre"
|
||||
|
||||
@ -672,12 +672,12 @@ msgstr "L'instance complète de la poule."
|
||||
msgid "Pool {letter}{number}"
|
||||
msgstr "Poule {letter}{number}"
|
||||
|
||||
#: draw/models.py:447 participation/models.py:1652
|
||||
#: draw/models.py:447 participation/models.py:1667
|
||||
msgid "pools"
|
||||
msgstr "poules"
|
||||
|
||||
#: draw/models.py:459 participation/models.py:1106 participation/models.py:1871
|
||||
#: participation/models.py:1901 participation/models.py:1943
|
||||
#: draw/models.py:459 participation/models.py:1121 participation/models.py:1886
|
||||
#: participation/models.py:1920 participation/models.py:1962
|
||||
msgid "participation"
|
||||
msgstr "participation"
|
||||
|
||||
@ -701,9 +701,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
|
||||
|
||||
#: draw/models.py:496 draw/models.py:519 participation/models.py:1237
|
||||
#: participation/models.py:1674 participation/models.py:1908
|
||||
#: participation/views.py:1489 participation/views.py:1754
|
||||
#: draw/models.py:496 draw/models.py:519 participation/models.py:1252
|
||||
#: participation/models.py:1689 participation/models.py:1927
|
||||
#: participation/views.py:1492 participation/views.py:1757
|
||||
#, python-brace-format
|
||||
msgid "Problem #{problem}"
|
||||
msgstr "Problème n°{problem}"
|
||||
@ -814,6 +814,67 @@ msgstr "Pb."
|
||||
msgid "Room"
|
||||
msgstr "Salle"
|
||||
|
||||
#: draw/templates/draw/tournament_content.html:310
|
||||
#: draw/templates/draw/tournament_content.html:315
|
||||
#: draw/templates/draw/tournament_content.html:320
|
||||
#: draw/templates/draw/tournament_content.html:324
|
||||
#: draw/templates/draw/tournament_content.html:330
|
||||
#: draw/templates/draw/tournament_content.html:336
|
||||
#: draw/templates/draw/tournament_content.html:342
|
||||
#: draw/templates/draw/tournament_content.html:346
|
||||
#: draw/templates/draw/tournament_content.html:353
|
||||
#: draw/templates/draw/tournament_content.html:360
|
||||
#: draw/templates/draw/tournament_content.html:367
|
||||
#: draw/templates/draw/tournament_content.html:374
|
||||
msgctxt "Role abbreviation"
|
||||
msgid "Rep"
|
||||
msgstr "Déf"
|
||||
|
||||
#: draw/templates/draw/tournament_content.html:311
|
||||
#: draw/templates/draw/tournament_content.html:316
|
||||
#: draw/templates/draw/tournament_content.html:318
|
||||
#: draw/templates/draw/tournament_content.html:326
|
||||
#: draw/templates/draw/tournament_content.html:332
|
||||
#: draw/templates/draw/tournament_content.html:334
|
||||
#: draw/templates/draw/tournament_content.html:340
|
||||
#: draw/templates/draw/tournament_content.html:348
|
||||
#: draw/templates/draw/tournament_content.html:355
|
||||
#: draw/templates/draw/tournament_content.html:362
|
||||
#: draw/templates/draw/tournament_content.html:364
|
||||
#: draw/templates/draw/tournament_content.html:371
|
||||
msgctxt "Role abbreviation"
|
||||
msgid "Rev"
|
||||
msgstr "Rap"
|
||||
|
||||
#: draw/templates/draw/tournament_content.html:312
|
||||
#: draw/templates/draw/tournament_content.html:314
|
||||
#: draw/templates/draw/tournament_content.html:319
|
||||
#: draw/templates/draw/tournament_content.html:327
|
||||
#: draw/templates/draw/tournament_content.html:329
|
||||
#: draw/templates/draw/tournament_content.html:335
|
||||
#: draw/templates/draw/tournament_content.html:341
|
||||
#: draw/templates/draw/tournament_content.html:349
|
||||
#: draw/templates/draw/tournament_content.html:356
|
||||
#: draw/templates/draw/tournament_content.html:358
|
||||
#: draw/templates/draw/tournament_content.html:365
|
||||
#: draw/templates/draw/tournament_content.html:372
|
||||
msgctxt "Role abbreviation"
|
||||
msgid "Opp"
|
||||
msgstr "Opp"
|
||||
|
||||
#: draw/templates/draw/tournament_content.html:325
|
||||
#: draw/templates/draw/tournament_content.html:331
|
||||
#: draw/templates/draw/tournament_content.html:337
|
||||
#: draw/templates/draw/tournament_content.html:339
|
||||
#: draw/templates/draw/tournament_content.html:350
|
||||
#: draw/templates/draw/tournament_content.html:352
|
||||
#: draw/templates/draw/tournament_content.html:359
|
||||
#: draw/templates/draw/tournament_content.html:366
|
||||
#: draw/templates/draw/tournament_content.html:373
|
||||
msgctxt "Role abbreviation"
|
||||
msgid "Obs"
|
||||
msgstr "Obs"
|
||||
|
||||
#: draw/templates/draw/tournament_content.html:395
|
||||
#: draw/templates/draw/tournament_content.html:414
|
||||
msgid "Abort"
|
||||
@ -919,26 +980,26 @@ msgid "selected for final"
|
||||
msgstr "sélectionnée pour la finale"
|
||||
|
||||
#: participation/admin.py:124 participation/admin.py:188
|
||||
#: participation/models.py:1681 participation/tables.py:114
|
||||
msgid "defender"
|
||||
#: participation/models.py:1696 participation/tables.py:114
|
||||
msgid "reporter"
|
||||
msgstr "défenseur⋅se"
|
||||
|
||||
#: participation/admin.py:128 participation/models.py:1688
|
||||
#: participation/models.py:1955
|
||||
#: participation/admin.py:128 participation/models.py:1703
|
||||
#: participation/models.py:1974
|
||||
msgid "opponent"
|
||||
msgstr "opposant⋅e"
|
||||
|
||||
#: participation/admin.py:132 participation/models.py:1695
|
||||
#: participation/models.py:1956
|
||||
#: participation/admin.py:132 participation/models.py:1710
|
||||
#: participation/models.py:1975
|
||||
msgid "reviewer"
|
||||
msgstr "rapporteur⋅rice"
|
||||
|
||||
#: participation/admin.py:136 participation/models.py:1702
|
||||
#: participation/models.py:1957
|
||||
#: participation/admin.py:136 participation/models.py:1717
|
||||
#: participation/models.py:1976
|
||||
msgid "observer"
|
||||
msgstr "observateur⋅rice"
|
||||
|
||||
#: participation/admin.py:192 participation/models.py:1906
|
||||
#: participation/admin.py:192 participation/models.py:1925
|
||||
msgid "problem"
|
||||
msgstr "numéro de problème"
|
||||
|
||||
@ -1027,12 +1088,12 @@ msgid "The following user was not found:"
|
||||
msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :"
|
||||
|
||||
#: participation/forms.py:350
|
||||
msgid "The defender, the opponent and the reviewer must be different."
|
||||
msgid "The reporter, the opponent and the reviewer must be different."
|
||||
msgstr ""
|
||||
"Les équipes défenseuse, opposante et rapportrice doivent être différent⋅es."
|
||||
|
||||
#: participation/forms.py:354
|
||||
msgid "This defender did not work on this problem."
|
||||
msgid "This reporter did not work on this problem."
|
||||
msgstr "Ce⋅tte défenseur⋅se ne travaille pas sur ce problème."
|
||||
|
||||
#: participation/forms.py:373
|
||||
@ -1239,7 +1300,7 @@ msgid "first phase date"
|
||||
msgstr "date du premier tour"
|
||||
|
||||
#: participation/models.py:327
|
||||
msgid "limit date to upload the syntheses for the first phase"
|
||||
msgid "limit date to upload the written reviews for the first phase"
|
||||
msgstr "date limite pour envoyer les notes de synthèses pour la première phase"
|
||||
|
||||
#: participation/models.py:332
|
||||
@ -1252,7 +1313,7 @@ msgstr ""
|
||||
"cocher la case lorsque les solutions pour le second tour sont accessibles"
|
||||
|
||||
#: participation/models.py:342
|
||||
msgid "limit date to upload the syntheses for the second phase"
|
||||
msgid "limit date to upload the written reviews for the second phase"
|
||||
msgstr "date limite d'envoi des notes de synthèse pour la seconde phase"
|
||||
|
||||
#: participation/models.py:347
|
||||
@ -1265,7 +1326,7 @@ msgstr ""
|
||||
"cocher la case lorsque les solutions pour le second tour sont accessibles"
|
||||
|
||||
#: participation/models.py:357
|
||||
msgid "limit date to upload the syntheses for the third phase"
|
||||
msgid "limit date to upload the written reviews for the third phase"
|
||||
msgstr ""
|
||||
"date limite pour envoyer les notes de synthèses pour la troisième phase"
|
||||
|
||||
@ -1294,7 +1355,7 @@ msgid "Final ranking"
|
||||
msgstr "Classement final"
|
||||
|
||||
#: participation/models.py:481 participation/models.py:553
|
||||
#: participation/models.py:1312 participation/views.py:1728
|
||||
#: participation/models.py:1327 participation/views.py:1731
|
||||
msgid "Team"
|
||||
msgstr "Équipe"
|
||||
|
||||
@ -1326,15 +1387,15 @@ msgstr "Scores jour 3"
|
||||
msgid "Tweaks day 3"
|
||||
msgstr "Ajustements 3"
|
||||
|
||||
#: participation/models.py:485 participation/models.py:1312
|
||||
#: participation/views.py:1735
|
||||
#: participation/models.py:485 participation/models.py:1327
|
||||
#: participation/views.py:1738
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: participation/models.py:485 participation/models.py:553
|
||||
#: participation/models.py:1312
|
||||
#: participation/models.py:1327
|
||||
#: participation/templates/participation/tournament_harmonize.html:14
|
||||
#: participation/views.py:1738
|
||||
#: participation/views.py:1741
|
||||
msgid "Rank"
|
||||
msgstr "Rang"
|
||||
|
||||
@ -1346,7 +1407,7 @@ msgstr "Score"
|
||||
msgid "Mention"
|
||||
msgstr "Mention"
|
||||
|
||||
#: participation/models.py:698 participation/models.py:1581
|
||||
#: participation/models.py:698 participation/models.py:1596
|
||||
msgid "Don't update the table structure for a better automated integration."
|
||||
msgstr ""
|
||||
"Ne pas mettre à jour la structure de la table pour une meilleure intégration "
|
||||
@ -1448,7 +1509,7 @@ msgstr "Tirage au sort des solutions"
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<p>The solutions draw is ended. You can check the result on <a "
|
||||
"href='{draw_url}'>this page</a>.</p><p>For the first round, you will defend "
|
||||
"href='{draw_url}'>this page</a>.</p><p>For the first round, you will present "
|
||||
"<a href='{solution_url}'>your solution of the problem {problem}</a>.</p>"
|
||||
msgstr ""
|
||||
"<p>Le tirage au sort des solutions est terminé. Vous pouvez consulter les "
|
||||
@ -1456,70 +1517,70 @@ msgstr ""
|
||||
"tour, vous défendrez <a href='{solution_url}'>votre solution du problème "
|
||||
"{problem}</a>.</p>"
|
||||
|
||||
#: participation/models.py:930 participation/models.py:988
|
||||
#: participation/models.py:1047
|
||||
#: participation/models.py:930 participation/models.py:993
|
||||
#: participation/models.py:1057
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<p>You will oppose the solution of the team {opponent} on the <a "
|
||||
"href='{solution_url}'>problem {problem}</a>. You can upload your synthesis "
|
||||
"sheet on <a href='{passage_url}'>this page</a>.</p>"
|
||||
"href='{solution_url}'>problem {problem}</a>. You can upload your written "
|
||||
"review on <a href='{passage_url}'>this page</a>.</p>"
|
||||
msgstr ""
|
||||
"<p>Vous opposerez la solution de l'équipe {opponent} sur le <a "
|
||||
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
||||
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
||||
|
||||
#: participation/models.py:939 participation/models.py:997
|
||||
#: participation/models.py:1056
|
||||
#: participation/models.py:939 participation/models.py:1002
|
||||
#: participation/models.py:1066
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<p>You will report the solution of the team {reviewer} on the <a "
|
||||
"href='{solution_url}'>problem {problem}. You can upload your synthesis sheet "
|
||||
"on <a href='{passage_url}'>this page</a>.</p>"
|
||||
"href='{solution_url}'>problem {problem}</a>. You can upload your written "
|
||||
"review on <a href='{passage_url}'>this page</a>.</p>"
|
||||
msgstr ""
|
||||
"<p>Vous rapporterez la solution de l'équipe {reviewer} sur le <a "
|
||||
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
||||
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
||||
|
||||
#: participation/models.py:949 participation/models.py:1007
|
||||
#: participation/models.py:1066
|
||||
#: participation/models.py:949 participation/models.py:1012
|
||||
#: participation/models.py:1076
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<p>You will observe the solution of the team {observer} on the <a "
|
||||
"href='{solution_url}'>problem {problem}. You can upload your synthesis sheet "
|
||||
"on <a href='{passage_url}'>this page</a>.</p>"
|
||||
"href='{solution_url}'>problem {problem}</a>. You can upload your written "
|
||||
"review on <a href='{passage_url}'>this page</a>.</p>"
|
||||
msgstr ""
|
||||
"<p>Vous observerez la solution de l'équipe {observer} sur le <a "
|
||||
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
||||
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
||||
|
||||
#: participation/models.py:969 registration/models.py:629
|
||||
#: participation/models.py:974 registration/models.py:629
|
||||
msgid "First round"
|
||||
msgstr "Premier tour"
|
||||
|
||||
#: participation/models.py:981
|
||||
#: participation/models.py:986
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<p>For the second round, you will defend <a href='{solution_url}'>your "
|
||||
"<p>For the second round, you will present <a href='{solution_url}'>your "
|
||||
"solution of the problem {problem}</a>.</p>"
|
||||
msgstr ""
|
||||
"<p>Pour le second tour, vous défendrez <a href='{solution_url}'>votre "
|
||||
"solution du problème {problem}</a>.</p>"
|
||||
|
||||
#: participation/models.py:1027 participation/models.py:1086
|
||||
#: participation/models.py:1037 participation/models.py:1101
|
||||
#: registration/models.py:640
|
||||
msgid "Second round"
|
||||
msgstr "Second tour"
|
||||
|
||||
#: participation/models.py:1040
|
||||
#: participation/models.py:1050
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<p>For the third round, you will defend <a href='{solution_url}'>your "
|
||||
"<p>For the third round, you will present <a href='{solution_url}'>your "
|
||||
"solution of the problem {problem}</a>.</p>"
|
||||
msgstr ""
|
||||
"<p>Pour le troisième tour, vous défendrez <a href='{solution_url}'>votre "
|
||||
"solution du problème {problem}</a>.</p>"
|
||||
|
||||
#: participation/models.py:1092
|
||||
#: participation/models.py:1107
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<p>The tournament {tournament} is ended. You can check the results on the <a "
|
||||
@ -1528,57 +1589,57 @@ msgstr ""
|
||||
"<p>Le tournoi {tournament} est terminé. Vous pouvez consulter les résultats "
|
||||
"sur la <a href='{url}'>page du tournoi</a>.</p>"
|
||||
|
||||
#: participation/models.py:1097
|
||||
#: participation/models.py:1112
|
||||
msgid "Tournament ended"
|
||||
msgstr "Tournoi terminé"
|
||||
|
||||
#: participation/models.py:1107 participation/models.py:1150
|
||||
#: participation/models.py:1122 participation/models.py:1165
|
||||
msgid "participations"
|
||||
msgstr "participations"
|
||||
|
||||
#: participation/models.py:1122 participation/models.py:1123
|
||||
#: participation/models.py:1124
|
||||
#: participation/models.py:1137 participation/models.py:1138
|
||||
#: participation/models.py:1139
|
||||
#, python-brace-format
|
||||
msgid "Round {round}"
|
||||
msgstr "Tour {round}"
|
||||
|
||||
#: participation/models.py:1138
|
||||
#: participation/models.py:1153
|
||||
msgid "room"
|
||||
msgstr "salle"
|
||||
|
||||
#: participation/models.py:1140
|
||||
#: participation/models.py:1155
|
||||
msgid "Room 1"
|
||||
msgstr "Salle 1"
|
||||
|
||||
#: participation/models.py:1141
|
||||
#: participation/models.py:1156
|
||||
msgid "Room 2"
|
||||
msgstr "Salle 2"
|
||||
|
||||
#: participation/models.py:1144
|
||||
#: participation/models.py:1159
|
||||
msgid "For 5-teams pools only"
|
||||
msgstr "Pour les poules de 5 équipe uniquement"
|
||||
|
||||
#: participation/models.py:1156
|
||||
#: participation/models.py:1171
|
||||
msgid "juries"
|
||||
msgstr "jurys"
|
||||
|
||||
#: participation/models.py:1165
|
||||
#: participation/models.py:1180
|
||||
msgid "president of the jury"
|
||||
msgstr "président⋅e du jury"
|
||||
|
||||
#: participation/models.py:1172
|
||||
#: participation/models.py:1187
|
||||
msgid "BigBlueButton URL"
|
||||
msgstr "Lien BigBlueButton"
|
||||
|
||||
#: participation/models.py:1173
|
||||
#: participation/models.py:1188
|
||||
msgid "The link of the BBB visio for this pool."
|
||||
msgstr "Le lien du salon BBB pour cette poule."
|
||||
|
||||
#: participation/models.py:1178
|
||||
#: participation/models.py:1193
|
||||
msgid "results available"
|
||||
msgstr "résultats disponibles"
|
||||
|
||||
#: participation/models.py:1179
|
||||
#: participation/models.py:1194
|
||||
msgid ""
|
||||
"Check this case when results become accessible to teams. They stay "
|
||||
"accessible to you. Only averages are given."
|
||||
@ -1587,194 +1648,194 @@ msgstr ""
|
||||
"Ils restent toujours accessibles pour vous. Seules les moyennes sont "
|
||||
"communiquées."
|
||||
|
||||
#: participation/models.py:1211
|
||||
#: participation/models.py:1226
|
||||
msgid "The president of the jury must be part of the jury."
|
||||
msgstr "Læ président⋅e du jury doit faire partie du jury."
|
||||
|
||||
#: participation/models.py:1238 participation/models.py:1312
|
||||
#: participation/views.py:1483 participation/views.py:1732
|
||||
#: participation/models.py:1253 participation/models.py:1327
|
||||
#: participation/views.py:1486 participation/views.py:1735
|
||||
msgid "Problem"
|
||||
msgstr "Problème"
|
||||
|
||||
#: participation/models.py:1243 participation/views.py:1498
|
||||
#: participation/models.py:1258 participation/views.py:1501
|
||||
msgid "Role"
|
||||
msgstr "Rôle"
|
||||
|
||||
#: participation/models.py:1248 participation/views.py:1532
|
||||
#: participation/views.py:1533
|
||||
#: participation/models.py:1263 participation/views.py:1535
|
||||
#: participation/views.py:1536
|
||||
msgid "Juree"
|
||||
msgstr "Juré⋅e"
|
||||
|
||||
#: participation/models.py:1271 participation/models.py:1597
|
||||
#: participation/models.py:1619 participation/views.py:1602
|
||||
#: participation/models.py:1286 participation/models.py:1612
|
||||
#: participation/models.py:1634 participation/views.py:1605
|
||||
msgid "Average"
|
||||
msgstr "Moyenne"
|
||||
|
||||
#: participation/models.py:1277 participation/views.py:1621
|
||||
#: participation/models.py:1292 participation/views.py:1624
|
||||
msgid "Coefficient"
|
||||
msgstr "Coefficien"
|
||||
|
||||
#: participation/models.py:1278 participation/views.py:1664
|
||||
#: participation/models.py:1293 participation/views.py:1667
|
||||
msgid "Subtotal"
|
||||
msgstr "Sous-total"
|
||||
|
||||
#: participation/models.py:1544
|
||||
#: participation/models.py:1559
|
||||
#, python-brace-format
|
||||
msgid "Input must be a valid integer between {min_note} and {max_note}."
|
||||
msgstr "L'entrée doit être un entier valide entre {min_note} et {max_note}."
|
||||
|
||||
#: participation/models.py:1632
|
||||
#: participation/models.py:1647
|
||||
#, python-brace-format
|
||||
msgid "The jury {jury} is not part of the jury for this pool."
|
||||
msgstr "{jury} ne fait pas partie du jury pour cette poule."
|
||||
|
||||
#: participation/models.py:1645
|
||||
#: participation/models.py:1660
|
||||
#, python-brace-format
|
||||
msgid "Pool {code} for tournament {tournament} with teams {teams}"
|
||||
msgstr "Poule {code} du tournoi {tournament} avec les équipes {teams}"
|
||||
|
||||
#: participation/models.py:1665
|
||||
#: participation/models.py:1680
|
||||
msgid "position"
|
||||
msgstr "position"
|
||||
|
||||
#: participation/models.py:1672
|
||||
msgid "defended solution"
|
||||
#: participation/models.py:1687
|
||||
msgid "reported solution"
|
||||
msgstr "solution défendue"
|
||||
|
||||
#: participation/models.py:1710
|
||||
#: participation/models.py:1725
|
||||
msgid "penalties"
|
||||
msgstr "pénalités"
|
||||
|
||||
#: participation/models.py:1712
|
||||
#: participation/models.py:1727
|
||||
msgid ""
|
||||
"Number of penalties for the defender. The defender will loose a 0.5 "
|
||||
"Number of penalties for the reporter. The reporter will loose a 0.5 "
|
||||
"coefficient per penalty."
|
||||
msgstr ""
|
||||
"Nombre de pénalités pour l'équipe défenseuse. Elle perd un coefficient 0.5 "
|
||||
"sur sa présentation orale par pénalité."
|
||||
|
||||
#: participation/models.py:1838 participation/models.py:1841
|
||||
#: participation/models.py:1844 participation/models.py:1847
|
||||
#: participation/models.py:1853 participation/models.py:1856
|
||||
#: participation/models.py:1859 participation/models.py:1862
|
||||
#, python-brace-format
|
||||
msgid "Team {trigram} is not registered in the pool."
|
||||
msgstr "L'équipe {trigram} n'est pas inscrite dans la poule."
|
||||
|
||||
#: participation/models.py:1852
|
||||
#: participation/models.py:1867
|
||||
#, python-brace-format
|
||||
msgid "Passage of {defender} for problem {problem}"
|
||||
msgstr "Passage de {defender} pour le problème {problem}"
|
||||
msgid "Passage of {reporter} for problem {problem}"
|
||||
msgstr "Passage de {reporter} pour le problème {problem}"
|
||||
|
||||
#: participation/models.py:1856 participation/models.py:1865
|
||||
#: participation/models.py:1950 participation/models.py:1993
|
||||
#: participation/models.py:1871 participation/models.py:1880
|
||||
#: participation/models.py:1969 participation/models.py:2012
|
||||
msgid "passage"
|
||||
msgstr "passage"
|
||||
|
||||
#: participation/models.py:1857
|
||||
#: participation/models.py:1872
|
||||
msgid "passages"
|
||||
msgstr "passages"
|
||||
|
||||
#: participation/models.py:1876
|
||||
#: participation/models.py:1891
|
||||
msgid "difference"
|
||||
msgstr "différence"
|
||||
|
||||
#: participation/models.py:1877
|
||||
#: participation/models.py:1892
|
||||
msgid "Score to add/remove on the final score"
|
||||
msgstr "Score à ajouter/retrancher au score final"
|
||||
|
||||
#: participation/models.py:1884
|
||||
#: participation/models.py:1899
|
||||
msgid "tweak"
|
||||
msgstr "harmonisation"
|
||||
|
||||
#: participation/models.py:1885
|
||||
#: participation/models.py:1900
|
||||
msgid "tweaks"
|
||||
msgstr "harmonisations"
|
||||
|
||||
#: participation/models.py:1913
|
||||
#: participation/models.py:1932
|
||||
msgid "solution for the final tournament"
|
||||
msgstr "solution pour la finale"
|
||||
|
||||
#: participation/models.py:1918 participation/models.py:1962
|
||||
#: participation/models.py:1937 participation/models.py:1981
|
||||
msgid "file"
|
||||
msgstr "fichier"
|
||||
|
||||
#: participation/models.py:1928
|
||||
#: participation/models.py:1947
|
||||
#, python-brace-format
|
||||
msgid "Solution of team {team} for problem {problem}"
|
||||
msgstr "Solution de l'équipe {team} pour le problème {problem}"
|
||||
|
||||
#: participation/models.py:1930
|
||||
#: participation/models.py:1949
|
||||
msgid "for final"
|
||||
msgstr "pour la finale"
|
||||
|
||||
#: participation/models.py:1933
|
||||
#: participation/models.py:1952
|
||||
msgid "solution"
|
||||
msgstr "solution"
|
||||
|
||||
#: participation/models.py:1934
|
||||
#: participation/models.py:1953
|
||||
msgid "solutions"
|
||||
msgstr "solutions"
|
||||
|
||||
#: participation/models.py:1968
|
||||
#: participation/models.py:1987
|
||||
#, python-brace-format
|
||||
msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
|
||||
msgid "Written review of {team} as {type} for problem {problem} of {reporter}"
|
||||
msgstr ""
|
||||
"Note de synthèse de l'équipe {team} en tant que {type} pour le problème "
|
||||
"{problem} de {defender}"
|
||||
"{problem} de {reporter}"
|
||||
|
||||
#: participation/models.py:1976
|
||||
msgid "synthesis"
|
||||
#: participation/models.py:1995
|
||||
msgid "written review"
|
||||
msgstr "note de synthèse"
|
||||
|
||||
#: participation/models.py:1977
|
||||
msgid "syntheses"
|
||||
#: participation/models.py:1996
|
||||
msgid "written reviews"
|
||||
msgstr "notes de synthèse"
|
||||
|
||||
#: participation/models.py:1986
|
||||
#: participation/models.py:2005
|
||||
msgid "jury"
|
||||
msgstr "jury"
|
||||
|
||||
#: participation/models.py:1998
|
||||
msgid "defender writing note"
|
||||
#: participation/models.py:2017
|
||||
msgid "reporter writing note"
|
||||
msgstr "note d'écrit défenseur⋅se"
|
||||
|
||||
#: participation/models.py:2004
|
||||
msgid "defender oral note"
|
||||
#: participation/models.py:2023
|
||||
msgid "reporter oral note"
|
||||
msgstr "note d'oral défenseur⋅se"
|
||||
|
||||
#: participation/models.py:2010
|
||||
#: participation/models.py:2029
|
||||
msgid "opponent writing note"
|
||||
msgstr "note d'écrit opposant⋅e"
|
||||
|
||||
#: participation/models.py:2016
|
||||
#: participation/models.py:2035
|
||||
msgid "opponent oral note"
|
||||
msgstr "note d'oral opposant⋅e"
|
||||
|
||||
#: participation/models.py:2022
|
||||
#: participation/models.py:2041
|
||||
msgid "reviewer writing note"
|
||||
msgstr "note d'écrit rapporteur⋅rice"
|
||||
|
||||
#: participation/models.py:2028
|
||||
#: participation/models.py:2047
|
||||
msgid "reviewer oral note"
|
||||
msgstr "note d'oral du rapporteur⋅rice"
|
||||
|
||||
#: participation/models.py:2034
|
||||
#: participation/models.py:2053
|
||||
msgid "observer writing note"
|
||||
msgstr "note d'écrit de l'observateur⋅rice"
|
||||
|
||||
#: participation/models.py:2040
|
||||
#: participation/models.py:2059
|
||||
msgid "observer oral note"
|
||||
msgstr "note d'oral de l'observateur⋅rice"
|
||||
|
||||
#: participation/models.py:2105
|
||||
#: participation/models.py:2124
|
||||
#, python-brace-format
|
||||
msgid "Notes of {jury} for {passage}"
|
||||
msgstr "Notes de {jury} pour le {passage}"
|
||||
|
||||
#: participation/models.py:2108
|
||||
#: participation/models.py:2127
|
||||
msgid "note"
|
||||
msgstr "note"
|
||||
|
||||
#: participation/models.py:2109
|
||||
#: participation/models.py:2128
|
||||
msgid "notes"
|
||||
msgstr "notes"
|
||||
|
||||
@ -1910,7 +1971,7 @@ msgstr "Envoyer une solution"
|
||||
#: participation/templates/participation/upload_motivation_letter.html:13
|
||||
#: participation/templates/participation/upload_notes.html:24
|
||||
#: participation/templates/participation/upload_solution.html:11
|
||||
#: participation/templates/participation/upload_synthesis.html:18
|
||||
#: participation/templates/participation/upload_written_review.html:23
|
||||
#: registration/templates/registration/upload_health_sheet.html:17
|
||||
#: registration/templates/registration/upload_parental_authorization.html:17
|
||||
#: registration/templates/registration/upload_photo_authorization.html:18
|
||||
@ -1933,7 +1994,7 @@ msgid "Position:"
|
||||
msgstr "Position :"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:28
|
||||
msgid "Defender:"
|
||||
msgid "Reporter:"
|
||||
msgstr "Défenseur⋅se :"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:31
|
||||
@ -1949,11 +2010,11 @@ msgid "Observer:"
|
||||
msgstr "Observateur⋅rice :"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:42
|
||||
msgid "Defended solution:"
|
||||
msgid "Reported solution:"
|
||||
msgstr "Solution défendue"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:45
|
||||
msgid "Defender penalties count:"
|
||||
msgid "Reporter penalties count:"
|
||||
msgstr "Nombre de pénalités :"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:48
|
||||
@ -1963,7 +2024,7 @@ msgstr "Notes de synthèse :"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:53
|
||||
#: participation/templates/participation/pool_detail.html:68
|
||||
msgid "No synthesis was uploaded yet."
|
||||
msgid "No review was uploaded yet."
|
||||
msgstr "Aucune note de synthèse n'a encore été envoyée."
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:61
|
||||
@ -1973,19 +2034,19 @@ msgstr "Modifier les notes"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:66
|
||||
#: participation/templates/participation/passage_detail.html:187
|
||||
msgid "Upload synthesis"
|
||||
msgstr "Envoyer une note de synthèse"
|
||||
msgid "Upload review"
|
||||
msgstr "Envoyer la note de synthèse"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:74
|
||||
msgid "Notes detail"
|
||||
msgstr "Détails des notes"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:82
|
||||
msgid "Average points for the defender writing"
|
||||
msgid "Average points for the reporter writing"
|
||||
msgstr "Moyenne de l'écrit de l'équipe défenseuse"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:90
|
||||
msgid "Average points for the defender oral"
|
||||
msgid "Average points for the reporter oral"
|
||||
msgstr "Moyenne de l'oral de l'équipe défenseuse"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:98
|
||||
@ -2013,7 +2074,7 @@ msgid "Average points for the observer oral"
|
||||
msgstr "Moyenne de l'oral de l'équipe observatrice"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:140
|
||||
msgid "Defender points"
|
||||
msgid "Reporter points"
|
||||
msgstr "Points de l'équipe défenseuse"
|
||||
|
||||
#: participation/templates/participation/passage_detail.html:148
|
||||
@ -2058,7 +2119,7 @@ msgid "Edit jury"
|
||||
msgstr "Modifier le jury"
|
||||
|
||||
#: participation/templates/participation/pool_detail.html:49
|
||||
msgid "Defended solutions:"
|
||||
msgid "Reported solutions:"
|
||||
msgstr "Solutions défendues :"
|
||||
|
||||
#: participation/templates/participation/pool_detail.html:55
|
||||
@ -2374,15 +2435,15 @@ msgid "date of the random draw"
|
||||
msgstr "date du tirage au sort"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:41
|
||||
msgid "date of maximal syntheses submission for the first round"
|
||||
msgid "date of maximal written reviews submission for the first round"
|
||||
msgstr "date limite de soumission des notes de synthèse pour le premier tour"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:44
|
||||
msgid "date of maximal syntheses submission for the second round"
|
||||
msgid "date of maximal written reviews submission for the second round"
|
||||
msgstr "date limite de soumission des notes de synthèse pour le second tour"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:48
|
||||
msgid "date of maximal syntheses submission for the third round"
|
||||
msgid "date of maximal written reviews submission for the third round"
|
||||
msgstr "date limite de soumission des notes de synthèse pour le troisième tour"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:56
|
||||
@ -2462,6 +2523,42 @@ msgstr "Dépublier les notes pour le troisième tour"
|
||||
msgid "Files available for download"
|
||||
msgstr "Fichiers disponibles au téléchargement"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:236
|
||||
msgid "Validated team participant data spreadsheet"
|
||||
msgstr "Tableur des données des équipes validées"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:241
|
||||
msgid "All teams participant data spreadsheet"
|
||||
msgstr "Tableur des données de toutes les équipes"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:246
|
||||
msgid "Archive of all authorisations sorted by team and person"
|
||||
msgstr "Archive de toutes les autorisations triées par équipe et personne"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:251
|
||||
msgid "Archive of all submitted solutions sorted by team"
|
||||
msgstr "Archive de toutes les solutions envoyées triées par équipe"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:256
|
||||
msgid "Archive of all sent solutions sorted by problem"
|
||||
msgstr "Archive de toutes les solutions envoyées triées par problème"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:261
|
||||
msgid "Archive of all sent solutions sorted by pool"
|
||||
msgstr "Archive de toutes les solutions envoyées triées par poule"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:266
|
||||
msgid "Archive of all summary notes sorted by pool and passage"
|
||||
msgstr "Archive de toutes les notes de synthèse triées par poule et passage"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:272
|
||||
msgid "Note spreadsheet on Google Sheets"
|
||||
msgstr "Tableur de notes sur Google Sheets"
|
||||
|
||||
#: participation/templates/participation/tournament_detail.html:277
|
||||
msgid "Archive of all printable note sheets sorted by pool"
|
||||
msgstr "Archive de toutes les fiches de notes imprimables triées par poule"
|
||||
|
||||
#: participation/templates/participation/tournament_harmonize.html:16
|
||||
#: registration/models.py:655
|
||||
msgid "Note"
|
||||
@ -2504,11 +2601,11 @@ msgstr ""
|
||||
msgid "Download empty notation sheet"
|
||||
msgstr "Télécharger la fiche de notation vierge"
|
||||
|
||||
#: participation/templates/participation/upload_synthesis.html:9
|
||||
#: participation/templates/participation/upload_written_review.html:9
|
||||
msgid "Templates:"
|
||||
msgstr "Modèles :"
|
||||
|
||||
#: participation/templates/participation/upload_synthesis.html:13
|
||||
#: participation/templates/participation/upload_written_review.html:14
|
||||
msgid "Warning: non-free format"
|
||||
msgstr "Attention : format non libre"
|
||||
|
||||
@ -2656,96 +2753,96 @@ msgstr "Vous ne pouvez pas envoyer de solution après la date limite."
|
||||
msgid "Solutions of team {trigram}.zip"
|
||||
msgstr "Solutions de l'équipe {trigram}.zip"
|
||||
|
||||
#: participation/views.py:1022
|
||||
#: participation/views.py:1023
|
||||
#, python-brace-format
|
||||
msgid "Syntheses of team {trigram}.zip"
|
||||
msgid "Written reviews of team {trigram}.zip"
|
||||
msgstr "Notes de synthèse de l'équipe {trigram}.zip"
|
||||
|
||||
#: participation/views.py:1039 participation/views.py:1054
|
||||
#: participation/views.py:1040 participation/views.py:1056
|
||||
#, python-brace-format
|
||||
msgid "Solutions of {tournament}.zip"
|
||||
msgstr "Solutions de {tournament}.zip"
|
||||
|
||||
#: participation/views.py:1039 participation/views.py:1054
|
||||
#: participation/views.py:1041 participation/views.py:1057
|
||||
#, python-brace-format
|
||||
msgid "Syntheses of {tournament}.zip"
|
||||
msgid "Written reviews of {tournament}.zip"
|
||||
msgstr "Notes de synthèse de {tournament}.zip"
|
||||
|
||||
#: participation/views.py:1063
|
||||
#: participation/views.py:1066
|
||||
#, python-brace-format
|
||||
msgid "Solutions for pool {pool} of tournament {tournament}.zip"
|
||||
msgstr "Solutions pour la poule {pool} du tournoi {tournament}.zip"
|
||||
|
||||
#: participation/views.py:1064
|
||||
#: participation/views.py:1067
|
||||
#, python-brace-format
|
||||
msgid "Syntheses for pool {pool} of tournament {tournament}.zip"
|
||||
msgid "Written reviews for pool {pool} of tournament {tournament}.zip"
|
||||
msgstr "Notes de synthèses pour la poule {pool} du tournoi {tournament}.zip"
|
||||
|
||||
#: participation/views.py:1106
|
||||
#: participation/views.py:1109
|
||||
#, python-brace-format
|
||||
msgid "Jury of pool {pool} for {tournament} with teams {teams}"
|
||||
msgstr "Jury de la poule {pool} pour {tournament} avec les équipes {teams}"
|
||||
|
||||
#: participation/views.py:1122
|
||||
#: participation/views.py:1125
|
||||
#, python-brace-format
|
||||
msgid "The jury {name} is already in the pool!"
|
||||
msgstr "{name} est déjà dans la poule !"
|
||||
|
||||
#: participation/views.py:1142
|
||||
#: participation/views.py:1145
|
||||
msgid "New jury account"
|
||||
msgstr "Nouveau compte de juré⋅e"
|
||||
|
||||
#: participation/views.py:1163
|
||||
#: participation/views.py:1166
|
||||
#, python-brace-format
|
||||
msgid "The jury {name} has been successfully added!"
|
||||
msgstr "{name} a été ajouté⋅e avec succès en tant que juré⋅e !"
|
||||
|
||||
#: participation/views.py:1199
|
||||
#: participation/views.py:1202
|
||||
#, python-brace-format
|
||||
msgid "The jury {name} has been successfully removed!"
|
||||
msgstr "{name} a été retiré⋅e avec succès du jury !"
|
||||
|
||||
#: participation/views.py:1225
|
||||
#: participation/views.py:1228
|
||||
#, python-brace-format
|
||||
msgid "The jury {name} has been successfully promoted president!"
|
||||
msgstr "{name} a été nommé⋅e président⋅e du jury !"
|
||||
|
||||
#: participation/views.py:1253
|
||||
#: participation/views.py:1256
|
||||
msgid "The following user is not registered as a jury:"
|
||||
msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e :"
|
||||
|
||||
#: participation/views.py:1269
|
||||
#: participation/views.py:1272
|
||||
msgid "Notes were successfully uploaded."
|
||||
msgstr "Les notes ont bien été envoyées."
|
||||
|
||||
#: participation/views.py:1504
|
||||
msgid "Defender"
|
||||
#: participation/views.py:1507
|
||||
msgid "Reporter"
|
||||
msgstr "Défenseur⋅se"
|
||||
|
||||
#: participation/views.py:1510
|
||||
#: participation/views.py:1513
|
||||
msgid "Opponent"
|
||||
msgstr "Opposant⋅e"
|
||||
|
||||
#: participation/views.py:1517
|
||||
#: participation/views.py:1520
|
||||
msgid "Reviewer"
|
||||
msgstr "Rapporteur⋅rice"
|
||||
|
||||
#: participation/views.py:1524
|
||||
#: participation/views.py:1527
|
||||
msgid "Observer"
|
||||
msgstr "Observateur⋅rice"
|
||||
|
||||
#: participation/views.py:1895
|
||||
#: participation/views.py:1898
|
||||
#, python-brace-format
|
||||
msgid "Notation sheets of pool {pool} of {tournament}.zip"
|
||||
msgstr "Feuilles de notations pour la poule {pool} du tournoi {tournament}.zip"
|
||||
|
||||
#: participation/views.py:1900
|
||||
#: participation/views.py:1903
|
||||
#, python-brace-format
|
||||
msgid "Notation sheets of {tournament}.zip"
|
||||
msgstr "Feuilles de notation de {tournament}.zip"
|
||||
|
||||
#: participation/views.py:2067
|
||||
msgid "You can't upload a synthesis after the deadline."
|
||||
#: participation/views.py:2070
|
||||
msgid "You can't upload a written review after the deadline."
|
||||
msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite."
|
||||
|
||||
#: registration/admin.py:53 registration/admin.py:69 registration/admin.py:85
|
||||
|
@ -4,7 +4,7 @@
|
||||
from django.contrib import admin
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak
|
||||
from .models import Note, Participation, Passage, Pool, Solution, Team, Tournament, Tweak, WrittenReview
|
||||
|
||||
|
||||
class ParticipationInline(admin.StackedInline):
|
||||
@ -32,8 +32,8 @@ class SolutionInline(admin.TabularInline):
|
||||
show_change_link = True
|
||||
|
||||
|
||||
class SynthesisInline(admin.TabularInline):
|
||||
model = Synthesis
|
||||
class WrittenReviewInline(admin.TabularInline):
|
||||
model = WrittenReview
|
||||
extra = 0
|
||||
ordering = ('passage__solution_number', 'type',)
|
||||
autocomplete_fields = ('passage',)
|
||||
@ -51,7 +51,7 @@ class PassageInline(admin.TabularInline):
|
||||
model = Passage
|
||||
extra = 0
|
||||
ordering = ('position',)
|
||||
autocomplete_fields = ('defender', 'opponent', 'reviewer', 'observer',)
|
||||
autocomplete_fields = ('reporter', 'opponent', 'reviewer', 'observer',)
|
||||
show_change_link = True
|
||||
|
||||
|
||||
@ -95,7 +95,7 @@ class ParticipationAdmin(admin.ModelAdmin):
|
||||
search_fields = ('team__name', 'team__trigram',)
|
||||
list_filter = ('valid', 'tournament',)
|
||||
autocomplete_fields = ('team', 'tournament',)
|
||||
inlines = (SolutionInline, SynthesisInline,)
|
||||
inlines = (SolutionInline, WrittenReviewInline,)
|
||||
|
||||
|
||||
@admin.register(Pool)
|
||||
@ -113,17 +113,17 @@ class PoolAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(Passage)
|
||||
class PassageAdmin(admin.ModelAdmin):
|
||||
list_display = ('__str__', 'defender_trigram', 'solution_number', 'opponent_trigram', 'reviewer_trigram',
|
||||
list_display = ('__str__', 'reporter_trigram', 'solution_number', 'opponent_trigram', 'reviewer_trigram',
|
||||
'observer_trigram', 'pool_abbr', 'position', 'tournament')
|
||||
list_filter = ('pool__tournament', 'pool__round', 'pool__letter', 'solution_number',)
|
||||
search_fields = ('pool__participations__team__name', 'pool__participations__team__trigram',)
|
||||
ordering = ('pool__tournament', 'pool__round', 'pool__letter', 'position',)
|
||||
autocomplete_fields = ('pool', 'defender', 'opponent', 'reviewer', 'observer',)
|
||||
autocomplete_fields = ('pool', 'reporter', 'opponent', 'reviewer', 'observer',)
|
||||
inlines = (NoteInline,)
|
||||
|
||||
@admin.display(description=_("defender"), ordering='defender__team__trigram')
|
||||
def defender_trigram(self, record: Passage):
|
||||
return record.defender.team.trigram
|
||||
@admin.display(description=_("reporter"), ordering='reporter__team__trigram')
|
||||
def reporter_trigram(self, record: Passage):
|
||||
return record.reporter.team.trigram
|
||||
|
||||
@admin.display(description=_("opponent"), ordering='opponent__team__trigram')
|
||||
def opponent_trigram(self, record: Passage):
|
||||
@ -148,13 +148,13 @@ class PassageAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(Note)
|
||||
class NoteAdmin(admin.ModelAdmin):
|
||||
list_display = ('passage', 'pool', 'jury', 'defender_writing', 'defender_oral',
|
||||
list_display = ('passage', 'pool', 'jury', 'reporter_writing', 'reporter_oral',
|
||||
'opponent_writing', 'opponent_oral', 'reviewer_writing', 'reviewer_oral',
|
||||
'observer_writing', 'observer_oral',)
|
||||
list_filter = ('passage__pool__letter', 'passage__solution_number', 'jury',
|
||||
'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral',
|
||||
'reporter_writing', 'reporter_oral', 'opponent_writing', 'opponent_oral',
|
||||
'reviewer_writing', 'reviewer_oral', 'observer_writing', 'observer_oral')
|
||||
search_fields = ('jury__user__last_name', 'jury__user__first_name', 'passage__defender__team__trigram',)
|
||||
search_fields = ('jury__user__last_name', 'jury__user__first_name', 'passage__reporter__team__trigram',)
|
||||
autocomplete_fields = ('jury', 'passage',)
|
||||
|
||||
@admin.display(description=_("pool"))
|
||||
@ -178,19 +178,19 @@ class SolutionAdmin(admin.ModelAdmin):
|
||||
return Tournament.final_tournament() if record.final_solution else record.participation.tournament
|
||||
|
||||
|
||||
@admin.register(Synthesis)
|
||||
class SynthesisAdmin(admin.ModelAdmin):
|
||||
list_display = ('participation', 'type', 'defender', 'passage',)
|
||||
@admin.register(WrittenReview)
|
||||
class WrittenReviewAdmin(admin.ModelAdmin):
|
||||
list_display = ('participation', 'type', 'reporter', 'passage',)
|
||||
list_filter = ('participation__tournament', 'type', 'passage__solution_number',)
|
||||
search_fields = ('participation__team__name', 'participation__team__trigram',)
|
||||
autocomplete_fields = ('participation', 'passage',)
|
||||
|
||||
@admin.display(description=_("defender"))
|
||||
def defender(self, record: Synthesis):
|
||||
return record.passage.defender
|
||||
@admin.display(description=_("reporter"))
|
||||
def reporter(self, record: WrittenReview):
|
||||
return record.passage.reporter
|
||||
|
||||
@admin.display(description=_("problem"))
|
||||
def problem(self, record: Synthesis):
|
||||
def problem(self, record: WrittenReview):
|
||||
return record.passage.solution_number
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from ..models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament
|
||||
from ..models import Note, Participation, Passage, Pool, Solution, Team, Tournament, WrittenReview
|
||||
|
||||
|
||||
class NoteSerializer(serializers.ModelSerializer):
|
||||
@ -38,9 +38,9 @@ class SolutionSerializer(serializers.ModelSerializer):
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class SynthesisSerializer(serializers.ModelSerializer):
|
||||
class WrittenReviewSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Synthesis
|
||||
model = WrittenReview
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
@ -58,9 +58,9 @@ class TournamentSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Tournament
|
||||
fields = ('id', 'pk', 'name', 'date_start', 'date_end', 'place', 'max_teams', 'price', 'remote',
|
||||
'inscription_limit', 'solution_limit', 'solutions_draw', 'syntheses_first_phase_limit',
|
||||
'solutions_available_second_phase', 'syntheses_second_phase_limit',
|
||||
'solutions_available_third_phase', 'syntheses_third_phase_limit',
|
||||
'inscription_limit', 'solution_limit', 'solutions_draw', 'reviews_first_phase_limit',
|
||||
'solutions_available_second_phase', 'reviews_second_phase_limit',
|
||||
'solutions_available_third_phase', 'reviews_third_phase_limit',
|
||||
'description', 'organizers', 'final', 'participations',)
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from .views import NoteViewSet, ParticipationViewSet, PassageViewSet, PoolViewSet, \
|
||||
SolutionViewSet, SynthesisViewSet, TeamViewSet, TournamentViewSet, TweakViewSet
|
||||
SolutionViewSet, TeamViewSet, TournamentViewSet, TweakViewSet, WrittenReviewViewSet
|
||||
|
||||
|
||||
def register_participation_urls(router, path):
|
||||
@ -13,8 +13,8 @@ def register_participation_urls(router, path):
|
||||
router.register(path + "/participation", ParticipationViewSet)
|
||||
router.register(path + "/passage", PassageViewSet)
|
||||
router.register(path + "/pool", PoolViewSet)
|
||||
router.register(path + "/review", WrittenReviewViewSet)
|
||||
router.register(path + "/solution", SolutionViewSet)
|
||||
router.register(path + "/synthesis", SynthesisViewSet)
|
||||
router.register(path + "/team", TeamViewSet)
|
||||
router.register(path + "/tournament", TournamentViewSet)
|
||||
router.register(path + "/tweak", TweakViewSet)
|
||||
|
@ -4,15 +4,15 @@ from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from .serializers import NoteSerializer, ParticipationSerializer, PassageSerializer, PoolSerializer, \
|
||||
SolutionSerializer, SynthesisSerializer, TeamSerializer, TournamentSerializer, TweakSerializer
|
||||
from ..models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak
|
||||
SolutionSerializer, TeamSerializer, TournamentSerializer, TweakSerializer, WrittenReviewSerializer
|
||||
from ..models import Note, Participation, Passage, Pool, Solution, Team, Tournament, Tweak, WrittenReview
|
||||
|
||||
|
||||
class NoteViewSet(ModelViewSet):
|
||||
queryset = Note.objects.all()
|
||||
serializer_class = NoteSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ['jury', 'passage', 'defender_writing', 'defender_oral', 'opponent_writing',
|
||||
filterset_fields = ['jury', 'passage', 'reporter_writing', 'reporter_oral', 'opponent_writing',
|
||||
'opponent_oral', 'reviewer_writing', 'reviewer_oral', 'observer_writing', 'observer_oral', ]
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ class PassageViewSet(ModelViewSet):
|
||||
queryset = Passage.objects.all()
|
||||
serializer_class = PassageSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ['pool', 'solution_number', 'defender', 'opponent', 'reviewer', 'observer', 'pool_tournament', ]
|
||||
filterset_fields = ['pool', 'solution_number', 'reporter', 'opponent', 'reviewer', 'observer', 'pool_tournament', ]
|
||||
|
||||
|
||||
class PoolViewSet(ModelViewSet):
|
||||
@ -44,9 +44,9 @@ class SolutionViewSet(ModelViewSet):
|
||||
filterset_fields = ['participation', 'number', 'problem', 'final_solution', ]
|
||||
|
||||
|
||||
class SynthesisViewSet(ModelViewSet):
|
||||
queryset = Synthesis.objects.all()
|
||||
serializer_class = SynthesisSerializer
|
||||
class WrittenReviewViewSet(ModelViewSet):
|
||||
queryset = WrittenReview.objects.all()
|
||||
serializer_class = WrittenReviewSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ['participation', 'number', 'passage', 'type', ]
|
||||
|
||||
@ -64,9 +64,9 @@ class TournamentViewSet(ModelViewSet):
|
||||
serializer_class = TournamentSerializer
|
||||
filter_backends = [DjangoFilterBackend]
|
||||
filterset_fields = ['name', 'date_start', 'date_end', 'place', 'max_teams', 'price', 'remote',
|
||||
'inscription_limit', 'solution_limit', 'solutions_draw', 'syntheses_first_phase_limit',
|
||||
'solutions_available_second_phase', 'syntheses_second_phase_limit',
|
||||
'solutions_available_third_phase', 'syntheses_third_phase_limit',
|
||||
'inscription_limit', 'solution_limit', 'solutions_draw', 'reviews_first_phase_limit',
|
||||
'solutions_available_second_phase', 'reviews_second_phase_limit',
|
||||
'solutions_available_third_phase', 'reviews_third_phase_limit',
|
||||
'description', 'organizers', 'final', ]
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@ from pypdf import PdfReader
|
||||
from registration.models import VolunteerRegistration
|
||||
from tfjm import settings
|
||||
|
||||
from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament
|
||||
from .models import Note, Participation, Passage, Pool, Solution, Team, Tournament, WrittenReview
|
||||
|
||||
|
||||
class TeamForm(forms.ModelForm):
|
||||
@ -137,7 +137,7 @@ class TournamentForm(forms.ModelForm):
|
||||
if settings.NB_ROUNDS < 3:
|
||||
del self.fields['date_third_phase']
|
||||
del self.fields['solutions_available_third_phase']
|
||||
del self.fields['syntheses_third_phase_limit']
|
||||
del self.fields['reviews_third_phase_limit']
|
||||
if not settings.PAYMENT_MANAGEMENT:
|
||||
del self.fields['price']
|
||||
|
||||
@ -151,14 +151,14 @@ class TournamentForm(forms.ModelForm):
|
||||
'solution_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%d %H:%M'),
|
||||
'solutions_draw': forms.DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%d %H:%M'),
|
||||
'date_first_phase': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
|
||||
'syntheses_first_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
|
||||
format='%Y-%m-%d %H:%M'),
|
||||
'reviews_first_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
|
||||
format='%Y-%m-%d %H:%M'),
|
||||
'date_second_phase': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
|
||||
'syntheses_second_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
|
||||
format='%Y-%m-%d %H:%M'),
|
||||
'reviews_second_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
|
||||
format='%Y-%m-%d %H:%M'),
|
||||
'date_third_phase': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
|
||||
'syntheses_third_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
|
||||
format='%Y-%m-%d %H:%M'),
|
||||
'reviews_third_phase_limit': forms.DateTimeInput(attrs={'type': 'datetime-local'},
|
||||
format='%Y-%m-%d %H:%M'),
|
||||
'organizers': forms.SelectMultiple(attrs={
|
||||
'class': 'selectpicker',
|
||||
'data-live-search': 'true',
|
||||
@ -345,21 +345,21 @@ class UploadNotesForm(forms.Form):
|
||||
class PassageForm(forms.ModelForm):
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
if "defender" in cleaned_data and "opponent" in cleaned_data and "reviewer" in cleaned_data \
|
||||
and len({cleaned_data["defender"], cleaned_data["opponent"], cleaned_data["reviewer"]}) < 3:
|
||||
self.add_error(None, _("The defender, the opponent and the reviewer must be different."))
|
||||
if "defender" in self.cleaned_data and "solution_number" in self.cleaned_data \
|
||||
and not Solution.objects.filter(participation=cleaned_data["defender"],
|
||||
if "reporter" in cleaned_data and "opponent" in cleaned_data and "reviewer" in cleaned_data \
|
||||
and len({cleaned_data["reporter"], cleaned_data["opponent"], cleaned_data["reviewer"]}) < 3:
|
||||
self.add_error(None, _("The reporter, the opponent and the reviewer must be different."))
|
||||
if "reporter" in self.cleaned_data and "solution_number" in self.cleaned_data \
|
||||
and not Solution.objects.filter(participation=cleaned_data["reporter"],
|
||||
problem=cleaned_data["solution_number"]).exists():
|
||||
self.add_error("solution_number", _("This defender did not work on this problem."))
|
||||
self.add_error("solution_number", _("This reporter did not work on this problem."))
|
||||
return cleaned_data
|
||||
|
||||
class Meta:
|
||||
model = Passage
|
||||
fields = ('position', 'solution_number', 'defender', 'opponent', 'reviewer', 'opponent', 'defender_penalties',)
|
||||
fields = ('position', 'solution_number', 'reporter', 'opponent', 'reviewer', 'opponent', 'reporter_penalties',)
|
||||
|
||||
|
||||
class SynthesisForm(forms.ModelForm):
|
||||
class WrittenReviewForm(forms.ModelForm):
|
||||
def clean_file(self):
|
||||
if "file" in self.files:
|
||||
file = self.files["file"]
|
||||
@ -375,16 +375,16 @@ class SynthesisForm(forms.ModelForm):
|
||||
|
||||
def save(self, commit=True):
|
||||
"""
|
||||
Don't save a synthesis with this way. Use a view instead
|
||||
Don't save a written review with this way. Use a view instead
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Synthesis
|
||||
model = WrittenReview
|
||||
fields = ('file',)
|
||||
|
||||
|
||||
class NoteForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Note
|
||||
fields = ('defender_writing', 'defender_oral', 'opponent_writing',
|
||||
fields = ('reporter_writing', 'reporter_oral', 'opponent_writing',
|
||||
'opponent_oral', 'reviewer_writing', 'reviewer_oral', 'observer_writing', 'observer_oral', )
|
||||
|
@ -51,23 +51,23 @@ class Command(BaseCommand):
|
||||
team3, score3 = sorted_notes[2]
|
||||
|
||||
pool1 = tournament.pools.filter(round=1, participations=team2).first()
|
||||
defender_passage_1 = Passage.objects.get(pool__tournament=tournament, pool__round=1, defender=team2)
|
||||
reporter_passage_1 = Passage.objects.get(pool__tournament=tournament, pool__round=1, reporter=team2)
|
||||
opponent_passage_1 = Passage.objects.get(pool__tournament=tournament, pool__round=1, opponent=team2)
|
||||
reviewer_passage_1 = Passage.objects.get(pool__tournament=tournament, pool__round=1, reviewer=team2)
|
||||
pool2 = tournament.pools.filter(round=2, participations=team2).first()
|
||||
defender_passage_2 = Passage.objects.get(pool__tournament=tournament, pool__round=2, defender=team2)
|
||||
reporter_passage_2 = Passage.objects.get(pool__tournament=tournament, pool__round=2, reporter=team2)
|
||||
opponent_passage_2 = Passage.objects.get(pool__tournament=tournament, pool__round=2, opponent=team2)
|
||||
reviewer_passage_2 = Passage.objects.get(pool__tournament=tournament, pool__round=2, reviewer=team2)
|
||||
|
||||
line.append(team2.team.trigram)
|
||||
line.append(str(pool1.jury_president or ""))
|
||||
line.append(f"Pb. {defender_passage_1.solution_number}")
|
||||
line.extend([defender_passage_1.average_defender_writing, defender_passage_1.average_defender_oral,
|
||||
line.append(f"Pb. {reporter_passage_1.solution_number}")
|
||||
line.extend([reporter_passage_1.average_reporter_writing, reporter_passage_1.average_reporter_oral,
|
||||
opponent_passage_1.average_opponent_writing, opponent_passage_1.average_opponent_oral,
|
||||
reviewer_passage_1.average_reviewer_writing, reviewer_passage_1.average_reviewer_oral])
|
||||
line.append(str(pool2.jury_president or ""))
|
||||
line.append(f"Pb. {defender_passage_2.solution_number}")
|
||||
line.extend([defender_passage_2.average_defender_writing, defender_passage_2.average_defender_oral,
|
||||
line.append(f"Pb. {reporter_passage_2.solution_number}")
|
||||
line.extend([reporter_passage_2.average_reporter_writing, reporter_passage_2.average_reporter_oral,
|
||||
opponent_passage_2.average_opponent_writing, opponent_passage_2.average_opponent_oral,
|
||||
reviewer_passage_2.average_reviewer_writing, reviewer_passage_2.average_reviewer_oral])
|
||||
line.extend([score2, f"{score1:.1f} ({team1.team.trigram})",
|
||||
|
@ -0,0 +1,75 @@
|
||||
# Generated by Django 5.0.6 on 2024-07-06 19:19
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("participation", "0019_note_observer_oral_note_observer_writing_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name="Synthesis",
|
||||
new_name="WrittenReview",
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name="writtenreview",
|
||||
options={
|
||||
"ordering": ("passage__pool__round", "type"),
|
||||
"verbose_name": "written review",
|
||||
"verbose_name_plural": "written reviews",
|
||||
},
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="tournament",
|
||||
old_name="syntheses_first_phase_limit",
|
||||
new_name="reviews_first_phase_limit",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="tournament",
|
||||
old_name="syntheses_second_phase_limit",
|
||||
new_name="reviews_second_phase_limit",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="tournament",
|
||||
old_name="syntheses_third_phase_limit",
|
||||
new_name="reviews_third_phase_limit",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="tournament",
|
||||
name="reviews_first_phase_limit",
|
||||
field=models.DateTimeField(
|
||||
default=django.utils.timezone.now,
|
||||
verbose_name="limit date to upload the written reviews for the first phase",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="tournament",
|
||||
name="reviews_second_phase_limit",
|
||||
field=models.DateTimeField(
|
||||
default=django.utils.timezone.now,
|
||||
verbose_name="limit date to upload the written reviews for the second phase",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="tournament",
|
||||
name="reviews_third_phase_limit",
|
||||
field=models.DateTimeField(
|
||||
default=django.utils.timezone.now,
|
||||
verbose_name="limit date to upload the written reviews for the third phase",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="writtenreview",
|
||||
name="passage",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="written_reviews",
|
||||
to="participation.passage",
|
||||
verbose_name="passage",
|
||||
),
|
||||
),
|
||||
]
|
@ -0,0 +1,133 @@
|
||||
# Generated by Django 5.0.6 on 2024-07-06 20:00
|
||||
import django
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("participation", "0020_rename_synthesis_writtenreview_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="note",
|
||||
old_name="defender_oral",
|
||||
new_name="reporter_oral",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="note",
|
||||
old_name="defender_writing",
|
||||
new_name="reporter_writing",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="passage",
|
||||
old_name="defender",
|
||||
new_name="reporter",
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="passage",
|
||||
old_name="defender_penalties",
|
||||
new_name="reporter_penalties",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="passage",
|
||||
name="solution_number",
|
||||
field=models.PositiveSmallIntegerField(
|
||||
choices=[
|
||||
(1, "Problem #1"),
|
||||
(2, "Problem #2"),
|
||||
(3, "Problem #3"),
|
||||
(4, "Problem #4"),
|
||||
(5, "Problem #5"),
|
||||
(6, "Problem #6"),
|
||||
(7, "Problem #7"),
|
||||
(8, "Problem #8"),
|
||||
(9, "Problem #9"),
|
||||
(10, "Problem #10"),
|
||||
],
|
||||
verbose_name="reported solution",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="note",
|
||||
name="reporter_oral",
|
||||
field=models.PositiveSmallIntegerField(
|
||||
choices=[
|
||||
(0, 0),
|
||||
(1, 1),
|
||||
(2, 2),
|
||||
(3, 3),
|
||||
(4, 4),
|
||||
(5, 5),
|
||||
(6, 6),
|
||||
(7, 7),
|
||||
(8, 8),
|
||||
(9, 9),
|
||||
(10, 10),
|
||||
(11, 11),
|
||||
(12, 12),
|
||||
(13, 13),
|
||||
(14, 14),
|
||||
(15, 15),
|
||||
(16, 16),
|
||||
(17, 17),
|
||||
(18, 18),
|
||||
(19, 19),
|
||||
(20, 20),
|
||||
],
|
||||
default=0,
|
||||
verbose_name="reporter oral note",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="note",
|
||||
name="reporter_writing",
|
||||
field=models.PositiveSmallIntegerField(
|
||||
choices=[
|
||||
(0, 0),
|
||||
(1, 1),
|
||||
(2, 2),
|
||||
(3, 3),
|
||||
(4, 4),
|
||||
(5, 5),
|
||||
(6, 6),
|
||||
(7, 7),
|
||||
(8, 8),
|
||||
(9, 9),
|
||||
(10, 10),
|
||||
(11, 11),
|
||||
(12, 12),
|
||||
(13, 13),
|
||||
(14, 14),
|
||||
(15, 15),
|
||||
(16, 16),
|
||||
(17, 17),
|
||||
(18, 18),
|
||||
(19, 19),
|
||||
(20, 20),
|
||||
],
|
||||
default=0,
|
||||
verbose_name="reporter writing note",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="passage",
|
||||
name="reporter",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to="participation.participation",
|
||||
verbose_name="reporter",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="passage",
|
||||
name="reporter_penalties",
|
||||
field=models.PositiveSmallIntegerField(
|
||||
default=0,
|
||||
help_text="Number of penalties for the reporter. The reporter will loose a 0.5 coefficient per penalty.",
|
||||
verbose_name="penalties",
|
||||
),
|
||||
),
|
||||
]
|
@ -323,8 +323,8 @@ class Tournament(models.Model):
|
||||
default=date.today,
|
||||
)
|
||||
|
||||
syntheses_first_phase_limit = models.DateTimeField(
|
||||
verbose_name=_("limit date to upload the syntheses for the first phase"),
|
||||
reviews_first_phase_limit = models.DateTimeField(
|
||||
verbose_name=_("limit date to upload the written reviews for the first phase"),
|
||||
default=timezone.now,
|
||||
)
|
||||
|
||||
@ -338,8 +338,8 @@ class Tournament(models.Model):
|
||||
default=False,
|
||||
)
|
||||
|
||||
syntheses_second_phase_limit = models.DateTimeField(
|
||||
verbose_name=_("limit date to upload the syntheses for the second phase"),
|
||||
reviews_second_phase_limit = models.DateTimeField(
|
||||
verbose_name=_("limit date to upload the written reviews for the second phase"),
|
||||
default=timezone.now,
|
||||
)
|
||||
|
||||
@ -353,8 +353,8 @@ class Tournament(models.Model):
|
||||
default=False,
|
||||
)
|
||||
|
||||
syntheses_third_phase_limit = models.DateTimeField(
|
||||
verbose_name=_("limit date to upload the syntheses for the third phase"),
|
||||
reviews_third_phase_limit = models.DateTimeField(
|
||||
verbose_name=_("limit date to upload the written reviews for the third phase"),
|
||||
default=timezone.now,
|
||||
)
|
||||
|
||||
@ -442,10 +442,10 @@ class Tournament(models.Model):
|
||||
return Solution.objects.filter(participation__tournament=self)
|
||||
|
||||
@property
|
||||
def syntheses(self):
|
||||
def written_reviews(self):
|
||||
if self.final:
|
||||
return Synthesis.objects.filter(final_solution=True)
|
||||
return Synthesis.objects.filter(participation__tournament=self)
|
||||
return WrittenReview.objects.filter(final_solution=True)
|
||||
return WrittenReview.objects.filter(participation__tournament=self)
|
||||
|
||||
@property
|
||||
def best_format(self):
|
||||
@ -490,7 +490,7 @@ class Tournament(models.Model):
|
||||
line = [f"{participation.team.name} ({participation.team.trigram})"]
|
||||
lines.append(line)
|
||||
|
||||
passage1 = Passage.objects.get(pool__tournament=self, pool__round=1, defender=participation)
|
||||
passage1 = Passage.objects.get(pool__tournament=self, pool__round=1, reporter=participation)
|
||||
pool1 = passage1.pool
|
||||
if pool1.participations.count() != 5:
|
||||
position1 = passage1.position
|
||||
@ -502,8 +502,8 @@ class Tournament(models.Model):
|
||||
line.append(f"=SIERREUR('{_('Pool')} {pool1.short_name}'!$D{pool1.juries.count() + 10 + position1}; 0)")
|
||||
line.append(tweak1.diff if tweak1 else 0)
|
||||
|
||||
if Passage.objects.filter(pool__tournament=self, pool__round=2, defender=participation).exists():
|
||||
passage2 = Passage.objects.get(pool__tournament=self, pool__round=2, defender=participation)
|
||||
if Passage.objects.filter(pool__tournament=self, pool__round=2, reporter=participation).exists():
|
||||
passage2 = Passage.objects.get(pool__tournament=self, pool__round=2, reporter=participation)
|
||||
pool2 = passage2.pool
|
||||
if pool2.participations.count() != 5:
|
||||
position2 = passage2.position
|
||||
@ -519,8 +519,8 @@ class Tournament(models.Model):
|
||||
if settings.NB_ROUNDS >= 3:
|
||||
line.append(f"=$B{i + 2} + $C{i + 2} + $D{i + 2} + E{i + 2}")
|
||||
|
||||
if Passage.objects.filter(pool__tournament=self, pool__round=3, defender=participation).exists():
|
||||
passage3 = Passage.objects.get(pool__tournament=self, pool__round=3, defender=participation)
|
||||
if Passage.objects.filter(pool__tournament=self, pool__round=3, reporter=participation).exists():
|
||||
passage3 = Passage.objects.get(pool__tournament=self, pool__round=3, reporter=participation)
|
||||
pool3 = passage3.pool
|
||||
if pool3.participations.count() != 5:
|
||||
position3 = passage3.position
|
||||
@ -911,128 +911,128 @@ class Participation(models.Model):
|
||||
'priority': 1,
|
||||
'content': content,
|
||||
})
|
||||
elif timezone.now() <= tournament.syntheses_first_phase_limit + timedelta(hours=2):
|
||||
defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, defender=self)
|
||||
elif timezone.now() <= tournament.reviews_first_phase_limit + timedelta(hours=2):
|
||||
reporter_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, reporter=self)
|
||||
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, opponent=self)
|
||||
reviewer_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, reviewer=self)
|
||||
observer_passage = Passage.objects.filter(pool__tournament=self.tournament, pool__round=1, observer=self)
|
||||
observer_passage = observer_passage.get() if observer_passage.exists() else None
|
||||
|
||||
defender_text = _("<p>The solutions draw is ended. You can check the result on "
|
||||
reporter_text = _("<p>The solutions draw is ended. You can check the result on "
|
||||
"<a href='{draw_url}'>this page</a>.</p>"
|
||||
"<p>For the first round, you will defend "
|
||||
"<p>For the first round, you will present "
|
||||
"<a href='{solution_url}'>your solution of the problem {problem}</a>.</p>")
|
||||
draw_url = reverse_lazy("draw:index")
|
||||
solution_url = defender_passage.defended_solution.file.url
|
||||
defender_content = format_lazy(defender_text, draw_url=draw_url,
|
||||
solution_url=solution_url, problem=defender_passage.solution_number)
|
||||
solution_url = reporter_passage.reported_solution.file.url
|
||||
reporter_content = format_lazy(reporter_text, draw_url=draw_url,
|
||||
solution_url=solution_url, problem=reporter_passage.solution_number)
|
||||
|
||||
opponent_text = _("<p>You will oppose the solution of the team {opponent} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = opponent_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = opponent_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(opponent_passage.pk,))
|
||||
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.defender.team.trigram,
|
||||
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=opponent_passage.solution_number, passage_url=passage_url)
|
||||
|
||||
reviewer_text = _("<p>You will report the solution of the team {reviewer} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = reviewer_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = reviewer_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,))
|
||||
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram,
|
||||
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=reviewer_passage.solution_number, passage_url=passage_url)
|
||||
|
||||
if observer_passage:
|
||||
observer_text = _("<p>You will observe the solution of the team {observer} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = observer_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = observer_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(observer_passage.pk,))
|
||||
observer_content = format_lazy(observer_text,
|
||||
observer=observer_passage.defender.team.trigram,
|
||||
observer=observer_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=observer_passage.solution_number, passage_url=passage_url)
|
||||
else:
|
||||
observer_content = ""
|
||||
|
||||
if settings.TFJM_APP == "TFJM":
|
||||
syntheses_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
|
||||
syntheses_templates = " — ".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex", "odt", "docx"])
|
||||
reviews_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
|
||||
reviews_templates = " — ".join(f"<a href='{reviews_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex", "odt", "docx"])
|
||||
else:
|
||||
syntheses_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
|
||||
syntheses_templates = " — ".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex"])
|
||||
syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>"
|
||||
reviews_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
|
||||
reviews_templates = " — ".join(f"<a href='{reviews_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex"])
|
||||
reviews_templates_content = f"<p>{_('Templates:')} {reviews_templates}</p>"
|
||||
|
||||
content = defender_content + opponent_content + reviewer_content + observer_content \
|
||||
+ syntheses_templates_content
|
||||
content = reporter_content + opponent_content + reviewer_content + observer_content \
|
||||
+ reviews_templates_content
|
||||
informations.append({
|
||||
'title': _("First round"),
|
||||
'type': "info",
|
||||
'priority': 1,
|
||||
'content': content,
|
||||
})
|
||||
elif timezone.now() <= tournament.syntheses_second_phase_limit + timedelta(hours=2):
|
||||
defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, defender=self)
|
||||
elif timezone.now() <= tournament.reviews_second_phase_limit + timedelta(hours=2):
|
||||
reporter_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, reporter=self)
|
||||
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, opponent=self)
|
||||
reviewer_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, reviewer=self)
|
||||
observer_passage = Passage.objects.filter(pool__tournament=self.tournament, pool__round=2, observer=self)
|
||||
observer_passage = observer_passage.get() if observer_passage.exists() else None
|
||||
|
||||
defender_text = _("<p>For the second round, you will defend "
|
||||
reporter_text = _("<p>For the second round, you will present "
|
||||
"<a href='{solution_url}'>your solution of the problem {problem}</a>.</p>")
|
||||
draw_url = reverse_lazy("draw:index")
|
||||
solution_url = defender_passage.defended_solution.file.url
|
||||
defender_content = format_lazy(defender_text, draw_url=draw_url,
|
||||
solution_url=solution_url, problem=defender_passage.solution_number)
|
||||
solution_url = reporter_passage.reported_solution.file.url
|
||||
reporter_content = format_lazy(reporter_text, draw_url=draw_url,
|
||||
solution_url=solution_url, problem=reporter_passage.solution_number)
|
||||
|
||||
opponent_text = _("<p>You will oppose the solution of the team {opponent} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = opponent_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = opponent_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(opponent_passage.pk,))
|
||||
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.defender.team.trigram,
|
||||
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=opponent_passage.solution_number, passage_url=passage_url)
|
||||
|
||||
reviewer_text = _("<p>You will report the solution of the team {reviewer} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = reviewer_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = reviewer_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,))
|
||||
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram,
|
||||
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=reviewer_passage.solution_number, passage_url=passage_url)
|
||||
|
||||
if observer_passage:
|
||||
observer_text = _("<p>You will observe the solution of the team {observer} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = observer_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = observer_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(observer_passage.pk,))
|
||||
observer_content = format_lazy(observer_text,
|
||||
observer=observer_passage.defender.team.trigram,
|
||||
observer=observer_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=observer_passage.solution_number, passage_url=passage_url)
|
||||
else:
|
||||
observer_content = ""
|
||||
|
||||
if settings.TFJM_APP == "TFJM":
|
||||
syntheses_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
|
||||
syntheses_templates = " — ".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex", "odt", "docx"])
|
||||
reviews_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
|
||||
reviews_templates = " — ".join(f"<a href='{reviews_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex", "odt", "docx"])
|
||||
else:
|
||||
syntheses_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
|
||||
syntheses_templates = " — ".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex"])
|
||||
syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>"
|
||||
reviews_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
|
||||
reviews_templates = " — ".join(f"<a href='{reviews_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex"])
|
||||
reviews_templates_content = f"<p>{_('Templates:')} {reviews_templates}</p>"
|
||||
|
||||
content = defender_content + opponent_content + reviewer_content + observer_content \
|
||||
+ syntheses_templates_content
|
||||
content = reporter_content + opponent_content + reviewer_content + observer_content \
|
||||
+ reviews_templates_content
|
||||
informations.append({
|
||||
'title': _("Second round"),
|
||||
'type': "info",
|
||||
@ -1040,63 +1040,63 @@ class Participation(models.Model):
|
||||
'content': content,
|
||||
})
|
||||
elif settings.TFJM_APP == "ETEAM" \
|
||||
and timezone.now() <= tournament.syntheses_third_phase_limit + timedelta(hours=2):
|
||||
defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, defender=self)
|
||||
and timezone.now() <= tournament.reviews_third_phase_limit + timedelta(hours=2):
|
||||
reporter_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, reporter=self)
|
||||
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, opponent=self)
|
||||
reviewer_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, reviewer=self)
|
||||
observer_passage = Passage.objects.filter(pool__tournament=self.tournament, pool__round=3, observer=self)
|
||||
observer_passage = observer_passage.get() if observer_passage.exists() else None
|
||||
|
||||
defender_text = _("<p>For the third round, you will defend "
|
||||
reporter_text = _("<p>For the third round, you will present "
|
||||
"<a href='{solution_url}'>your solution of the problem {problem}</a>.</p>")
|
||||
draw_url = reverse_lazy("draw:index")
|
||||
solution_url = defender_passage.defended_solution.file.url
|
||||
defender_content = format_lazy(defender_text, draw_url=draw_url,
|
||||
solution_url=solution_url, problem=defender_passage.solution_number)
|
||||
solution_url = reporter_passage.reported_solution.file.url
|
||||
reporter_content = format_lazy(reporter_text, draw_url=draw_url,
|
||||
solution_url=solution_url, problem=reporter_passage.solution_number)
|
||||
|
||||
opponent_text = _("<p>You will oppose the solution of the team {opponent} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = opponent_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = opponent_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(opponent_passage.pk,))
|
||||
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.defender.team.trigram,
|
||||
opponent_content = format_lazy(opponent_text, opponent=opponent_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=opponent_passage.solution_number, passage_url=passage_url)
|
||||
|
||||
reviewer_text = _("<p>You will report the solution of the team {reviewer} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = reviewer_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = reviewer_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,))
|
||||
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram,
|
||||
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=reviewer_passage.solution_number, passage_url=passage_url)
|
||||
|
||||
if observer_passage:
|
||||
observer_text = _("<p>You will observe the solution of the team {observer} on the "
|
||||
"<a href='{solution_url}'>problem {problem}</a>. "
|
||||
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = observer_passage.defended_solution.file.url
|
||||
"You can upload your written review on <a href='{passage_url}'>this page</a>.</p>")
|
||||
solution_url = observer_passage.reported_solution.file.url
|
||||
passage_url = reverse_lazy("participation:passage_detail", args=(observer_passage.pk,))
|
||||
observer_content = format_lazy(observer_text,
|
||||
observer=observer_passage.defender.team.trigram,
|
||||
observer=observer_passage.reporter.team.trigram,
|
||||
solution_url=solution_url,
|
||||
problem=observer_passage.solution_number, passage_url=passage_url)
|
||||
else:
|
||||
observer_content = ""
|
||||
|
||||
if settings.TFJM_APP == "TFJM":
|
||||
syntheses_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
|
||||
syntheses_templates = " — ".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex", "odt", "docx"])
|
||||
reviews_template_begin = f"{settings.STATIC_URL}tfjm/Fiche_synthèse."
|
||||
reviews_templates = " — ".join(f"<a href='{reviews_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex", "odt", "docx"])
|
||||
else:
|
||||
syntheses_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
|
||||
syntheses_templates = " — ".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex"])
|
||||
syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>"
|
||||
reviews_template_begin = f"{settings.STATIC_URL}eteam/Written_review."
|
||||
reviews_templates = " — ".join(f"<a href='{reviews_template_begin}{ext}'>{ext.upper()}</a>"
|
||||
for ext in ["pdf", "tex"])
|
||||
reviews_templates_content = f"<p>{_('Templates:')} {reviews_templates}</p>"
|
||||
|
||||
content = defender_content + opponent_content + reviewer_content + observer_content \
|
||||
+ syntheses_templates_content
|
||||
content = reporter_content + opponent_content + reviewer_content + observer_content \
|
||||
+ reviews_templates_content
|
||||
informations.append({
|
||||
'title': _("Second round"),
|
||||
'type': "info",
|
||||
@ -1204,7 +1204,7 @@ class Pool(models.Model):
|
||||
|
||||
@property
|
||||
def solutions(self):
|
||||
return [passage.defended_solution for passage in self.passages.all()]
|
||||
return [passage.reported_solution for passage in self.passages.all()]
|
||||
|
||||
@property
|
||||
def coeff(self):
|
||||
@ -1251,12 +1251,12 @@ class Pool(models.Model):
|
||||
header = [
|
||||
sum(([str(_("Problem #{problem}").format(problem=passage.solution_number))] + (passage_width - 1) * [""]
|
||||
for passage in passages), start=[str(_("Problem")), ""]),
|
||||
sum(([f"{_('Defender')} ({passage.defender.team.trigram})", "",
|
||||
sum(([f"{_('Reporter')} ({passage.reporter.team.trigram})", "",
|
||||
f"{_('Opponent')} ({passage.opponent.team.trigram})", "",
|
||||
f"{_('Reviewer')} ({passage.reviewer.team.trigram})", ""]
|
||||
+ ([f"{_('Observer')} ({passage.observer.team.trigram})", ""] if has_observer else [])
|
||||
for passage in passages), start=[str(_("Role")), ""]),
|
||||
sum(([f"{_('Writing')} (/{20 if settings.TFJM_APP == "TFJM" else 10})",
|
||||
sum(([f"{_('Writing')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})",
|
||||
f"{_('Oral')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})",
|
||||
f"{_('Writing')} (/10)", f"{_('Oral')} (/10)", f"{_('Writing')} (/10)", f"{_('Oral')} (/10)"]
|
||||
+ ([f"{_('Writing')} (/10)", f"{_('Oral')} (/10)"] if has_observer else [])
|
||||
@ -1268,7 +1268,7 @@ class Pool(models.Model):
|
||||
line = [str(jury), jury.id]
|
||||
for passage in passages:
|
||||
note = passage.notes.filter(jury=jury).first()
|
||||
line.extend([note.defender_writing, note.defender_oral, note.opponent_writing, note.opponent_oral,
|
||||
line.extend([note.reporter_writing, note.reporter_oral, note.opponent_writing, note.opponent_oral,
|
||||
note.reviewer_writing, note.reviewer_oral])
|
||||
if has_observer:
|
||||
line.extend([note.observer_writing, note.observer_oral])
|
||||
@ -1284,7 +1284,7 @@ class Pool(models.Model):
|
||||
return getcol((number - 1) // 26) + chr(65 + (number - 1) % 26)
|
||||
|
||||
average = [str(_("Average")), ""]
|
||||
coeffs = sum(([passage.coeff_defender_writing, passage.coeff_defender_oral,
|
||||
coeffs = sum(([passage.coeff_reporter_writing, passage.coeff_reporter_oral,
|
||||
passage.coeff_opponent_writing, passage.coeff_opponent_oral,
|
||||
passage.coeff_reviewer_writing, passage.coeff_reviewer_oral]
|
||||
+ ([passage.coeff_observer_writing, passage.coeff_observer_oral] if has_observer else [])
|
||||
@ -1330,11 +1330,11 @@ class Pool(models.Model):
|
||||
pool__round=self.round,
|
||||
pool__letter=self.letter).order_by('position', 'pool__room')
|
||||
for i, passage in enumerate(all_passages):
|
||||
participation = passage.defender
|
||||
defender_passage = Passage.objects.get(defender=participation,
|
||||
participation = passage.reporter
|
||||
reporter_passage = Passage.objects.get(reporter=participation,
|
||||
pool__tournament=self.tournament, pool__round=self.round)
|
||||
defender_row = 5 + defender_passage.pool.juries.count()
|
||||
defender_col = defender_passage.position - 1
|
||||
reporter_row = 5 + reporter_passage.pool.juries.count()
|
||||
reporter_col = reporter_passage.position - 1
|
||||
|
||||
opponent_passage = Passage.objects.get(opponent=participation,
|
||||
pool__tournament=self.tournament, pool__round=self.round)
|
||||
@ -1347,8 +1347,8 @@ class Pool(models.Model):
|
||||
reviewer_col = reviewer_passage.position - 1
|
||||
|
||||
formula = "="
|
||||
formula += (f"'{_('Pool')} {defender_passage.pool.short_name}'"
|
||||
f"!{getcol(min_column + defender_col * passage_width)}{defender_row + 3}") # Defender
|
||||
formula += (f"'{_('Pool')} {reporter_passage.pool.short_name}'"
|
||||
f"!{getcol(min_column + reporter_col * passage_width)}{reporter_row + 3}") # Reporter
|
||||
formula += (f" + '{_('Pool')} {opponent_passage.pool.short_name}'"
|
||||
f"!{getcol(min_column + opponent_col * passage_width + 2)}{opponent_row + 3}") # Opponent
|
||||
formula += (f" + '{_('Pool')} {reviewer_passage.pool.short_name}'"
|
||||
@ -1362,8 +1362,8 @@ class Pool(models.Model):
|
||||
f"!{getcol(min_column + observer_col * passage_width + 6)}{observer_row + 3}")
|
||||
|
||||
ranking.append([f"{participation.team.name} ({participation.team.trigram})", "",
|
||||
f"='{_('Pool')} {defender_passage.pool.short_name}'"
|
||||
f"!${getcol(3 + defender_col * passage_width)}$1",
|
||||
f"='{_('Pool')} {reporter_passage.pool.short_name}'"
|
||||
f"!${getcol(3 + reporter_col * passage_width)}$1",
|
||||
formula,
|
||||
f"=RANG(D{max_row + 6 + i}; "
|
||||
f"D${max_row + 6}:D${max_row + 5 + pool_size})"])
|
||||
@ -1430,7 +1430,7 @@ class Pool(models.Model):
|
||||
(f"A{max_row + 6}:E{max_row + 5 + pool_size}", (0.9, 0.9, 0.9)),]
|
||||
# Display penalties in red
|
||||
bg_colors += [(f"{getcol(2 + (passage.position - 1) * passage_width + 2)}{max_row + 2}", (1.0, 0.7, 0.7))
|
||||
for passage in self.passages.filter(defender_penalties__gte=1).all()]
|
||||
for passage in self.passages.filter(reporter_penalties__gte=1).all()]
|
||||
for bg_range, bg_color in bg_colors:
|
||||
r, g, b = bg_color
|
||||
format_requests.append({
|
||||
@ -1684,16 +1684,16 @@ class Passage(models.Model):
|
||||
)
|
||||
|
||||
solution_number = models.PositiveSmallIntegerField(
|
||||
verbose_name=_("defended solution"),
|
||||
verbose_name=_("reported solution"),
|
||||
choices=[
|
||||
(i, format_lazy(_("Problem #{problem}"), problem=i)) for i in range(1, len(settings.PROBLEMS) + 1)
|
||||
],
|
||||
)
|
||||
|
||||
defender = models.ForeignKey(
|
||||
reporter = models.ForeignKey(
|
||||
Participation,
|
||||
on_delete=models.PROTECT,
|
||||
verbose_name=_("defender"),
|
||||
verbose_name=_("reporter"),
|
||||
related_name="+",
|
||||
)
|
||||
|
||||
@ -1721,17 +1721,17 @@ class Passage(models.Model):
|
||||
default=None,
|
||||
)
|
||||
|
||||
defender_penalties = models.PositiveSmallIntegerField(
|
||||
reporter_penalties = models.PositiveSmallIntegerField(
|
||||
verbose_name=_("penalties"),
|
||||
default=0,
|
||||
help_text=_("Number of penalties for the defender. "
|
||||
"The defender will loose a 0.5 coefficient per penalty."),
|
||||
help_text=_("Number of penalties for the reporter. "
|
||||
"The reporter will loose a 0.5 coefficient per penalty."),
|
||||
)
|
||||
|
||||
@property
|
||||
def defended_solution(self) -> "Solution":
|
||||
def reported_solution(self) -> "Solution":
|
||||
return Solution.objects.get(
|
||||
participation=self.defender,
|
||||
participation=self.reporter,
|
||||
problem=self.solution_number,
|
||||
final_solution=self.pool.tournament.final)
|
||||
|
||||
@ -1740,27 +1740,27 @@ class Passage(models.Model):
|
||||
return sum(items) / len(items) if items else 0
|
||||
|
||||
@property
|
||||
def average_defender_writing(self) -> float:
|
||||
return self.avg(note.defender_writing for note in self.notes.all())
|
||||
def average_reporter_writing(self) -> float:
|
||||
return self.avg(note.reporter_writing for note in self.notes.all())
|
||||
|
||||
@property
|
||||
def coeff_defender_writing(self) -> float:
|
||||
def coeff_reporter_writing(self) -> float:
|
||||
return 1 if settings.TFJM_APP == "TFJM" else 2
|
||||
|
||||
@property
|
||||
def average_defender_oral(self) -> float:
|
||||
return self.avg(note.defender_oral for note in self.notes.all())
|
||||
def average_reporter_oral(self) -> float:
|
||||
return self.avg(note.reporter_oral for note in self.notes.all())
|
||||
|
||||
@property
|
||||
def coeff_defender_oral(self) -> float:
|
||||
def coeff_reporter_oral(self) -> float:
|
||||
coeff = 1.6 if settings.TFJM_APP == "TFJM" else 3
|
||||
coeff *= 1 - 0.25 * self.defender_penalties
|
||||
coeff *= 1 - 0.25 * self.reporter_penalties
|
||||
return coeff
|
||||
|
||||
@property
|
||||
def average_defender(self) -> float:
|
||||
return (self.coeff_defender_writing * self.average_defender_writing
|
||||
+ self.coeff_defender_oral * self.average_defender_oral)
|
||||
def average_reporter(self) -> float:
|
||||
return (self.coeff_reporter_writing * self.average_reporter_writing
|
||||
+ self.coeff_reporter_oral * self.average_reporter_oral)
|
||||
|
||||
@property
|
||||
def average_opponent_writing(self) -> float:
|
||||
@ -1827,8 +1827,8 @@ class Passage(models.Model):
|
||||
|
||||
@property
|
||||
def averages(self):
|
||||
yield self.average_defender_writing
|
||||
yield self.average_defender_oral
|
||||
yield self.average_reporter_writing
|
||||
yield self.average_reporter_oral
|
||||
yield self.average_opponent_writing
|
||||
yield self.average_opponent_oral
|
||||
yield self.average_reviewer_writing
|
||||
@ -1838,7 +1838,7 @@ class Passage(models.Model):
|
||||
yield self.average_observer_oral
|
||||
|
||||
def average(self, participation):
|
||||
avg = self.average_defender if participation == self.defender else self.average_opponent \
|
||||
avg = self.average_reporter if participation == self.reporter else self.average_opponent \
|
||||
if participation == self.opponent else self.average_reviewer if participation == self.reviewer \
|
||||
else self.average_observer if participation == self.observer else 0
|
||||
avg *= self.pool.coeff
|
||||
@ -1849,9 +1849,9 @@ class Passage(models.Model):
|
||||
return reverse_lazy("participation:passage_detail", args=(self.pk,))
|
||||
|
||||
def clean(self):
|
||||
if self.defender not in self.pool.participations.all():
|
||||
if self.reporter not in self.pool.participations.all():
|
||||
raise ValidationError(_("Team {trigram} is not registered in the pool.")
|
||||
.format(trigram=self.defender.team.trigram))
|
||||
.format(trigram=self.reporter.team.trigram))
|
||||
if self.opponent not in self.pool.participations.all():
|
||||
raise ValidationError(_("Team {trigram} is not registered in the pool.")
|
||||
.format(trigram=self.opponent.team.trigram))
|
||||
@ -1864,8 +1864,8 @@ class Passage(models.Model):
|
||||
return super().clean()
|
||||
|
||||
def __str__(self):
|
||||
return _("Passage of {defender} for problem {problem}")\
|
||||
.format(defender=self.defender.team, problem=self.solution_number)
|
||||
return _("Passage of {reporter} for problem {problem}")\
|
||||
.format(reporter=self.reporter.team, problem=self.solution_number)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("passage")
|
||||
@ -1905,8 +1905,12 @@ def get_solution_filename(instance, filename):
|
||||
+ ("_final" if instance.final_solution else "")
|
||||
|
||||
|
||||
def get_review_filename(instance, filename):
|
||||
return f"reviews/{instance.participation.team.trigram}_{instance.type}_{instance.passage.pk}"
|
||||
|
||||
|
||||
def get_synthesis_filename(instance, filename):
|
||||
return f"syntheses/{instance.participation.team.trigram}_{instance.type}_{instance.passage.pk}"
|
||||
return get_review_filename(instance, filename)
|
||||
|
||||
|
||||
class Solution(models.Model):
|
||||
@ -1951,7 +1955,7 @@ class Solution(models.Model):
|
||||
ordering = ('participation__team__trigram', 'final_solution', 'problem',)
|
||||
|
||||
|
||||
class Synthesis(models.Model):
|
||||
class WrittenReview(models.Model):
|
||||
participation = models.ForeignKey(
|
||||
Participation,
|
||||
on_delete=models.CASCADE,
|
||||
@ -1961,7 +1965,7 @@ class Synthesis(models.Model):
|
||||
passage = models.ForeignKey(
|
||||
Passage,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="syntheses",
|
||||
related_name="written_reviews",
|
||||
verbose_name=_("passage"),
|
||||
)
|
||||
|
||||
@ -1980,16 +1984,16 @@ class Synthesis(models.Model):
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return _("Synthesis of {team} as {type} for problem {problem} of {defender}").format(
|
||||
return _("Written review of {team} as {type} for problem {problem} of {reporter}").format(
|
||||
team=self.participation.team.trigram,
|
||||
type=self.get_type_display(),
|
||||
problem=self.passage.solution_number,
|
||||
defender=self.passage.defender.team.trigram,
|
||||
reporter=self.passage.reporter.team.trigram,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("synthesis")
|
||||
verbose_name_plural = _("syntheses")
|
||||
verbose_name = _("written review")
|
||||
verbose_name_plural = _("written reviews")
|
||||
unique_together = (('participation', 'passage', 'type', ), )
|
||||
ordering = ('passage__pool__round', 'type',)
|
||||
|
||||
@ -2009,14 +2013,14 @@ class Note(models.Model):
|
||||
related_name="notes",
|
||||
)
|
||||
|
||||
defender_writing = models.PositiveSmallIntegerField(
|
||||
verbose_name=_("defender writing note"),
|
||||
reporter_writing = models.PositiveSmallIntegerField(
|
||||
verbose_name=_("reporter writing note"),
|
||||
choices=[(i, i) for i in range(0, 21)],
|
||||
default=0,
|
||||
)
|
||||
|
||||
defender_oral = models.PositiveSmallIntegerField(
|
||||
verbose_name=_("defender oral note"),
|
||||
reporter_oral = models.PositiveSmallIntegerField(
|
||||
verbose_name=_("reporter oral note"),
|
||||
choices=[(i, i) for i in range(0, 21)],
|
||||
default=0,
|
||||
)
|
||||
@ -2058,8 +2062,8 @@ class Note(models.Model):
|
||||
)
|
||||
|
||||
def get_all(self):
|
||||
yield self.defender_writing
|
||||
yield self.defender_oral
|
||||
yield self.reporter_writing
|
||||
yield self.reporter_oral
|
||||
yield self.opponent_writing
|
||||
yield self.opponent_oral
|
||||
yield self.reviewer_writing
|
||||
@ -2068,10 +2072,10 @@ class Note(models.Model):
|
||||
yield self.observer_writing
|
||||
yield self.observer_oral
|
||||
|
||||
def set_all(self, defender_writing: int, defender_oral: int, opponent_writing: int, opponent_oral: int,
|
||||
def set_all(self, reporter_writing: int, reporter_oral: int, opponent_writing: int, opponent_oral: int,
|
||||
reviewer_writing: int, reviewer_oral: int, observer_writing: int = 0, observer_oral: int = 0):
|
||||
self.defender_writing = defender_writing
|
||||
self.defender_oral = defender_oral
|
||||
self.reporter_writing = reporter_writing
|
||||
self.reporter_oral = reporter_oral
|
||||
self.opponent_writing = opponent_writing
|
||||
self.opponent_oral = opponent_oral
|
||||
self.reviewer_writing = reviewer_writing
|
||||
|
@ -108,13 +108,13 @@ class PoolTable(tables.Table):
|
||||
class PassageTable(tables.Table):
|
||||
# FIXME Ne pas afficher l'équipe observatrice si non nécessaire
|
||||
|
||||
defender = tables.LinkColumn(
|
||||
reporter = tables.LinkColumn(
|
||||
"participation:passage_detail",
|
||||
args=[tables.A("id")],
|
||||
verbose_name=_("defender").capitalize,
|
||||
verbose_name=_("reporter").capitalize,
|
||||
)
|
||||
|
||||
def render_defender(self, value):
|
||||
def render_reporter(self, value):
|
||||
return value.team.trigram
|
||||
|
||||
def render_opponent(self, value):
|
||||
@ -131,7 +131,7 @@ class PassageTable(tables.Table):
|
||||
'class': 'table table-condensed table-striped text-center',
|
||||
}
|
||||
model = Passage
|
||||
fields = ('defender', 'opponent', 'reviewer', 'observer', 'solution_number', )
|
||||
fields = ('reporter', 'opponent', 'reviewer', 'observer', 'solution_number', )
|
||||
|
||||
|
||||
class NoteTable(tables.Table):
|
||||
@ -159,5 +159,5 @@ class NoteTable(tables.Table):
|
||||
'class': 'table table-condensed table-striped text-center',
|
||||
}
|
||||
model = Note
|
||||
fields = ('jury', 'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral',
|
||||
fields = ('jury', 'reporter_writing', 'reporter_oral', 'opponent_writing', 'opponent_oral',
|
||||
'reviewer_writing', 'reviewer_oral', 'observer_writing', 'observer_oral', 'update',)
|
||||
|
@ -6,7 +6,7 @@
|
||||
<form method="post">
|
||||
<div id="form-content">
|
||||
<h4>{% trans "Notes of" %} {{ note.jury }}</h4>
|
||||
<h5>{% trans "Defense of" %} {{ note.passage.defender.team.trigram }}, {% trans "Pb." %} {{ note.passage.solution_number }}</h5>
|
||||
<h5>{% trans "Defense of" %} {{ note.passage.reporter.team.trigram }}, {% trans "Pb." %} {{ note.passage.solution_number }}</h5>
|
||||
<hr>
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
|
@ -25,8 +25,8 @@
|
||||
<dt class="col-sm-3">{% trans "Position:" %}</dt>
|
||||
<dd class="col-sm-9">{{ passage.position }}</dd>
|
||||
|
||||
<dt class="col-sm-3">{% trans "Defender:" %}</dt>
|
||||
<dd class="col-sm-9"><a href="{{ passage.defender.get_absolute_url }}">{{ passage.defender.team }}</a></dd>
|
||||
<dt class="col-sm-3">{% trans "Reporter:" %}</dt>
|
||||
<dd class="col-sm-9"><a href="{{ passage.reporter.get_absolute_url }}">{{ passage.reporter.team }}</a></dd>
|
||||
|
||||
<dt class="col-sm-3">{% trans "Opponent:" %}</dt>
|
||||
<dd class="col-sm-9"><a href="{{ passage.opponent.get_absolute_url }}">{{ passage.opponent.team }}</a></dd>
|
||||
@ -39,18 +39,18 @@
|
||||
<dd class="col-sm-9"><a href="{{ passage.observer.get_absolute_url }}">{{ passage.observer.team }}</a></dd>
|
||||
{% endif %}
|
||||
|
||||
<dt class="col-sm-3">{% trans "Defended solution:" %}</dt>
|
||||
<dd class="col-sm-9"><a href="{{ passage.defended_solution.file.url }}">{{ passage.defended_solution }}</a></dd>
|
||||
<dt class="col-sm-3">{% trans "Reported solution:" %}</dt>
|
||||
<dd class="col-sm-9"><a href="{{ passage.reported_solution.file.url }}">{{ passage.reported_solution }}</a></dd>
|
||||
|
||||
<dt class="col-sm-3">{% trans "Defender penalties count:" %}</dt>
|
||||
<dd class="col-sm-9">{{ passage.defender_penalties }}</dd>
|
||||
<dt class="col-sm-3">{% trans "Reporter penalties count:" %}</dt>
|
||||
<dd class="col-sm-9">{{ passage.reporter_penalties }}</dd>
|
||||
|
||||
<dt class="col-sm-3">{% trans "Syntheses:" %}</dt>
|
||||
<dd class="col-sm-9">
|
||||
{% for synthesis in passage.syntheses.all %}
|
||||
<a href="{{ synthesis.file.url }}">{{ synthesis }}{% if not forloop.last %}, {% endif %}</a>
|
||||
{% for review in passage.written_reviews.all %}
|
||||
<a href="{{ review.file.url }}">{{ review }}{% if not forloop.last %}, {% endif %}</a>
|
||||
{% empty %}
|
||||
{% trans "No synthesis was uploaded yet." %}
|
||||
{% trans "No review was uploaded yet." %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
</dl>
|
||||
@ -63,7 +63,7 @@
|
||||
</div>
|
||||
{% elif user.registration.participates %}
|
||||
<div class="card-footer text-center">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#uploadSynthesisModal">{% trans "Upload synthesis" %}</button>
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#uploadWrittenReviewModal">{% trans "Upload review" %}</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -79,19 +79,19 @@
|
||||
<div class="card-body">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-8">
|
||||
{% trans "Average points for the defender writing" %}
|
||||
({{ passage.defender.team.trigram }}) :
|
||||
{% trans "Average points for the reporter writing" %}
|
||||
({{ passage.reporter.team.trigram }}) :
|
||||
</dt>
|
||||
<dd class="col-sm-4">
|
||||
{{ passage.average_defender_writing|floatformat }}/{% if TFJM_APP == "TFJM" %}20{% else %}10{% endif %}
|
||||
{{ passage.average_reporter_writing|floatformat }}/{% if TFJM_APP == "TFJM" %}20{% else %}10{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-8">
|
||||
{% trans "Average points for the defender oral" %}
|
||||
({{ passage.defender.team.trigram }}) :
|
||||
{% trans "Average points for the reporter oral" %}
|
||||
({{ passage.reporter.team.trigram }}) :
|
||||
</dt>
|
||||
<dd class="col-sm-4">
|
||||
{{ passage.average_defender_oral|floatformat }}/{% if TFJM_APP == "TFJM" %}20{% else %}10{% endif %}
|
||||
{{ passage.average_reporter_oral|floatformat }}/{% if TFJM_APP == "TFJM" %}20{% else %}10{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-8">
|
||||
@ -137,11 +137,11 @@
|
||||
|
||||
<dl class="row">
|
||||
<dt class="col-sm-8">
|
||||
{% trans "Defender points" %}
|
||||
({{ passage.defender.team.trigram }}) :
|
||||
{% trans "Reporter points" %}
|
||||
({{ passage.reporter.team.trigram }}) :
|
||||
</dt>
|
||||
<dd class="col-sm-4">
|
||||
{{ passage.average_defender|floatformat }}/{% if TFJM_APP == "TFJM" %}52{% else %}50{% endif %}
|
||||
{{ passage.average_reporter|floatformat }}/{% if TFJM_APP == "TFJM" %}52{% else %}50{% endif %}
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-8">
|
||||
@ -184,10 +184,10 @@
|
||||
{% include "base_modal.html" with modal_id=note.modal_name %}
|
||||
{% endfor %}
|
||||
{% elif user.registration.participates %}
|
||||
{% trans "Upload synthesis" as modal_title %}
|
||||
{% trans "Upload review" as modal_title %}
|
||||
{% trans "Upload" as modal_button %}
|
||||
{% url "participation:upload_synthesis" pk=passage.pk as modal_action %}
|
||||
{% include "base_modal.html" with modal_id="uploadSynthesis" modal_enctype="multipart/form-data" %}
|
||||
{% url "participation:upload_review" pk=passage.pk as modal_action %}
|
||||
{% include "base_modal.html" with modal_id="uploadWrittenReview" modal_enctype="multipart/form-data" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@ -201,8 +201,8 @@
|
||||
initModal("{{ note.modal_name }}", "{% url "participation:update_notes" pk=note.pk %}")
|
||||
{% endfor %}
|
||||
{% elif user.registration.participates %}
|
||||
initModal("uploadSynthesis", "{% url "participation:upload_synthesis" pk=passage.pk %}")
|
||||
initModal("uploadWrittenReview", "{% url "participation:upload_review" pk=passage.pk %}")
|
||||
{% endif %}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -46,10 +46,10 @@
|
||||
</a>
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-3">{% trans "Defended solutions:" %}</dt>
|
||||
<dt class="col-sm-3">{% trans "Reported solutions:" %}</dt>
|
||||
<dd class="col-sm-9">
|
||||
{% for passage in pool.passages.all %}
|
||||
<a href="{{ passage.defended_solution.file.url }}">{{ passage.defender.team.trigram }} — {{ passage.get_solution_number_display }}</a>{% if not forloop.last %}, {% endif %}
|
||||
<a href="{{ passage.reported_solution.file.url }}">{{ passage.reporter.team.trigram }} — {{ passage.get_solution_number_display }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
<a href="{% url 'participation:pool_download_solutions' pool_id=pool.id %}" class="badge rounded-pill text-bg-secondary">
|
||||
<i class="fas fa-download"></i> {% trans "Download all" %}
|
||||
@ -61,16 +61,16 @@
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for passage in pool.passages.all %}
|
||||
<li class="list-group-item">
|
||||
{{ passage.defender.team.trigram }} — {{ passage.get_solution_number_display }} :
|
||||
{% for synthesis in passage.syntheses.all %}
|
||||
<a href="{{ synthesis.file.url }}">{{ synthesis.participation.team.trigram }} ({{ synthesis.get_type_display }})</a>{% if not forloop.last %}, {% endif %}
|
||||
{{ passage.reporter.team.trigram }} — {{ passage.get_solution_number_display }} :
|
||||
{% for review in passage.written_reviews.all %}
|
||||
<a href="{{ review.file.url }}">{{ review.participation.team.trigram }} ({{ review.get_type_display }})</a>{% if not forloop.last %}, {% endif %}
|
||||
{% empty %}
|
||||
{% trans "No synthesis was uploaded yet." %}
|
||||
{% trans "No review was uploaded yet." %}
|
||||
{% endfor %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<a href="{% url 'participation:pool_download_syntheses' pool_id=pool.id %}" class="badge rounded-pill text-bg-secondary">
|
||||
<a href="{% url 'participation:pool_download_written_reviews' pool_id=pool.id %}" class="badge rounded-pill text-bg-secondary">
|
||||
<i class="fas fa-download"></i> {% trans "Download all" %}
|
||||
</a>
|
||||
</dd>
|
||||
|
@ -41,7 +41,7 @@
|
||||
\begin{center}
|
||||
\begin{itemize}
|
||||
{% for passage in passages.all %}
|
||||
\item D\'efenseur\textperiodcentered{}se au passage {{ forloop.counter }} : \underline{\texttt{~{{ passage.defender.team.trigram }}~}} $\qquad$ probl\`eme \underline{~{{ passage.solution_number }}~}
|
||||
\item D\'efenseur\textperiodcentered{}se au passage {{ forloop.counter }} : \underline{\texttt{~{{ passage.reporter.team.trigram }}~}} $\qquad$ probl\`eme \underline{~{{ passage.solution_number }}~}
|
||||
{% endfor %}
|
||||
\end{itemize}
|
||||
\end{center}
|
||||
@ -50,7 +50,7 @@
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%DEFENSEUR
|
||||
\begin{tabular}{|c|p{24mm}|p{11cm}|c|{% for passage in passages.all %}p{2cm}|{% endfor %}}\hline
|
||||
\multicolumn{4}{|l|}{Læ {\bf D\'efenseur\textperiodcentered{}se} \normalsize pr\'esente les id\'ees et r\'esultats principaux pour la solution du probl\`eme.} {% for passage in passages.all %}& P.{{ forloop.counter }} - {{ passage.defender.team.trigram }} {% endfor %}\\ \hline \hline
|
||||
\multicolumn{4}{|l|}{Læ {\bf D\'efenseur\textperiodcentered{}se} \normalsize pr\'esente les id\'ees et r\'esultats principaux pour la solution du probl\`eme.} {% for passage in passages.all %}& P.{{ forloop.counter }} - {{ passage.reporter.team.trigram }} {% endfor %}\\ \hline \hline
|
||||
|
||||
%ECRIT
|
||||
\multirow{6}{3mm}{\centering \bf\'E\\ C\\ R\\ I\\ T} & \multirow{3}{20mm}{Partie scientifique} & Profondeur et difficulté des éléments présentés & [0,6] {{ esp|safe }}\\ \cline{3-{{ passages.count|add:4 }}}
|
||||
|
@ -46,7 +46,7 @@ Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{% if pool.partici
|
||||
\begin{tabular}{|p{40mm}{% for passage in passages.all %}{% if passages.count == 3 %}|p{3cm}|p{3cm}{% else %}|p{2.5cm}|p{2.5cm}{% endif %}{% endfor %}|}\hline
|
||||
\multirow{2}{40mm}{\LARGE R\^ole} {% for passage in passages.all %}& \multicolumn{2}{c|}{ \Large Probl\`eme {{ passage.solution_number }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
|
||||
{% for passage in passages.all %}& \hspace{4mm} {\Large \'ECRIT} & \hspace{4mm} {\Large ORAL}{% endfor %} \\ \hline
|
||||
\multirow{2}{35mm}{\LARGE D\'efenseur\textperiodcentered{}se} {% for passage in passages.all %}& \multicolumn{2}{c|}{\Large {{ passage.defender.team.trigram }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
|
||||
\multirow{2}{35mm}{\LARGE D\'efenseur\textperiodcentered{}se} {% for passage in passages.all %}& \multicolumn{2}{c|}{\Large {{ passage.reporter.team.trigram }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
|
||||
{% for passage in passages.all %}
|
||||
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 20$
|
||||
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 20$
|
||||
|
@ -38,15 +38,15 @@
|
||||
<dt class="col-sm-6 text-sm-end">{% trans 'date of the random draw'|capfirst %}</dt>
|
||||
<dd class="col-sm-6">{{ tournament.solutions_draw }}</dd>
|
||||
|
||||
<dt class="col-sm-6 text-sm-end">{% trans 'date of maximal syntheses submission for the first round'|capfirst %}</dt>
|
||||
<dd class="col-sm-6">{{ tournament.syntheses_first_phase_limit }}</dd>
|
||||
<dt class="col-sm-6 text-sm-end">{% trans 'date of maximal written reviews submission for the first round'|capfirst %}</dt>
|
||||
<dd class="col-sm-6">{{ tournament.reviews_first_phase_limit }}</dd>
|
||||
|
||||
<dt class="col-sm-6 text-sm-end">{% trans 'date of maximal syntheses submission for the second round'|capfirst %}</dt>
|
||||
<dd class="col-sm-6">{{ tournament.syntheses_second_phase_limit }}</dd>
|
||||
<dt class="col-sm-6 text-sm-end">{% trans 'date of maximal written reviews submission for the second round'|capfirst %}</dt>
|
||||
<dd class="col-sm-6">{{ tournament.reviews_second_phase_limit }}</dd>
|
||||
|
||||
{% if TFJM.APP == "ETEAM" %}
|
||||
<dt class="col-sm-6 text-sm-end">{% trans 'date of maximal syntheses submission for the third round'|capfirst %}</dt>
|
||||
<dd class="col-sm-6">{{ tournament.syntheses_third_phase_limit }}</dd>
|
||||
<dt class="col-sm-6 text-sm-end">{% trans 'date of maximal written reviews submission for the third round'|capfirst %}</dt>
|
||||
<dd class="col-sm-6">{{ tournament.reviews_third_phase_limit }}</dd>
|
||||
{% endif %}
|
||||
|
||||
<dt class="col-sm-6 text-sm-end">{% trans 'description'|capfirst %}</dt>
|
||||
@ -233,48 +233,48 @@
|
||||
<ul>
|
||||
<li>
|
||||
<a href="{% url "participation:tournament_csv" pk=tournament.pk %}">
|
||||
Validated team participant data spreadsheet
|
||||
{% trans "Validated team participant data spreadsheet" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "participation:tournament_csv" pk=tournament.pk %}?all">
|
||||
All teams participant data spreadsheet
|
||||
{% trans "All teams participant data spreadsheet" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "participation:tournament_authorizations" tournament_id=tournament.id %}">
|
||||
Archive of all authorisations sorted by team and person
|
||||
{% trans "Archive of all authorisations sorted by team and person" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "participation:tournament_solutions" tournament_id=tournament.id %}">
|
||||
Archive of all submitted solutions sorted by team
|
||||
{% trans "Archive of all submitted solutions sorted by team" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "participation:tournament_solutions" tournament_id=tournament.id %}?sort_by=problem">
|
||||
Archive of all sent solutions sorted by problem
|
||||
{% trans "Archive of all sent solutions sorted by problem" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "participation:tournament_solutions" tournament_id=tournament.id %}?sort_by=pool">
|
||||
Archive of all sent solutions sorted by pool
|
||||
{% trans "Archive of all sent solutions sorted by pool" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "participation:tournament_syntheses" tournament_id=tournament.id %}?sort_by=pool">
|
||||
Archive of all summary notes sorted by pool and passage
|
||||
<a href="{% url "participation:tournament_written_reviews" tournament_id=tournament.id %}?sort_by=pool">
|
||||
{% trans "Archive of all summary notes sorted by pool and passage" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://docs.google.com/spreadsheets/d/{{ tournament.notes_sheet_id }}/edit">
|
||||
<i class="fas fa-table"></i>
|
||||
Note spreadsheet on Google Sheets
|
||||
{% trans "Note spreadsheet on Google Sheets" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "participation:tournament_notation_sheets" tournament_id=tournament.id %}">
|
||||
Archive of all printable note sheets sorted by pool
|
||||
{% trans "Archive of all printable note sheets sorted by pool" %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -8,11 +8,11 @@ from .views import CreateTeamView, FinalNotationSheetTemplateView, GSheetNotific
|
||||
PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, PoolJuryView, PoolNotesTemplateView, \
|
||||
PoolPresideJuryView, PoolRemoveJuryView, PoolUpdateView, PoolUploadNotesView, \
|
||||
ScaleNotationSheetTemplateView, SelectTeamFinalView, \
|
||||
SolutionsDownloadView, SolutionUploadView, SynthesisUploadView, \
|
||||
SolutionsDownloadView, SolutionUploadView, \
|
||||
TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, \
|
||||
TeamUploadMotivationLetterView, TournamentCreateView, TournamentDetailView, TournamentExportCSVView, \
|
||||
TournamentHarmonizeNoteView, TournamentHarmonizeView, TournamentListView, TournamentPaymentsView, \
|
||||
TournamentPublishNotesView, TournamentUpdateView
|
||||
TournamentPublishNotesView, TournamentUpdateView, WrittenReviewUploadView
|
||||
|
||||
|
||||
app_name = "participation"
|
||||
@ -42,8 +42,8 @@ urlpatterns = [
|
||||
name="tournament_authorizations"),
|
||||
path("tournament/<int:tournament_id>/solutions/", SolutionsDownloadView.as_view(),
|
||||
name="tournament_solutions"),
|
||||
path("tournament/<int:tournament_id>/syntheses/", SolutionsDownloadView.as_view(),
|
||||
name="tournament_syntheses"),
|
||||
path("tournament/<int:tournament_id>/written_reviews/", SolutionsDownloadView.as_view(),
|
||||
name="tournament_written_reviews"),
|
||||
path("tournament/<int:tournament_id>/notation/sheets/", NotationSheetsArchiveView.as_view(),
|
||||
name="tournament_notation_sheets"),
|
||||
path("tournament/<int:pk>/notation/notifications/", GSheetNotificationsView.as_view(),
|
||||
@ -60,7 +60,7 @@ urlpatterns = [
|
||||
path("pools/<int:pk>/", PoolDetailView.as_view(), name="pool_detail"),
|
||||
path("pools/<int:pk>/update/", PoolUpdateView.as_view(), name="pool_update"),
|
||||
path("pools/<int:pool_id>/solutions/", SolutionsDownloadView.as_view(), name="pool_download_solutions"),
|
||||
path("pools/<int:pool_id>/syntheses/", SolutionsDownloadView.as_view(), name="pool_download_syntheses"),
|
||||
path("pools/<int:pool_id>/written_reviews/", SolutionsDownloadView.as_view(), name="pool_download_written_reviews"),
|
||||
path("pools/<int:pk>/notation/scale/", ScaleNotationSheetTemplateView.as_view(), name="pool_scale_note_sheet"),
|
||||
path("pools/<int:pk>/notation/final/", FinalNotationSheetTemplateView.as_view(), name="pool_final_note_sheet"),
|
||||
path("pools/<int:pool_id>/notation/sheets/", NotationSheetsArchiveView.as_view(), name="pool_notation_sheets"),
|
||||
@ -71,6 +71,6 @@ urlpatterns = [
|
||||
path("pools/<int:pk>/upload-notes/template/", PoolNotesTemplateView.as_view(), name="pool_notes_template"),
|
||||
path("pools/passages/<int:pk>/", PassageDetailView.as_view(), name="passage_detail"),
|
||||
path("pools/passages/<int:pk>/update/", PassageUpdateView.as_view(), name="passage_update"),
|
||||
path("pools/passages/<int:pk>/solution/", SynthesisUploadView.as_view(), name="upload_synthesis"),
|
||||
path("pools/passages/<int:pk>/written_review/", WrittenReviewUploadView.as_view(), name="upload_written_review"),
|
||||
path("pools/passages/notes/<int:pk>/", NoteUpdateView.as_view(), name="update_notes"),
|
||||
]
|
||||
|
@ -46,9 +46,9 @@ from tfjm.lists import get_sympa_client
|
||||
from tfjm.views import AdminMixin, VolunteerMixin
|
||||
|
||||
from .forms import AddJuryForm, JoinTeamForm, MotivationLetterForm, NoteForm, ParticipationForm, PassageForm, \
|
||||
PoolForm, RequestValidationForm, SolutionForm, SynthesisForm, TeamForm, TournamentForm, \
|
||||
UploadNotesForm, ValidateParticipationForm
|
||||
from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament, Tweak
|
||||
PoolForm, RequestValidationForm, SolutionForm, TeamForm, TournamentForm, UploadNotesForm, \
|
||||
ValidateParticipationForm, WrittenReviewForm
|
||||
from .models import Note, Participation, Passage, Pool, Solution, Team, Tournament, Tweak, WrittenReview
|
||||
from .tables import NoteTable, ParticipationTable, PassageTable, PoolTable, TeamTable, TournamentTable
|
||||
|
||||
|
||||
@ -977,7 +977,7 @@ class PoolUpdateView(VolunteerMixin, UpdateView):
|
||||
|
||||
class SolutionsDownloadView(VolunteerMixin, View):
|
||||
"""
|
||||
Download all solutions or syntheses as a ZIP archive.
|
||||
Download all solutions or written reviews as a ZIP archive.
|
||||
"""
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
@ -1018,11 +1018,12 @@ class SolutionsDownloadView(VolunteerMixin, View):
|
||||
if 'team_id' in kwargs:
|
||||
team = Team.objects.get(pk=kwargs["team_id"])
|
||||
solutions = Solution.objects.filter(participation=team.participation).all()
|
||||
syntheses = Synthesis.objects.filter(participation=team.participation).all()
|
||||
filename = _("Solutions of team {trigram}.zip") if is_solution else _("Syntheses of team {trigram}.zip")
|
||||
written_reviews = WrittenReview.objects.filter(participation=team.participation).all()
|
||||
filename = _("Solutions of team {trigram}.zip") if is_solution \
|
||||
else _("Written reviews of team {trigram}.zip")
|
||||
filename = filename.format(trigram=team.trigram)
|
||||
|
||||
def prefix(s: Solution | Synthesis) -> str:
|
||||
def prefix(s: Solution | WrittenReview) -> str:
|
||||
return ""
|
||||
elif 'tournament_id' in kwargs:
|
||||
tournament = Tournament.objects.get(pk=kwargs["tournament_id"])
|
||||
@ -1035,11 +1036,12 @@ class SolutionsDownloadView(VolunteerMixin, View):
|
||||
for sol in pool.solutions:
|
||||
sol.pool = pool
|
||||
solutions.append(sol)
|
||||
syntheses = Synthesis.objects.filter(passage__pool__tournament=tournament).all()
|
||||
filename = _("Solutions of {tournament}.zip") if is_solution else _("Syntheses of {tournament}.zip")
|
||||
written_reviews = WrittenReview.objects.filter(passage__pool__tournament=tournament).all()
|
||||
filename = _("Solutions of {tournament}.zip") if is_solution \
|
||||
else _("Written reviews of {tournament}.zip")
|
||||
filename = filename.format(tournament=tournament.name)
|
||||
|
||||
def prefix(s: Solution | Synthesis) -> str:
|
||||
def prefix(s: Solution | WrittenReview) -> str:
|
||||
pool = s.pool if is_solution else s.passage.pool
|
||||
p = f"Poule {pool.short_name}/"
|
||||
if not is_solution:
|
||||
@ -1050,27 +1052,28 @@ class SolutionsDownloadView(VolunteerMixin, View):
|
||||
solutions = Solution.objects.filter(participation__tournament=tournament).all()
|
||||
else:
|
||||
solutions = Solution.objects.filter(final_solution=True).all()
|
||||
syntheses = Synthesis.objects.filter(passage__pool__tournament=tournament).all()
|
||||
filename = _("Solutions of {tournament}.zip") if is_solution else _("Syntheses of {tournament}.zip")
|
||||
written_reviews = WrittenReview.objects.filter(passage__pool__tournament=tournament).all()
|
||||
filename = _("Solutions of {tournament}.zip") if is_solution \
|
||||
else _("Written reviews of {tournament}.zip")
|
||||
filename = filename.format(tournament=tournament.name)
|
||||
|
||||
def prefix(s: Solution | Synthesis) -> str:
|
||||
def prefix(s: Solution | WrittenReview) -> str:
|
||||
return f"{s.participation.team.trigram}/" if sort_by == "team" else f"Problème {s.problem}/"
|
||||
else:
|
||||
pool = Pool.objects.get(pk=kwargs["pool_id"])
|
||||
solutions = pool.solutions
|
||||
syntheses = Synthesis.objects.filter(passage__pool=pool).all()
|
||||
written_reviews = WrittenReview.objects.filter(passage__pool=pool).all()
|
||||
filename = _("Solutions for pool {pool} of tournament {tournament}.zip") \
|
||||
if is_solution else _("Syntheses for pool {pool} of tournament {tournament}.zip")
|
||||
if is_solution else _("Written reviews for pool {pool} of tournament {tournament}.zip")
|
||||
filename = filename.format(pool=pool.short_name,
|
||||
tournament=pool.tournament.name)
|
||||
|
||||
def prefix(s: Solution | Synthesis) -> str:
|
||||
def prefix(s: Solution | WrittenReview) -> str:
|
||||
return ""
|
||||
|
||||
output = BytesIO()
|
||||
zf = ZipFile(output, "w")
|
||||
for s in (solutions if is_solution else syntheses):
|
||||
for s in (solutions if is_solution else written_reviews):
|
||||
if s.file.storage.exists(s.file.path):
|
||||
zf.write("media/" + s.file.name, prefix(s) + f"{s}.pdf")
|
||||
|
||||
@ -1500,10 +1503,10 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
header_role.addElement(role_tc)
|
||||
header_role.addElement(CoveredTableCell())
|
||||
for i in range(pool_size):
|
||||
defender_tc = TableCell(valuetype="string", stylename=title_style_left)
|
||||
defender_tc.addElement(P(text=_("Defender")))
|
||||
defender_tc.setAttribute('numbercolumnsspanned', "2")
|
||||
header_role.addElement(defender_tc)
|
||||
reporter_tc = TableCell(valuetype="string", stylename=title_style_left)
|
||||
reporter_tc.addElement(P(text=_("Reporter")))
|
||||
reporter_tc.setAttribute('numbercolumnsspanned', "2")
|
||||
header_role.addElement(reporter_tc)
|
||||
header_role.addElement(CoveredTableCell())
|
||||
|
||||
opponent_tc = TableCell(valuetype="string", stylename=title_style)
|
||||
@ -1536,13 +1539,13 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
header_notes.addElement(CoveredTableCell())
|
||||
|
||||
for i in range(pool_size):
|
||||
defender_w_tc = TableCell(valuetype="string", stylename=title_style_botleft)
|
||||
defender_w_tc.addElement(P(text=f"{_('Writing')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})"))
|
||||
header_notes.addElement(defender_w_tc)
|
||||
reporter_w_tc = TableCell(valuetype="string", stylename=title_style_botleft)
|
||||
reporter_w_tc.addElement(P(text=f"{_('Writing')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})"))
|
||||
header_notes.addElement(reporter_w_tc)
|
||||
|
||||
defender_o_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
||||
defender_o_tc.addElement(P(text=f"{_('Oral')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})"))
|
||||
header_notes.addElement(defender_o_tc)
|
||||
reporter_o_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
||||
reporter_o_tc.addElement(P(text=f"{_('Oral')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})"))
|
||||
header_notes.addElement(reporter_o_tc)
|
||||
|
||||
opponent_w_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
||||
opponent_w_tc.addElement(P(text=f"{_('Writing')} (/10)"))
|
||||
@ -1623,13 +1626,13 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
coeff_row.addElement(coeff_tc)
|
||||
coeff_row.addElement(CoveredTableCell())
|
||||
for passage in self.object.passages.all():
|
||||
defender_w_tc = TableCell(valuetype="float", value=passage.coeff_defender_writing, stylename=style_left)
|
||||
defender_w_tc.addElement(P(text=str(passage.coeff_defender_writing)))
|
||||
coeff_row.addElement(defender_w_tc)
|
||||
reporter_w_tc = TableCell(valuetype="float", value=passage.coeff_reporter_writing, stylename=style_left)
|
||||
reporter_w_tc.addElement(P(text=str(passage.coeff_reporter_writing)))
|
||||
coeff_row.addElement(reporter_w_tc)
|
||||
|
||||
defender_o_tc = TableCell(valuetype="float", value=passage.coeff_defender_oral, stylename=style)
|
||||
defender_o_tc.addElement(P(text=str(passage.coeff_defender_oral)))
|
||||
coeff_row.addElement(defender_o_tc)
|
||||
reporter_o_tc = TableCell(valuetype="float", value=passage.coeff_reporter_oral, stylename=style)
|
||||
reporter_o_tc.addElement(P(text=str(passage.coeff_reporter_oral)))
|
||||
coeff_row.addElement(reporter_o_tc)
|
||||
|
||||
opponent_w_tc = TableCell(valuetype="float", value=passage.coeff_opponent_writing, stylename=style)
|
||||
opponent_w_tc.addElement(P(text=str(passage.coeff_opponent_writing)))
|
||||
@ -1668,12 +1671,12 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
for i, passage in enumerate(self.object.passages.all()):
|
||||
def_w_col = getcol(min_column + passage_width * i)
|
||||
def_o_col = getcol(min_column + passage_width * i + 1)
|
||||
defender_tc = TableCell(valuetype="float", value=passage.average_defender, stylename=style_botleft)
|
||||
defender_tc.addElement(P(text=str(passage.average_defender)))
|
||||
defender_tc.setAttribute('numbercolumnsspanned', "2")
|
||||
defender_tc.setAttribute("formula", f"of:=[.{def_w_col}{max_row + 1}] * [.{def_w_col}{max_row + 2}]"
|
||||
reporter_tc = TableCell(valuetype="float", value=passage.average_reporter, stylename=style_botleft)
|
||||
reporter_tc.addElement(P(text=str(passage.average_reporter)))
|
||||
reporter_tc.setAttribute('numbercolumnsspanned', "2")
|
||||
reporter_tc.setAttribute("formula", f"of:=[.{def_w_col}{max_row + 1}] * [.{def_w_col}{max_row + 2}]"
|
||||
f" + [.{def_o_col}{max_row + 1}] * [.{def_o_col}{max_row + 2}]")
|
||||
subtotal_row.addElement(defender_tc)
|
||||
subtotal_row.addElement(reporter_tc)
|
||||
subtotal_row.addElement(CoveredTableCell())
|
||||
|
||||
opp_w_col = getcol(min_column + passage_width * i + 2)
|
||||
@ -1745,7 +1748,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
|
||||
team_tc = TableCell(valuetype="string",
|
||||
stylename=style_botleft if passage.position == pool_size else style_left)
|
||||
team_tc.addElement(P(text=f"{passage.defender.team.name} ({passage.defender.team.trigram})"))
|
||||
team_tc.addElement(P(text=f"{passage.reporter.team.name} ({passage.reporter.team.trigram})"))
|
||||
team_tc.setAttribute('numbercolumnsspanned', "2")
|
||||
team_row.addElement(team_tc)
|
||||
|
||||
@ -1755,17 +1758,17 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
problem_tc.setAttribute("formula", f"of:=[.B{3 + passage_width * (passage.position - 1)}]")
|
||||
team_row.addElement(problem_tc)
|
||||
|
||||
defender_pos = passage.position - 1
|
||||
opponent_pos = self.object.passages.get(opponent=passage.defender).position - 1
|
||||
reviewer_pos = self.object.passages.get(reviewer=passage.defender).position - 1
|
||||
observer_pos = self.object.passages.get(observer=passage.defender).position - 1 \
|
||||
reporter_pos = passage.position - 1
|
||||
opponent_pos = self.object.passages.get(opponent=passage.reporter).position - 1
|
||||
reviewer_pos = self.object.passages.get(reviewer=passage.reporter).position - 1
|
||||
observer_pos = self.object.passages.get(observer=passage.reporter).position - 1 \
|
||||
if has_observer else None
|
||||
|
||||
score_tc = TableCell(valuetype="float", value=self.object.average(passage.defender),
|
||||
score_tc = TableCell(valuetype="float", value=self.object.average(passage.reporter),
|
||||
stylename=style_bot if passage.position == pool_size else style)
|
||||
score_tc.addElement(P(text=self.object.average(passage.defender)))
|
||||
score_tc.addElement(P(text=self.object.average(passage.reporter)))
|
||||
formula = "of:="
|
||||
formula += getcol(min_column + defender_pos * passage_width) + str(max_row + 3) # Defender
|
||||
formula += getcol(min_column + reporter_pos * passage_width) + str(max_row + 3) # Reporter
|
||||
formula += " + " + getcol(min_column + opponent_pos * passage_width + 2) + str(max_row + 3) # Opponent
|
||||
formula += " + " + getcol(min_column + reviewer_pos * passage_width + 4) + str(max_row + 3) # Reviewer
|
||||
if has_observer:
|
||||
@ -1775,9 +1778,9 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||
team_row.addElement(score_tc)
|
||||
|
||||
score_col = 'C'
|
||||
rank_tc = TableCell(valuetype="float", value=sorted_participations.index(passage.defender) + 1,
|
||||
rank_tc = TableCell(valuetype="float", value=sorted_participations.index(passage.reporter) + 1,
|
||||
stylename=style_botright if passage.position == pool_size else style_right)
|
||||
rank_tc.addElement(P(text=str(sorted_participations.index(passage.defender) + 1)))
|
||||
rank_tc.addElement(P(text=str(sorted_participations.index(passage.reporter) + 1)))
|
||||
rank_tc.setAttribute("formula", f"of:=RANK([.{score_col}{max_row + 5 + passage.position}]; "
|
||||
f"[.{score_col}${max_row + 6}]:"
|
||||
f"[.{score_col}${max_row + 5 + pool_size}])")
|
||||
@ -1981,7 +1984,7 @@ class PassageDetailView(LoginRequiredMixin, DetailView):
|
||||
or reg in passage.pool.juries.all()
|
||||
or reg.pools_presided.filter(tournament=passage.pool.tournament).exists()) \
|
||||
or reg.participates and reg.team \
|
||||
and reg.team.participation in [passage.defender, passage.opponent, passage.reviewer, passage.observer]:
|
||||
and reg.team.participation in [passage.reporter, passage.opponent, passage.reviewer, passage.observer]:
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
return self.handle_no_permission()
|
||||
|
||||
@ -2002,8 +2005,8 @@ class PassageDetailView(LoginRequiredMixin, DetailView):
|
||||
if 'notes' in context and not self.request.user.registration.is_admin:
|
||||
context['notes']._sequence.remove('update')
|
||||
|
||||
context['notes'].columns['defender_writing'].column.verbose_name += f" ({passage.defender.team.trigram})"
|
||||
context['notes'].columns['defender_oral'].column.verbose_name += f" ({passage.defender.team.trigram})"
|
||||
context['notes'].columns['reporter_writing'].column.verbose_name += f" ({passage.reporter.team.trigram})"
|
||||
context['notes'].columns['reporter_oral'].column.verbose_name += f" ({passage.reporter.team.trigram})"
|
||||
context['notes'].columns['opponent_writing'].column.verbose_name += f" ({passage.opponent.team.trigram})"
|
||||
context['notes'].columns['opponent_oral'].column.verbose_name += f" ({passage.opponent.team.trigram})"
|
||||
context['notes'].columns['reviewer_writing'].column.verbose_name += f" ({passage.reviewer.team.trigram})"
|
||||
@ -2028,9 +2031,9 @@ class PassageUpdateView(VolunteerMixin, UpdateView):
|
||||
return self.handle_no_permission()
|
||||
|
||||
|
||||
class SynthesisUploadView(LoginRequiredMixin, FormView):
|
||||
template_name = "participation/upload_synthesis.html"
|
||||
form_class = SynthesisForm
|
||||
class WrittenReviewUploadView(LoginRequiredMixin, FormView):
|
||||
template_name = "participation/upload_written_review.html"
|
||||
form_class = WrittenReviewForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_authenticated or not request.user.registration.participates:
|
||||
@ -2057,14 +2060,14 @@ class SynthesisUploadView(LoginRequiredMixin, FormView):
|
||||
form_syn = form.instance
|
||||
form_syn.type = 1 if self.participation == self.passage.opponent \
|
||||
else 2 if self.participation == self.passage.reviewer else 3
|
||||
syn_qs = Synthesis.objects.filter(participation=self.participation,
|
||||
passage=self.passage,
|
||||
type=form_syn.type).all()
|
||||
syn_qs = WrittenReview.objects.filter(participation=self.participation,
|
||||
passage=self.passage,
|
||||
type=form_syn.type).all()
|
||||
|
||||
deadline = self.passage.pool.tournament.syntheses_first_phase_limit if self.passage.pool.round == 1 \
|
||||
else self.passage.pool.tournament.syntheses_second_phase_limit
|
||||
deadline = self.passage.pool.tournament.reviews_first_phase_limit if self.passage.pool.round == 1 \
|
||||
else self.passage.pool.tournament.reviews_second_phase_limit
|
||||
if syn_qs.exists() and timezone.now() > deadline:
|
||||
form.add_error(None, _("You can't upload a synthesis after the deadline."))
|
||||
form.add_error(None, _("You can't upload a written review after the deadline."))
|
||||
return self.form_invalid(form)
|
||||
|
||||
# Drop previous solution if existing
|
||||
@ -2098,8 +2101,8 @@ class NoteUpdateView(VolunteerMixin, UpdateView):
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
form.fields['defender_writing'].label += f" ({self.object.passage.defender.team.trigram})"
|
||||
form.fields['defender_oral'].label += f" ({self.object.passage.defender.team.trigram})"
|
||||
form.fields['reporter_writing'].label += f" ({self.object.passage.reporter.team.trigram})"
|
||||
form.fields['reporter_oral'].label += f" ({self.object.passage.reporter.team.trigram})"
|
||||
form.fields['opponent_writing'].label += f" ({self.object.passage.opponent.team.trigram})"
|
||||
form.fields['opponent_oral'].label += f" ({self.object.passage.opponent.team.trigram})"
|
||||
form.fields['reviewer_writing'].label += f" ({self.object.passage.reviewer.team.trigram})"
|
||||
|
@ -26,7 +26,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import CreateView, DetailView, RedirectView, TemplateView, UpdateView, View
|
||||
from django_tables2 import SingleTableView
|
||||
from magic import Magic
|
||||
from participation.models import Passage, Solution, Synthesis, Tournament
|
||||
from participation.models import Passage, Solution, Tournament, WrittenReview
|
||||
from tfjm.tokens import email_validation_token
|
||||
from tfjm.views import UserMixin, UserRegistrationMixin, VolunteerMixin
|
||||
|
||||
@ -837,11 +837,11 @@ class SolutionView(LoginRequiredMixin, View):
|
||||
solution = Solution.objects.get(file__endswith=filename)
|
||||
user = request.user
|
||||
if user.registration.participates and user.registration.team.participation:
|
||||
passage_participant_qs = Passage.objects.filter(Q(defender=user.registration.team.participation)
|
||||
passage_participant_qs = Passage.objects.filter(Q(reporter=user.registration.team.participation)
|
||||
| Q(opponent=user.registration.team.participation)
|
||||
| Q(reviewer=user.registration.team.participation)
|
||||
| Q(observer=user.registration.team.participation),
|
||||
defender=solution.participation,
|
||||
reporter=solution.participation,
|
||||
solution_number=solution.problem)
|
||||
else:
|
||||
passage_participant_qs = Passage.objects.none()
|
||||
@ -853,7 +853,7 @@ class SolutionView(LoginRequiredMixin, View):
|
||||
or user.registration.is_volunteer
|
||||
and Passage.objects.filter(Q(pool__juries=user.registration)
|
||||
| Q(pool__tournament__in=user.registration.organized_tournaments.all()),
|
||||
defender=solution.participation,
|
||||
reporter=solution.participation,
|
||||
solution_number=solution.problem).exists()
|
||||
or user.registration.participates and user.registration.team
|
||||
and (solution.participation.team == user.registration.team or
|
||||
@ -871,30 +871,30 @@ class SolutionView(LoginRequiredMixin, View):
|
||||
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
||||
|
||||
|
||||
class SynthesisView(LoginRequiredMixin, View):
|
||||
class WrittenReviewView(LoginRequiredMixin, View):
|
||||
"""
|
||||
Display the sent synthesis.
|
||||
Display the sent written reviews.
|
||||
"""
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
filename = kwargs["filename"]
|
||||
path = f"media/syntheses/{filename}"
|
||||
path = f"media/reviews/{filename}"
|
||||
if not os.path.exists(path):
|
||||
raise Http404
|
||||
synthesis = Synthesis.objects.get(file__endswith=filename)
|
||||
review = WrittenReview.objects.get(file__endswith=filename)
|
||||
user = request.user
|
||||
if not (user.registration.is_admin or user.registration.is_volunteer
|
||||
and (user.registration in synthesis.passage.pool.juries.all()
|
||||
or user.registration in synthesis.passage.pool.tournament.organizers.all()
|
||||
or user.registration.pools_presided.filter(tournament=synthesis.passage.pool.tournament).exists())
|
||||
or user.registration.participates and user.registration.team == synthesis.participation.team):
|
||||
and (user.registration in review.passage.pool.juries.all()
|
||||
or user.registration in review.passage.pool.tournament.organizers.all()
|
||||
or user.registration.pools_presided.filter(tournament=review.passage.pool.tournament).exists())
|
||||
or user.registration.participates and user.registration.team == review.participation.team):
|
||||
raise PermissionDenied
|
||||
# Guess mime type of the file
|
||||
mime = Magic(mime=True)
|
||||
mime_type = mime.from_file(path)
|
||||
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
|
||||
# Replace file name
|
||||
true_file_name = str(synthesis) + f".{ext}"
|
||||
true_file_name = str(review) + f".{ext}"
|
||||
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
|
||||
|
||||
|
||||
|
@ -32,7 +32,7 @@ Round \underline{~~~~} pool \underline{~~~~}
|
||||
|
||||
\medskip
|
||||
|
||||
Problem \underline{~~~~} defended by team \underline{~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
|
||||
Problem \underline{~~~~} reported by team \underline{~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
|
||||
|
||||
\medskip
|
||||
|
||||
|
@ -24,7 +24,7 @@ from django.views.defaults import bad_request, page_not_found, permission_denied
|
||||
from django.views.generic import TemplateView
|
||||
from participation.views import MotivationLetterView
|
||||
from registration.views import HealthSheetView, ParentalAuthorizationView, PhotoAuthorizationView, \
|
||||
ReceiptView, SolutionView, SynthesisView, VaccineSheetView
|
||||
ReceiptView, SolutionView, VaccineSheetView, WrittenReviewView
|
||||
|
||||
from .views import AdminSearchView
|
||||
|
||||
@ -61,8 +61,8 @@ urlpatterns = [
|
||||
|
||||
path('media/solutions/<str:filename>/', SolutionView.as_view(),
|
||||
name='solution'),
|
||||
path('media/syntheses/<str:filename>/', SynthesisView.as_view(),
|
||||
name='synthesis'),
|
||||
path('media/reviews/<str:filename>/', WrittenReviewView.as_view(),
|
||||
name='reviews'),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
|
Loading…
Reference in New Issue
Block a user