1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-02-22 14:21:18 +00:00

Compare commits

..

No commits in common. "2a298a3ee4bbd2dcbfdee2450a5d34f86eec3eac" and "d84db949c6459521aa4d5be2d8157085c04f0119" have entirely different histories.

16 changed files with 275 additions and 594 deletions

View File

@ -122,8 +122,6 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
self.tournament = await Tournament.objects.filter(pk=self.tournament_id)\ self.tournament = await Tournament.objects.filter(pk=self.tournament_id)\
.prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget() .prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget()
translation.activate(settings.PREFERRED_LANGUAGE_CODE)
match content['type']: match content['type']:
case 'set_language': case 'set_language':
# Update the translation language # Update the translation language
@ -235,8 +233,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': 'Tirage au sort du TFJM²', 'title': 'Tirage au sort du TFJM²',
'body': _("The draw of tournament {tournament} started!") 'body': "Le tirage au sort du tournoi de "
.format(tournament=self.tournament.name)}) f"{self.tournament.name} a commencé !"})
async def draw_start(self, content) -> None: async def draw_start(self, content) -> None:
""" """
@ -405,8 +403,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await self.channel_layer.group_send( await self.channel_layer.group_send(
f"team-{dup.participation.team.trigram}", f"team-{dup.participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify', 'title': 'Tirage au sort du TFJM²', {'tid': self.tournament_id, 'type': 'draw.notify', 'title': 'Tirage au sort du TFJM²',
'body': _("Your dice score is identical to the one of one or multiple teams. " 'body': 'Votre score de dé est identique à celui de une ou plusieurs équipes. '
"Please relaunch it.")} 'Veuillez le relancer.'}
) )
# Alert the tournament # Alert the tournament
await self.channel_layer.group_send( await self.channel_layer.group_send(
@ -450,7 +448,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# We can add a joker team if there is not already a team in the pool that was in the same pool # We can add a joker team if there is not already a team in the pool that was in the same pool
# in the first round, and such that the number of such jokers is exactly the free space of the current pool. # in the first round, and such that the number of such jokers is exactly the free space of the current pool.
# Exception: if there is one only pool with 5 teams, we exchange the first and the last teams of the pool. # Exception: if there is one only pool with 5 teams, we exchange the first and the last teams of the pool.
if not self.tournament.final and settings.TFJM_APP == "TFJM": if not self.tournament.final:
tds_copy = sorted(tds, key=lambda td: (td.passage_index, -td.pool.letter,)) tds_copy = sorted(tds, key=lambda td: (td.passage_index, -td.pool.letter,))
jokers = [td for td in tds if td.passage_index == 4] jokers = [td for td in tds if td.passage_index == 4]
round2 = await self.tournament.draw.round_set.filter(number=2).aget() round2 = await self.tournament.draw.round_set.filter(number=2).aget()
@ -504,11 +502,12 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await self.tournament.draw.current_round.asave() await self.tournament.draw.current_round.asave()
# Display dice result in the header of the information alert # Display dice result in the header of the information alert
trigrams = ", ".join(f"<strong>{td.participation.team.trigram}</strong> ({td.passage_dice})" for td in tds) msg = "Les résultats des dés sont les suivants : "
msg = _("The dice results are the following: {trigrams}. " msg += ", ".join(f"<strong>{td.participation.team.trigram}</strong> ({td.passage_dice})" for td in tds)
"The passage order and the compositions of the different pools are displayed on the side. " msg += ". L'ordre de passage et les compositions des différentes poules sont affiché⋅es sur le côté. "
"The passage orders for the first round are determined from the dice scores, in increasing order. " msg += "Les ordres de passage pour le premier tour sont déterminés à partir des scores des dés, "
"For the second round, the passage orders are determined from the passage orders of the first round.") msg += "dans l'ordre croissant. Pour le deuxième tour, les ordres de passage sont déterminés à partir "
msg += "des ordres de passage du premier tour."
self.tournament.draw.last_message = msg self.tournament.draw.last_message = msg
await self.tournament.draw.asave() await self.tournament.draw.asave()
@ -611,8 +610,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Notify the team that it can draw a problem # Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{tds[0].participation.team.trigram}", await self.channel_layer.group_send(f"team-{tds[0].participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Your turn!"), 'title': "À votre tour !",
'body': _("It's your turn to draw a problem!")}) 'body': "C'est à vous de tirer un nouveau problème !"})
async def select_problem(self, **kwargs): async def select_problem(self, **kwargs):
""" """
@ -632,7 +631,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
.prefetch_related('team').aget() .prefetch_related('team').aget()
# Ensure that the user can draws a problem at this time # Ensure that the user can draws a problem at this time
if participation.id != td.participation_id: if participation.id != td.participation_id:
return await self.alert(_("This is not your turn."), 'danger') return await self.alert("This is not your turn.", 'danger')
while True: while True:
# Choose a random problem # Choose a random problem
@ -703,20 +702,19 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
.prefetch_related('team').aget() .prefetch_related('team').aget()
# Ensure that the user can accept a problem at this time # Ensure that the user can accept a problem at this time
if participation.id != td.participation_id: if participation.id != td.participation_id:
return await self.alert(_("This is not your turn."), 'danger') return await self.alert("This is not your turn.", 'danger')
td.accepted = td.purposed td.accepted = td.purposed
td.purposed = None td.purposed = None
await td.asave() await td.asave()
trigram = td.participation.team.trigram trigram = td.participation.team.trigram
msg = _("The team <strong>{trigram}</strong> accepted the problem <string>{problem}</strong>: " msg = f"L'équipe <strong>{trigram}</strong> a accepté le problème <strong>{td.accepted} : " \
"{problem_name}. ").format(trigram=trigram, problem=td.accepted, f"{settings.PROBLEMS[td.accepted - 1]}</strong>. "
problem_name=settings.PROBLEMS[td.accepted - 1])
if pool.size == 5 and await pool.teamdraw_set.filter(accepted=td.accepted).acount() < 2: if pool.size == 5 and await pool.teamdraw_set.filter(accepted=td.accepted).acount() < 2:
msg += _("One team more can accept this problem.") msg += "Une équipe peut encore l'accepter."
else: else:
msg += _("No team can accept this problem anymore.") msg += "Plus personne ne peut l'accepter."
self.tournament.draw.last_message = msg self.tournament.draw.last_message = msg
await self.tournament.draw.asave() await self.tournament.draw.asave()
@ -751,8 +749,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Notify the team that it can draw a problem # Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{new_trigram}", await self.channel_layer.group_send(f"team-{new_trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Your turn!"), 'title': "À votre tour !",
'body': _("It's your turn to draw a problem!")}) 'body': "C'est à vous de tirer un nouveau problème !"})
else: else:
# Pool is ended # Pool is ended
await self.end_pool(pool) await self.end_pool(pool)
@ -810,8 +808,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
'problems': [td.accepted async for td in pool.team_draws], 'problems': [td.accepted async for td in pool.team_draws],
}) })
msg += "<br><br>" + _("The draw of the pool {pool} is ended. The summary is below.") \ msg += f"<br><br>Le tirage de la poule {pool.get_letter_display()}{r.number} est terminé. " \
.format(pool=f"{pool.get_letter_display()}{r.number}") f"Le tableau récapitulatif est en bas."
self.tournament.draw.last_message = msg self.tournament.draw.last_message = msg
await self.tournament.draw.asave() await self.tournament.draw.asave()
@ -828,8 +826,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Notify the team that it can draw a dice # Notify the team that it can draw a dice
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Your turn!"), 'title': "À votre tour !",
'body': _("It's your turn to launch the dice!")}) 'body': "C'est à vous de lancer le dé !"})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.dice_visibility', {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
@ -845,11 +843,11 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
""" """
msg = self.tournament.draw.last_message msg = self.tournament.draw.last_message
if r.number < settings.NB_ROUNDS and not self.tournament.final and settings.TFJM_APP == "TFJM": if r.number < settings.NB_ROUNDS and not self.tournament.final:
# Next round # Next round
next_round = await self.tournament.draw.round_set.filter(number=r.number + 1).aget() next_round = await self.tournament.draw.round_set.filter(number=r.number + 1).aget()
self.tournament.draw.current_round = next_round self.tournament.draw.current_round = next_round
msg += "<br><br>" + _("The draw of the round {round} is ended.").format(round=r.number) msg += f"<br><br>Le tirage au sort du tour {r.number} est terminé."
self.tournament.draw.last_message = msg self.tournament.draw.last_message = msg
await self.tournament.draw.asave() await self.tournament.draw.asave()
@ -862,8 +860,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Notify the team that it can draw a dice # Notify the team that it can draw a dice
await self.channel_layer.group_send(f"team-{participation.team.trigram}", await self.channel_layer.group_send(f"team-{participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Your turn!"), 'title': "À votre tour !",
'body': _("It's your turn to launch the dice!")}) 'body': "C'est à vous de lancer le dé !"})
# Reorder dices # Reorder dices
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
@ -890,9 +888,9 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.dice_visibility', {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
'visible': True}) 'visible': True})
elif r.number == 1 and (self.tournament.final or settings.TFJM_APP == "ETEAM"): elif r.number == 1 and self.tournament.final:
# For the final tournament, we wait for a manual update between the two rounds. # For the final tournament, we wait for a manual update between the two rounds.
msg += "<br><br>" + _("The draw of the first round is ended.") msg += "<br><br>Le tirage au sort du tour 1 est terminé."
self.tournament.draw.last_message = msg self.tournament.draw.last_message = msg
await self.tournament.draw.asave() await self.tournament.draw.asave()
@ -921,7 +919,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
.prefetch_related('team').aget() .prefetch_related('team').aget()
# Ensure that the user can reject a problem at this time # Ensure that the user can reject a problem at this time
if participation.id != td.participation_id: if participation.id != td.participation_id:
return await self.alert(_("This is not your turn."), 'danger') return await self.alert("This is not your turn.", 'danger')
# Add the problem to the rejected problems list # Add the problem to the rejected problems list
problem = td.purposed problem = td.purposed
@ -935,16 +933,15 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Update messages # Update messages
trigram = td.participation.team.trigram trigram = td.participation.team.trigram
msg = _("The team <strong>{trigram}</strong> refused the problem <strong>{problem}</strong>: " msg = f"L'équipe <strong>{trigram}</strong> a refusé le problème <strong>{problem} : " \
"{problem_name}.").format(trigram=trigram, problem=problem, f"{settings.PROBLEMS[problem - 1]}</strong>. "
problem_name=settings.PROBLEMS[problem - 1]) + " "
if remaining >= 0: if remaining >= 0:
msg += _("It remains {remaining} refusals without penalty.").format(remaining=remaining) msg += f"Il lui reste {remaining} refus sans pénalité."
else: else:
if already_refused: if already_refused:
msg += _("This problem was already refused by this team.") msg += "Cela n'ajoute pas de pénalité."
else: else:
msg += _("It adds a 25% penalty on the coefficient of the oral defense.") msg += "Cela ajoute une pénalité de 25&nbsp;% sur le coefficient de l'oral de la défense."
self.tournament.draw.last_message = msg self.tournament.draw.last_message = msg
await self.tournament.draw.asave() await self.tournament.draw.asave()
@ -987,8 +984,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Notify the team that it can draw a problem # Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{new_trigram}", await self.channel_layer.group_send(f"team-{new_trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Your turn!"), 'title': "À votre tour !",
'body': _("It's your turn to draw a problem!")}) 'body': "C'est à vous de tirer un nouveau problème !"})
@ensure_orga @ensure_orga
async def export(self, **kwargs): async def export(self, **kwargs):
@ -1025,17 +1022,17 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
r2 = await self.tournament.draw.round_set.filter(number=2).aget() r2 = await self.tournament.draw.round_set.filter(number=2).aget()
self.tournament.draw.current_round = r2 self.tournament.draw.current_round = r2
msg = _("The draw of the round 2 is starting. " msg = "Le tirage au sort pour le tour 2 va commencer. " \
"The passage order is determined from the ranking of the first round, " "L'ordre de passage est déterminé à partir du classement du premier tour, " \
"in order to mix the teams between the two days.") "de sorte à mélanger les équipes entre les deux jours."
self.tournament.draw.last_message = msg self.tournament.draw.last_message = msg
await self.tournament.draw.asave() await self.tournament.draw.asave()
# Send notification to everyone # Send notification to everyone
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Draw") + " " + settings.APP_NAME, 'title': 'Tirage au sort du TFJM²',
'body': _("The draw of the second round is starting!")}) 'body': "Le tirage au sort pour le second tour de la finale a commencé !"})
# Set the first pool of the second round as the active pool # Set the first pool of the second round as the active pool
pool = await Pool.objects.filter(round=self.tournament.draw.current_round, letter=1).aget() pool = await Pool.objects.filter(round=self.tournament.draw.current_round, letter=1).aget()
@ -1085,8 +1082,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Notify the team that it can draw a problem # Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
{'tid': self.tournament_id, 'type': 'draw.notify', {'tid': self.tournament_id, 'type': 'draw.notify',
'title': _("Your turn!"), 'title': "À votre tour !",
'body': _("It's your turn to draw a problem!")}) 'body': "C'est à vous de tirer un nouveau problème !"})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.dice_visibility', {'tid': self.tournament_id, 'type': 'draw.dice_visibility',

View File

@ -110,61 +110,58 @@ class Draw(models.Model):
# Waiting for dices to determine pools and passage order # Waiting for dices to determine pools and passage order
if self.current_round.number == 1: if self.current_round.number == 1:
# Specific information for the first round # Specific information for the first round
s += _("We are going to start the problem draw.<br>" s += """Nous allons commencer le tirage des problèmes.<br>
"You can ask any question if something is not clear or wrong.<br><br>" Vous pouvez à tout moment poser toute question si quelque chose
"We are going to first draw the pools and the passage order for the first round " n'est pas clair ou ne va pas.<br><br>
"with all the teams, then for each pool, we will draw the draw order and the problems.") Nous allons d'abord tirer les poules et l'ordre de passage
s += "<br><br>" pour le premier tour avec toutes les équipes puis pour chaque poule,
s += _("The captains, you can now all throw a 100-sided dice, by clicking on the big dice button. " nous tirerons l'ordre de tirage pour le tour et les problèmes.<br><br>"""
"The pools and the passage order during the first round will be the increasing order " s += """
"of the dices, ie. the smallest dice will be the first to pass in pool A.") Les capitaines, vous pouvez désormais toustes lancer un 100,
en cliquant sur le gros bouton. Les poules et l'ordre de passage
lors du premier tour sera l'ordre croissant des dés, c'est-à-dire
que le plus petit lancer sera le premier à passer dans la poule A."""
case 'DICE_ORDER_POULE': case 'DICE_ORDER_POULE':
# Waiting for dices to determine the choice order # Waiting for dices to determine the choice order
s += _("We are going to start the problem draw for the pool <strong>{pool}</strong>, " s += f"""Nous passons au tirage des problèmes pour la poule
"between the teams <strong>{teams}</strong>. " <strong>{self.current_round.current_pool}</strong>, entre les équipes
"The captains can throw a 100-sided dice by clicking on the big dice button " <strong>{', '.join(td.participation.team.trigram
"to determine the order of draw. The team with the highest score will draw first.") \ for td in self.current_round.current_pool.teamdraw_set.all())}</strong>.
.format(pool=self.current_round.current_pool, Les capitaines peuvent lancer un 100 en cliquant sur le gros bouton
teams=', '.join(td.participation.team.trigram pour déterminer l'ordre de tirage. L'équipe réalisant le plus gros score pourra
for td in self.current_round.current_pool.teamdraw_set.all())) tirer en premier."""
case 'WAITING_DRAW_PROBLEM': case 'WAITING_DRAW_PROBLEM':
# Waiting for a problem draw # Waiting for a problem draw
td = self.current_round.current_pool.current_team td = self.current_round.current_pool.current_team
s += _("The team <strong>{trigram}</strong> is going to draw a problem. " s += f"""C'est au tour de l'équipe <strong>{td.participation.team.trigram}</strong>
"Click on the urn in the middle to draw a problem.") \ de choisir son problème. Cliquez sur l'urne au milieu pour tirer un problème au sort."""
.format(trigram=td.participation.team.trigram)
case 'WAITING_CHOOSE_PROBLEM': case 'WAITING_CHOOSE_PROBLEM':
# Waiting for the team that can accept or reject the problem # Waiting for the team that can accept or reject the problem
td = self.current_round.current_pool.current_team td = self.current_round.current_pool.current_team
s += _("The team <strong>{trigram}</strong> drew the problem <strong>{problem}: " s += f"""L'équipe <strong>{td.participation.team.trigram}</strong> a tiré le problème
"{problem_name}</strong>.") \ <strong>{td.purposed} : {settings.PROBLEMS[td.purposed - 1]}</strong>. """
.format(trigram=td.participation.team.trigram,
problem=td.purposed, problem_name=settings.PROBLEMS[td.purposed - 1]) + " "
if td.purposed in td.rejected: if td.purposed in td.rejected:
# The problem was previously rejected # The problem was previously rejected
s += _("It already refused this problem before, so it can refuse it without penalty and " s += """Elle a déjà refusé ce problème auparavant, elle peut donc le refuser sans pénalité et
"draw a new problem immediately, or change its mind.") tirer un nouveau problème immédiatement, ou bien revenir sur son choix."""
else: else:
# The problem can be rejected # The problem can be rejected
s += _("It can decide to accept or refuse this problem.") + " " s += "Elle peut décider d'accepter ou de refuser ce problème. "
if len(td.rejected) >= len(settings.PROBLEMS) - settings.RECOMMENDED_SOLUTIONS_COUNT: if len(td.rejected) >= len(settings.PROBLEMS) - settings.RECOMMENDED_SOLUTIONS_COUNT:
s += _("Refusing this problem will add a new 25% penalty " s += "Refuser ce problème ajoutera une nouvelle pénalité de 25 % sur le coefficient de l'oral de la défense."
"on the coefficient of the oral defense.")
else: else:
s += _("There are still {remaining} refusals without penalty.").format( s += f"Il reste {len(settings.PROBLEMS) - settings.RECOMMENDED_SOLUTIONS_COUNT - len(td.rejected)} refus sans pénalité."
remaining=len(settings.PROBLEMS) - settings.RECOMMENDED_SOLUTIONS_COUNT - len(td.rejected))
case 'WAITING_FINAL': case 'WAITING_FINAL':
# We are between the two rounds of the final tournament # We are between the two rounds of the final tournament
s += _("The draw for the second round will take place at the end of the first round. Good luck!") s += "Le tirage au sort pour le tour 2 aura lieu à la fin du premier tour. Bon courage !"
case 'DRAW_ENDED': case 'DRAW_ENDED':
# The draw is ended # The draw is ended
s += _("The draw is ended. The solutions of the other teams can be found in the tab " s += "Le tirage au sort est terminé. Les solutions des autres équipes peuvent être trouvées dans l'onglet « Ma participation »."
"\"My participation\".")
s += "<br><br>" if s else "" s += "<br><br>" if s else ""
rules_link = "https://tfjm.org/reglement" if settings.TFJM_APP == "TFJM" else "https://eteam.tfjm.org/rules/" s += """Pour plus de détails sur le déroulement du tirage au sort,
s += _("For more details on the draw, the rules are available on " le règlement est accessible sur
"<a class=\"alert-link\" href=\"{link}\">{link}</a>.").format(link=rules_link) <a class="alert-link" href="https://tfjm.org/reglement">https://tfjm.org/reglement</a>."""
return s return s
async def ainformation(self) -> str: async def ainformation(self) -> str:
@ -415,7 +412,7 @@ class Pool(models.Model):
solution_number=tds[line[0]].accepted, solution_number=tds[line[0]].accepted,
defender=tds[line[0]].participation, defender=tds[line[0]].participation,
opponent=tds[line[1]].participation, opponent=tds[line[1]].participation,
reviewer=tds[line[2]].participation, reporter=tds[line[2]].participation,
defender_penalties=tds[line[0]].penalty_int, defender_penalties=tds[line[0]].penalty_int,
) )

View File

@ -529,37 +529,37 @@ document.addEventListener('DOMContentLoaded', () => {
opponentTd.classList.add('text-center') opponentTd.classList.add('text-center')
opponentTd.innerText = 'Opp' opponentTd.innerText = 'Opp'
let reviewerTd = document.createElement('td') let reporterTd = document.createElement('td')
reviewerTd.classList.add('text-center') reporterTd.classList.add('text-center')
reviewerTd.innerText = 'Rap' reporterTd.innerText = 'Rap'
// Put the cells in their right places, according to the pool size and the row number. // Put the cells in their right places, according to the pool size and the row number.
if (poule.teams.length === 3) { if (poule.teams.length === 3) {
switch (i) { switch (i) {
case 0: case 0:
teamTr.append(defenderTd, reviewerTd, opponentTd) teamTr.append(defenderTd, reporterTd, opponentTd)
break break
case 1: case 1:
teamTr.append(opponentTd, defenderTd, reviewerTd) teamTr.append(opponentTd, defenderTd, reporterTd)
break break
case 2: case 2:
teamTr.append(reviewerTd, opponentTd, defenderTd) teamTr.append(reporterTd, opponentTd, defenderTd)
break break
} }
} else if (poule.teams.length === 4) { } else if (poule.teams.length === 4) {
let emptyTd = document.createElement('td') let emptyTd = document.createElement('td')
switch (i) { switch (i) {
case 0: case 0:
teamTr.append(defenderTd, emptyTd, reviewerTd, opponentTd) teamTr.append(defenderTd, emptyTd, reporterTd, opponentTd)
break break
case 1: case 1:
teamTr.append(opponentTd, defenderTd, emptyTd, reviewerTd) teamTr.append(opponentTd, defenderTd, emptyTd, reporterTd)
break break
case 2: case 2:
teamTr.append(reviewerTd, opponentTd, defenderTd, emptyTd) teamTr.append(reporterTd, opponentTd, defenderTd, emptyTd)
break break
case 3: case 3:
teamTr.append(emptyTd, reviewerTd, opponentTd, defenderTd) teamTr.append(emptyTd, reporterTd, opponentTd, defenderTd)
break break
} }
} else if (poule.teams.length === 5) { } else if (poule.teams.length === 5) {
@ -567,19 +567,19 @@ document.addEventListener('DOMContentLoaded', () => {
let emptyTd2 = document.createElement('td') let emptyTd2 = document.createElement('td')
switch (i) { switch (i) {
case 0: case 0:
teamTr.append(defenderTd, emptyTd, opponentTd, reviewerTd, emptyTd2) teamTr.append(defenderTd, emptyTd, opponentTd, reporterTd, emptyTd2)
break break
case 1: case 1:
teamTr.append(emptyTd, defenderTd, reviewerTd, emptyTd2, opponentTd) teamTr.append(emptyTd, defenderTd, reporterTd, emptyTd2, opponentTd)
break break
case 2: case 2:
teamTr.append(opponentTd, emptyTd, defenderTd, emptyTd2, reviewerTd) teamTr.append(opponentTd, emptyTd, defenderTd, emptyTd2, reporterTd)
break break
case 3: case 3:
teamTr.append(reviewerTd, opponentTd, emptyTd, defenderTd, emptyTd2) teamTr.append(reporterTd, opponentTd, emptyTd, defenderTd, emptyTd2)
break break
case 4: case 4:
teamTr.append(emptyTd, reviewerTd, emptyTd2, opponentTd, defenderTd) teamTr.append(emptyTd, reporterTd, emptyTd2, opponentTd, defenderTd)
break break
} }
} }

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: TFJM\n" "Project-Id-Version: TFJM\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-05 10:48+0200\n" "POT-Creation-Date: 2024-06-13 10:56+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n" "Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -93,7 +93,7 @@ msgstr ""
"Pour une permission qui concerne un tournoi, indique quel est le tournoi " "Pour une permission qui concerne un tournoi, indique quel est le tournoi "
"concerné." "concerné."
#: chat/models.py:73 draw/models.py:432 draw/models.py:459 #: chat/models.py:73 draw/models.py:429 draw/models.py:456
#: participation/admin.py:136 participation/admin.py:155 #: participation/admin.py:136 participation/admin.py:155
#: participation/models.py:1515 participation/models.py:1524 #: participation/models.py:1515 participation/models.py:1524
#: participation/tables.py:84 #: participation/tables.py:84
@ -264,12 +264,12 @@ msgstr "Connexion"
msgid "teams" msgid "teams"
msgstr "équipes" msgstr "équipes"
#: draw/admin.py:92 draw/models.py:237 draw/models.py:451 #: draw/admin.py:92 draw/models.py:234 draw/models.py:448
#: participation/models.py:1016 #: participation/models.py:1016
msgid "round" msgid "round"
msgstr "tour" msgstr "tour"
#: draw/apps.py:10 draw/consumers.py:1037 tfjm/templates/navbar.html:68 #: draw/apps.py:10 tfjm/templates/navbar.html:68
msgid "Draw" msgid "Draw"
msgstr "Tirage au sort" msgstr "Tirage au sort"
@ -277,182 +277,67 @@ msgstr "Tirage au sort"
msgid "You are not an organizer." msgid "You are not an organizer."
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice." msgstr "Vous n'êtes pas un⋅e organisateur⋅rice."
#: draw/consumers.py:167 #: draw/consumers.py:165
msgid "The draw is already started." msgid "The draw is already started."
msgstr "Le tirage a déjà commencé." msgstr "Le tirage a déjà commencé."
#: draw/consumers.py:173 #: draw/consumers.py:171
msgid "Invalid format" msgid "Invalid format"
msgstr "Format invalide" msgstr "Format invalide"
#: draw/consumers.py:178 #: draw/consumers.py:176
#, python-brace-format #, python-brace-format
msgid "The sum must be equal to the number of teams: expected {len}, got {sum}" msgid "The sum must be equal to the number of teams: expected {len}, got {sum}"
msgstr "" msgstr ""
"La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}" "La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}"
#: draw/consumers.py:183 #: draw/consumers.py:181
msgid "There can be at most one pool with 5 teams." msgid "There can be at most one pool with 5 teams."
msgstr "Il ne peut y avoir au plus qu'une seule poule de 5 équipes." msgstr "Il ne peut y avoir au plus qu'une seule poule de 5 équipes."
#: draw/consumers.py:223 #: draw/consumers.py:221
msgid "Draw started!" msgid "Draw started!"
msgstr "Le tirage a commencé !" msgstr "Le tirage a commencé !"
#: draw/consumers.py:238 #: draw/consumers.py:243
#, python-brace-format
msgid "The draw of tournament {tournament} started!"
msgstr "Le tirage au sort du tournoi {tournament} a commencé !"
#: draw/consumers.py:245
#, python-brace-format #, python-brace-format
msgid "The draw for the tournament {tournament} will start." msgid "The draw for the tournament {tournament} will start."
msgstr "Le tirage au sort du tournoi {tournament} va commencer." msgstr "Le tirage au sort du tournoi {tournament} va commencer."
#: draw/consumers.py:256 draw/consumers.py:282 draw/consumers.py:691 #: draw/consumers.py:254 draw/consumers.py:280 draw/consumers.py:690
#: draw/consumers.py:909 draw/consumers.py:999 draw/consumers.py:1021 #: draw/consumers.py:907 draw/consumers.py:996 draw/consumers.py:1018
#: draw/consumers.py:1112 draw/templates/draw/tournament_content.html:5 #: draw/consumers.py:1109 draw/templates/draw/tournament_content.html:5
msgid "The draw has not started yet." msgid "The draw has not started yet."
msgstr "Le tirage au sort n'a pas encore commencé." msgstr "Le tirage au sort n'a pas encore commencé."
#: draw/consumers.py:269 #: draw/consumers.py:267
#, python-brace-format #, python-brace-format
msgid "The draw for the tournament {tournament} is aborted." msgid "The draw for the tournament {tournament} is aborted."
msgstr "Le tirage au sort du tournoi {tournament} est annulé." msgstr "Le tirage au sort du tournoi {tournament} est annulé."
#: draw/consumers.py:309 draw/consumers.py:330 draw/consumers.py:625 #: draw/consumers.py:307 draw/consumers.py:328 draw/consumers.py:624
#: draw/consumers.py:696 draw/consumers.py:914 #: draw/consumers.py:695 draw/consumers.py:912
msgid "This is not the time for this." msgid "This is not the time for this."
msgstr "Ce n'est pas le moment pour cela." msgstr "Ce n'est pas le moment pour cela."
#: draw/consumers.py:322 draw/consumers.py:325 #: draw/consumers.py:320 draw/consumers.py:323
msgid "You've already launched the dice." msgid "You've already launched the dice."
msgstr "Vous avez déjà lancé le dé." msgstr "Vous avez déjà lancé le dé."
#: draw/consumers.py:328 #: draw/consumers.py:326
msgid "It is not your turn." msgid "It is not your turn."
msgstr "Ce n'est pas votre tour." msgstr "Ce n'est pas votre tour."
#: draw/consumers.py:408 #: draw/consumers.py:413
msgid ""
"Your dice score is identical to the one of one or multiple teams. Please "
"relaunch it."
msgstr ""
"Votre score de dé est identique à celui d'une ou plusieurs équipes. Merci de "
"le relancer."
#: draw/consumers.py:415
#, python-brace-format #, python-brace-format
msgid "Dices from teams {teams} are identical. Please relaunch your dices." msgid "Dices from teams {teams} are identical. Please relaunch your dices."
msgstr "" msgstr ""
"Les dés des équipes {teams} sont identiques. Merci de relancer vos dés." "Les dés des équipes {teams} sont identiques. Merci de relancer vos dés."
#: draw/consumers.py:508 #: draw/consumers.py:1021
#, python-brace-format
msgid ""
"The dice results are the following: {trigrams}. The passage order and the "
"compositions of the different pools are displayed on the side. The passage "
"orders for the first round are determined from the dice scores, in "
"increasing order. For the second round, the passage orders are determined "
"from the passage orders of the first round."
msgstr ""
"Les résultats des dés sont les suivants : {trigrams}. L'ordre de passage et "
"les compositions des différentes poules sont affichés sur le côté. Les "
"ordres de passage pour le premier tour sont déterminés à partir des scores "
"de dés, par ordre croissant. Pour le deuxième tour, les ordres de passage "
"sont déterminés à partir des ordres de passage du premier tour."
#: draw/consumers.py:614 draw/consumers.py:754 draw/consumers.py:831
#: draw/consumers.py:865 draw/consumers.py:990 draw/consumers.py:1088
msgid "Your turn!"
msgstr "À votre tour !"
#: draw/consumers.py:615 draw/consumers.py:755 draw/consumers.py:991
#: draw/consumers.py:1089
msgid "It's your turn to draw a problem!"
msgstr "C'est à vous de tirer un problème !"
#: draw/consumers.py:635 draw/consumers.py:706 draw/consumers.py:924
msgid "This is not your turn."
msgstr "Ce n'est pas votre tour."
#: draw/consumers.py:713
#, python-brace-format
msgid ""
"The team <strong>{trigram}</strong> accepted the problem <string>{problem}</"
"strong>: {problem_name}. "
msgstr ""
"L'équipe <strong>{trigram}</strong> a accepté le problème <strong>{problem}</"
"strong> : {problem_name}. "
#: draw/consumers.py:717
msgid "One team more can accept this problem."
msgstr "Une équipe de plus peut accepter ce problème."
#: draw/consumers.py:719
msgid "No team can accept this problem anymore."
msgstr "Aucune autre équipe ne peut accepter ce problème."
#: draw/consumers.py:813
#, python-brace-format
msgid "The draw of the pool {pool} is ended. The summary is below."
msgstr "Le tirage de la poule {pool} est terminé. Le résumé est ci-dessous."
#: draw/consumers.py:832 draw/consumers.py:866
msgid "It's your turn to launch the dice!"
msgstr "C'est à vous de lancer le dé !"
#: draw/consumers.py:852
#, python-brace-format
msgid "The draw of the round {round} is ended."
msgstr "Le tirage au sort du tour {round} est annulé."
#: draw/consumers.py:895
msgid "The draw of the first round is ended."
msgstr "Le tirage au sort du premier tour est terminé."
#: draw/consumers.py:938
#, python-brace-format
msgid ""
"The team <strong>{trigram}</strong> refused the problem <strong>{problem}</"
"strong>: {problem_name}."
msgstr ""
"L'équipe <strong>{trigram}</strong> a refusé le problème <strong>{problem}</"
"strong> : {problem_name}."
#: draw/consumers.py:942
#, python-brace-format
msgid "It remains {remaining} refusals without penalty."
msgstr "Il reste {remaining} refus sans pénalité."
#: draw/consumers.py:945
msgid "This problem was already refused by this team."
msgstr "Ce problème a déjà été refusé par cette équipe."
#: draw/consumers.py:947
msgid "It adds a 25% penalty on the coefficient of the oral defense."
msgstr ""
"Cela ajoute une pénalité de 25&nbsp;% sur le coefficient de l'oral de la "
"défense."
#: draw/consumers.py:1024
msgid "This is only available for the final tournament." msgid "This is only available for the final tournament."
msgstr "Cela n'est possible que pour la finale." msgstr "Cela n'est possible que pour la finale."
#: draw/consumers.py:1028
msgid ""
"The draw of the round 2 is starting. The passage order is determined from "
"the ranking of the first round, in order to mix the teams between the two "
"days."
msgstr ""
"Le tirage au sort du tour 2 commence. L'ordre de passage est déterminé à "
"partir du classement du premier tour, afin de mélanger les équipes entre les "
"deux jours."
#: draw/consumers.py:1038
msgid "The draw of the second round is starting!"
msgstr "Le tirage au sort du deuxième tour commence !"
#: draw/models.py:27 #: draw/models.py:27
msgid "The associated tournament." msgid "The associated tournament."
msgstr "Le tournoi associé." msgstr "Le tournoi associé."
@ -477,261 +362,154 @@ msgstr "Le dernier message qui est affiché sur l'interface de tirage."
msgid "State" msgid "State"
msgstr "État" msgstr "État"
#: draw/models.py:113 #: draw/models.py:174
msgid ""
"We are going to start the problem draw.<br>You can ask any question if "
"something is not clear or wrong.<br><br>We are going to first draw the pools "
"and the passage order for the first round with all the teams, then for each "
"pool, we will draw the draw order and the problems."
msgstr ""
"Nous allons commencer le tirage des problèmes.<br>Vous pouvez poser des "
"questions si quelque chose n'est pas clair ou faux.<br><br>Nous allons "
"d'abord tirer les poules et l'ordre de passage pour le premier tour avec "
"toutes les équipes, puis pour chaque poule, nous allons tirer l'ordre de "
"tirage et les problèmes."
#: draw/models.py:118
msgid ""
"The captains, you can now all throw a 100-sided dice, by clicking on the big "
"dice button. The pools and the passage order during the first round will be "
"the increasing order of the dices, ie. the smallest dice will be the first "
"to pass in pool A."
msgstr ""
"Les capitaines, vous pouvez maintenant tous lancer un dé à 100 faces, en "
"cliquant sur le gros bouton de dé. Les poules et l'ordre de passage pendant "
"le premier tour seront l'ordre croissant des dés, c'est-à-dire que le plus "
"petit dé passera en premier dans la poule A."
#: draw/models.py:123
#, python-brace-format
msgid ""
"We are going to start the problem draw for the pool <strong>{pool}</strong>, "
"between the teams <strong>{teams}</strong>. The captains can throw a 100-"
"sided dice by clicking on the big dice button to determine the order of "
"draw. The team with the highest score will draw first."
msgstr ""
"Nous allons commencer le tirage des problèmes pour la poule <strong>{pool}</"
"strong>, entre les équipes <strong>{teams}</strong>. Les capitaines peuvent "
"lancer un dé à 100 faces en cliquant sur le gros bouton de dé pour "
"déterminer l'ordre de tirage. L'équipe avec le score le plus élevé tirera en "
"premier."
#: draw/models.py:133
#, python-brace-format
msgid ""
"The team <strong>{trigram}</strong> is going to draw a problem. Click on the "
"urn in the middle to draw a problem."
msgstr ""
"L'équipe <strong>{trigram}</strong> va tirer un problème. Cliquez sur l'urne "
"au milieu pour tirer un problème."
#: draw/models.py:139
#, python-brace-format
msgid ""
"The team <strong>{trigram}</strong> drew the problem <strong>{problem}: "
"{problem_name}</strong>."
msgstr ""
"L'équipe <strong>{trigram}</strong> a tiré le problème <strong>{problem} : "
"{problem_name}</strong>."
#: draw/models.py:145
msgid ""
"It already refused this problem before, so it can refuse it without penalty "
"and draw a new problem immediately, or change its mind."
msgstr ""
"Elle a déjà refusé ce problème auparavant, donc elle peut le refuser sans "
"pénalité et tirer un nouveau problème immédiatement, ou changer d'avis."
#: draw/models.py:149
msgid "It can decide to accept or refuse this problem."
msgstr "Elle peut décider d'accepter ou de refuser ce problème."
#: draw/models.py:151
msgid ""
"Refusing this problem will add a new 25% penalty on the coefficient of "
"the oral defense."
msgstr ""
"Refuser ce problème ajoutera une nouvelle pénalité de 25nbsp;% sur le "
"coefficient de l'oral de la défense."
#: draw/models.py:154
#, python-brace-format
msgid "There are still {remaining} refusals without penalty."
msgstr "Il reste {remaining} refus sans pénalité."
#: draw/models.py:158
msgid ""
"The draw for the second round will take place at the end of the first round. "
"Good luck!"
msgstr ""
"Le tirage au sort du deuxième tour aura lieu à la fin du premier tour. Bonne "
"chance !"
#: draw/models.py:161
msgid ""
"The draw is ended. The solutions of the other teams can be found in the tab "
"\"My participation\"."
msgstr ""
"Le tirage est terminé. Les solutions des autres équipes peuvent être "
"trouvées dans l'onglet « Ma participation »."
#: draw/models.py:166
#, python-brace-format
msgid ""
"For more details on the draw, the rules are available on <a class=\"alert-"
"link\" href=\"{link}\">{link}</a>."
msgstr ""
"Pour plus de détails sur le tirage, les règles sont disponibles sur <a "
"class=\"alert-link\" href=\"{link}\">{link}</a>."
#: draw/models.py:177
#, python-brace-format #, python-brace-format
msgid "Draw of tournament {tournament}" msgid "Draw of tournament {tournament}"
msgstr "Tirage au sort du tournoi {tournament}" msgstr "Tirage au sort du tournoi {tournament}"
#: draw/models.py:180 draw/models.py:192 #: draw/models.py:177 draw/models.py:189
msgid "draw" msgid "draw"
msgstr "tirage au sort" msgstr "tirage au sort"
#: draw/models.py:181 #: draw/models.py:178
msgid "draws" msgid "draws"
msgstr "tirages au sort" msgstr "tirages au sort"
#: draw/models.py:197 #: draw/models.py:194
msgid "Round 1" msgid "Round 1"
msgstr "Tour 1" msgstr "Tour 1"
#: draw/models.py:198 #: draw/models.py:195
msgid "Round 2" msgid "Round 2"
msgstr "Tour 2" msgstr "Tour 2"
#: draw/models.py:199 #: draw/models.py:196
msgid "Round 3" msgid "Round 3"
msgstr "Tour 3" msgstr "Tour 3"
#: draw/models.py:200 #: draw/models.py:197
msgid "number" msgid "number"
msgstr "numéro" msgstr "numéro"
#: draw/models.py:201 #: draw/models.py:198
msgid "The number of the round, 1 or 2 (or 3 for ETEAM)" msgid "The number of the round, 1 or 2 (or 3 for ETEAM)"
msgstr "Le numéro du tour, 1 ou 2 (ou 3 pour ETEAM)" msgstr "Le numéro du tour, 1 ou 2 (ou 3 pour ETEAM)"
#: draw/models.py:211 #: draw/models.py:208
msgid "current pool" msgid "current pool"
msgstr "poule actuelle" msgstr "poule actuelle"
#: draw/models.py:212 #: draw/models.py:209
msgid "The current pool where teams select their problems." msgid "The current pool where teams select their problems."
msgstr "La poule en cours, où les équipes choisissent leurs problèmes" msgstr "La poule en cours, où les équipes choisissent leurs problèmes"
#: draw/models.py:238 #: draw/models.py:235
msgid "rounds" msgid "rounds"
msgstr "tours" msgstr "tours"
#: draw/models.py:260 participation/models.py:1024 #: draw/models.py:257 participation/models.py:1024
msgid "letter" msgid "letter"
msgstr "lettre" msgstr "lettre"
#: draw/models.py:261 #: draw/models.py:258
msgid "The letter of the pool: A, B, C or D." msgid "The letter of the pool: A, B, C or D."
msgstr "La lettre de la poule : A, B, C ou D." msgstr "La lettre de la poule : A, B, C ou D."
#: draw/models.py:265 #: draw/models.py:262
#: participation/templates/participation/tournament_detail.html:15 #: participation/templates/participation/tournament_detail.html:15
msgid "size" msgid "size"
msgstr "taille" msgstr "taille"
#: draw/models.py:267 #: draw/models.py:264
msgid "The number of teams in this pool, between 3 and 5." msgid "The number of teams in this pool, between 3 and 5."
msgstr "Le nombre d'équipes dans la poule, entre 3 et 5." msgstr "Le nombre d'équipes dans la poule, entre 3 et 5."
#: draw/models.py:276 #: draw/models.py:273
msgid "current team" msgid "current team"
msgstr "équipe actuelle" msgstr "équipe actuelle"
#: draw/models.py:277 #: draw/models.py:274
msgid "The current team that is selecting its problem." msgid "The current team that is selecting its problem."
msgstr "L'équipe qui est en train de choisir son problème." msgstr "L'équipe qui est en train de choisir son problème."
#: draw/models.py:286 #: draw/models.py:283
msgid "associated pool" msgid "associated pool"
msgstr "poule associée" msgstr "poule associée"
#: draw/models.py:287 #: draw/models.py:284
msgid "The full pool instance." msgid "The full pool instance."
msgstr "L'instance complète de la poule." msgstr "L'instance complète de la poule."
#: draw/models.py:429 #: draw/models.py:426
#, python-brace-format #, python-brace-format
msgid "Pool {letter}{number}" msgid "Pool {letter}{number}"
msgstr "Poule {letter}{number}" msgstr "Poule {letter}{number}"
#: draw/models.py:433 participation/models.py:1516 #: draw/models.py:430 participation/models.py:1516
msgid "pools" msgid "pools"
msgstr "poules" msgstr "poules"
#: draw/models.py:445 participation/models.py:1002 participation/models.py:1665 #: draw/models.py:442 participation/models.py:1002 participation/models.py:1665
#: participation/models.py:1695 participation/models.py:1737 #: participation/models.py:1695 participation/models.py:1737
msgid "participation" msgid "participation"
msgstr "participation" msgstr "participation"
#: draw/models.py:466 #: draw/models.py:463
msgid "passage index" msgid "passage index"
msgstr "numéro de passage" msgstr "numéro de passage"
#: draw/models.py:467 #: draw/models.py:464
msgid "" msgid ""
"The passage order in the pool, between 0 and the size of the pool minus 1." "The passage order in the pool, between 0 and the size of the pool minus 1."
msgstr "" msgstr ""
"L'ordre de passage dans la poule, de 0 à la taille de la poule moins 1." "L'ordre de passage dans la poule, de 0 à la taille de la poule moins 1."
#: draw/models.py:475 #: draw/models.py:472
msgid "choose index" msgid "choose index"
msgstr "numéro de choix" msgstr "numéro de choix"
#: draw/models.py:476 #: draw/models.py:473
msgid "" msgid ""
"The choice order in the pool, between 0 and the size of the pool minus 1." "The choice order in the pool, between 0 and the size of the pool minus 1."
msgstr "" msgstr ""
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1." "L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
#: draw/models.py:482 draw/models.py:505 participation/models.py:1538 #: draw/models.py:479 draw/models.py:502 participation/models.py:1538
#: participation/models.py:1702 #: participation/models.py:1702
#, python-brace-format #, python-brace-format
msgid "Problem #{problem}" msgid "Problem #{problem}"
msgstr "Problème n°{problem}" msgstr "Problème n°{problem}"
#: draw/models.py:486 #: draw/models.py:483
msgid "accepted problem" msgid "accepted problem"
msgstr "problème accepté" msgstr "problème accepté"
#: draw/models.py:493 #: draw/models.py:490
msgid "passage dice" msgid "passage dice"
msgstr "dé d'ordre de passage" msgstr "dé d'ordre de passage"
#: draw/models.py:500 #: draw/models.py:497
msgid "choice dice" msgid "choice dice"
msgstr "dé d'ordre de choix" msgstr "dé d'ordre de choix"
#: draw/models.py:509 #: draw/models.py:506
msgid "purposed problem" msgid "purposed problem"
msgstr "problème proposé" msgstr "problème proposé"
#: draw/models.py:514 #: draw/models.py:511
msgid "rejected problems" msgid "rejected problems"
msgstr "problèmes rejetés" msgstr "problèmes rejetés"
#: draw/models.py:543 #: draw/models.py:540
#, python-brace-format #, python-brace-format
msgid "Draw of the team {trigram} for the pool {letter}{number}" msgid "Draw of the team {trigram} for the pool {letter}{number}"
msgstr "Tirage de l'équipe {trigram} pour la poule {letter}{number}" msgstr "Tirage de l'équipe {trigram} pour la poule {letter}{number}"
#: draw/models.py:549 #: draw/models.py:546
msgid "team draw" msgid "team draw"
msgstr "tirage d'équipe" msgstr "tirage d'équipe"
#: draw/models.py:550 #: draw/models.py:547
msgid "team draws" msgid "team draws"
msgstr "tirages d'équipe" msgstr "tirages d'équipe"
@ -924,7 +702,7 @@ msgstr "opposant⋅e"
#: participation/admin.py:132 participation/models.py:1559 #: participation/admin.py:132 participation/models.py:1559
#: participation/models.py:1750 #: participation/models.py:1750
msgid "reviewer" msgid "reporter"
msgstr "rapporteur⋅rice" msgstr "rapporteur⋅rice"
#: participation/admin.py:187 participation/models.py:1700 #: participation/admin.py:187 participation/models.py:1700
@ -1016,7 +794,7 @@ msgid "The following user was not found:"
msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :" msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :"
#: participation/forms.py:349 #: participation/forms.py:349
msgid "The defender, the opponent and the reviewer must be different." msgid "The defender, the opponent and the reporter must be different."
msgstr "" msgstr ""
"Les équipes défenseuse, opposante et rapportrice doivent être différent⋅es." "Les équipes défenseuse, opposante et rapportrice doivent être différent⋅es."
@ -1397,11 +1175,11 @@ msgstr ""
#: participation/models.py:966 #: participation/models.py:966
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"<p>You will report the solution of the team {reviewer} on the <a " "<p>You will report the solution of the team {reporter} on the <a "
"href='{solution_url}'>problem {problem}. You can upload your synthesis sheet " "href='{solution_url}'>problem {problem}. You can upload your synthesis sheet "
"on <a href='{passage_url}'>this page</a>.</p>" "on <a href='{passage_url}'>this page</a>.</p>"
msgstr "" msgstr ""
"<p>Vous rapporterez la solution de l'équipe {reviewer} sur le <a " "<p>Vous rapporterez la solution de l'équipe {reporter} sur le <a "
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note " "href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>" "de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
@ -1631,11 +1409,11 @@ msgid "opponent oral note"
msgstr "note d'oral opposant⋅e" msgstr "note d'oral opposant⋅e"
#: participation/models.py:1815 #: participation/models.py:1815
msgid "reviewer writing note" msgid "reporter writing note"
msgstr "note d'écrit rapporteur⋅rice" msgstr "note d'écrit rapporteur⋅rice"
#: participation/models.py:1821 #: participation/models.py:1821
msgid "reviewer oral note" msgid "reporter oral note"
msgstr "note d'oral du rapporteur⋅rice" msgstr "note d'oral du rapporteur⋅rice"
#: participation/models.py:1881 #: participation/models.py:1881
@ -1814,7 +1592,7 @@ msgid "Opponent:"
msgstr "Opposant⋅e :" msgstr "Opposant⋅e :"
#: participation/templates/participation/passage_detail.html:34 #: participation/templates/participation/passage_detail.html:34
msgid "reviewer:" msgid "Reporter:"
msgstr "Rapporteur⋅rice :" msgstr "Rapporteur⋅rice :"
#: participation/templates/participation/passage_detail.html:37 #: participation/templates/participation/passage_detail.html:37
@ -1866,11 +1644,11 @@ msgid "Average points for the opponent oral"
msgstr "Moyenne de l'oral de l'équipe opposante" msgstr "Moyenne de l'oral de l'équipe opposante"
#: participation/templates/participation/passage_detail.html:101 #: participation/templates/participation/passage_detail.html:101
msgid "Average points for the reviewer writing" msgid "Average points for the reporter writing"
msgstr "Moyenne de l'écrit de l'équipe rapportrice" msgstr "Moyenne de l'écrit de l'équipe rapportrice"
#: participation/templates/participation/passage_detail.html:107 #: participation/templates/participation/passage_detail.html:107
msgid "Average points for the reviewer oral" msgid "Average points for the reporter oral"
msgstr "Moyenne de l'oral de l'équipe rapportrice" msgstr "Moyenne de l'oral de l'équipe rapportrice"
#: participation/templates/participation/passage_detail.html:117 #: participation/templates/participation/passage_detail.html:117
@ -1882,7 +1660,7 @@ msgid "Opponent points"
msgstr "Points de l'équipe opposante" msgstr "Points de l'équipe opposante"
#: participation/templates/participation/passage_detail.html:129 #: participation/templates/participation/passage_detail.html:129
msgid "reviewer points" msgid "Reporter points"
msgstr "Points de l'équipe rapportrice" msgstr "Points de l'équipe rapportrice"
#: participation/templates/participation/passage_detail.html:139 #: participation/templates/participation/passage_detail.html:139

View File

@ -51,7 +51,7 @@ class PassageInline(admin.TabularInline):
model = Passage model = Passage
extra = 0 extra = 0
ordering = ('position',) ordering = ('position',)
autocomplete_fields = ('defender', 'opponent', 'reviewer',) autocomplete_fields = ('defender', 'opponent', 'reporter',)
show_change_link = True show_change_link = True
@ -113,12 +113,12 @@ class PoolAdmin(admin.ModelAdmin):
@admin.register(Passage) @admin.register(Passage)
class PassageAdmin(admin.ModelAdmin): class PassageAdmin(admin.ModelAdmin):
list_display = ('__str__', 'defender_trigram', 'solution_number', 'opponent_trigram', 'reviewer_trigram', list_display = ('__str__', 'defender_trigram', 'solution_number', 'opponent_trigram', 'reporter_trigram',
'pool_abbr', 'position', 'tournament') 'pool_abbr', 'position', 'tournament')
list_filter = ('pool__tournament', 'pool__round', 'pool__letter', 'solution_number',) list_filter = ('pool__tournament', 'pool__round', 'pool__letter', 'solution_number',)
search_fields = ('pool__participations__team__name', 'pool__participations__team__trigram',) search_fields = ('pool__participations__team__name', 'pool__participations__team__trigram',)
ordering = ('pool__tournament', 'pool__round', 'pool__letter', 'position',) ordering = ('pool__tournament', 'pool__round', 'pool__letter', 'position',)
autocomplete_fields = ('pool', 'defender', 'opponent', 'reviewer',) autocomplete_fields = ('pool', 'defender', 'opponent', 'reporter',)
inlines = (NoteInline,) inlines = (NoteInline,)
@admin.display(description=_("defender"), ordering='defender__team__trigram') @admin.display(description=_("defender"), ordering='defender__team__trigram')
@ -129,9 +129,9 @@ class PassageAdmin(admin.ModelAdmin):
def opponent_trigram(self, record: Passage): def opponent_trigram(self, record: Passage):
return record.opponent.team.trigram return record.opponent.team.trigram
@admin.display(description=_("reviewer"), ordering='reviewer__team__trigram') @admin.display(description=_("reporter"), ordering='reporter__team__trigram')
def reviewer_trigram(self, record: Passage): def reporter_trigram(self, record: Passage):
return record.reviewer.team.trigram return record.reporter.team.trigram
@admin.display(description=_("pool"), ordering='pool__letter') @admin.display(description=_("pool"), ordering='pool__letter')
def pool_abbr(self, record): def pool_abbr(self, record):
@ -145,10 +145,10 @@ class PassageAdmin(admin.ModelAdmin):
@admin.register(Note) @admin.register(Note)
class NoteAdmin(admin.ModelAdmin): class NoteAdmin(admin.ModelAdmin):
list_display = ('passage', 'pool', 'jury', 'defender_writing', 'defender_oral', list_display = ('passage', 'pool', 'jury', 'defender_writing', 'defender_oral',
'opponent_writing', 'opponent_oral', 'reviewer_writing', 'reviewer_oral',) 'opponent_writing', 'opponent_oral', 'reporter_writing', 'reporter_oral',)
list_filter = ('passage__pool__letter', 'passage__solution_number', 'jury', list_filter = ('passage__pool__letter', 'passage__solution_number', 'jury',
'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral', 'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral',
'reviewer_writing', 'reviewer_oral') 'reporter_writing', 'reporter_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__defender__team__trigram',)
autocomplete_fields = ('jury', 'passage',) autocomplete_fields = ('jury', 'passage',)

View File

@ -13,7 +13,7 @@ class NoteViewSet(ModelViewSet):
serializer_class = NoteSerializer serializer_class = NoteSerializer
filter_backends = [DjangoFilterBackend] filter_backends = [DjangoFilterBackend]
filterset_fields = ['jury', 'passage', 'defender_writing', 'defender_oral', 'opponent_writing', filterset_fields = ['jury', 'passage', 'defender_writing', 'defender_oral', 'opponent_writing',
'opponent_oral', 'reviewer_writing', 'reviewer_oral', ] 'opponent_oral', 'reporter_writing', 'reporter_oral', ]
class ParticipationViewSet(ModelViewSet): class ParticipationViewSet(ModelViewSet):
@ -27,7 +27,7 @@ class PassageViewSet(ModelViewSet):
queryset = Passage.objects.all() queryset = Passage.objects.all()
serializer_class = PassageSerializer serializer_class = PassageSerializer
filter_backends = [DjangoFilterBackend] filter_backends = [DjangoFilterBackend]
filterset_fields = ['pool', 'solution_number', 'defender', 'opponent', 'reviewer', 'pool_tournament', ] filterset_fields = ['pool', 'solution_number', 'defender', 'opponent', 'reporter', 'pool_tournament', ]
class PoolViewSet(ModelViewSet): class PoolViewSet(ModelViewSet):

View File

@ -344,9 +344,9 @@ class UploadNotesForm(forms.Form):
class PassageForm(forms.ModelForm): class PassageForm(forms.ModelForm):
def clean(self): def clean(self):
cleaned_data = super().clean() cleaned_data = super().clean()
if "defender" in cleaned_data and "opponent" in cleaned_data and "reviewer" in cleaned_data \ if "defender" in cleaned_data and "opponent" in cleaned_data and "reporter" in cleaned_data \
and len({cleaned_data["defender"], cleaned_data["opponent"], cleaned_data["reviewer"]}) < 3: and len({cleaned_data["defender"], cleaned_data["opponent"], cleaned_data["reporter"]}) < 3:
self.add_error(None, _("The defender, the opponent and the reviewer must be different.")) self.add_error(None, _("The defender, the opponent and the reporter must be different."))
if "defender" in self.cleaned_data and "solution_number" in self.cleaned_data \ if "defender" in self.cleaned_data and "solution_number" in self.cleaned_data \
and not Solution.objects.filter(participation=cleaned_data["defender"], and not Solution.objects.filter(participation=cleaned_data["defender"],
problem=cleaned_data["solution_number"]).exists(): problem=cleaned_data["solution_number"]).exists():
@ -355,7 +355,7 @@ class PassageForm(forms.ModelForm):
class Meta: class Meta:
model = Passage model = Passage
fields = ('position', 'solution_number', 'defender', 'opponent', 'reviewer', 'defender_penalties',) fields = ('position', 'solution_number', 'defender', 'opponent', 'reporter', 'defender_penalties',)
class SynthesisForm(forms.ModelForm): class SynthesisForm(forms.ModelForm):
@ -386,4 +386,4 @@ class NoteForm(forms.ModelForm):
class Meta: class Meta:
model = Note model = Note
fields = ('defender_writing', 'defender_oral', 'opponent_writing', fields = ('defender_writing', 'defender_oral', 'opponent_writing',
'opponent_oral', 'reviewer_writing', 'reviewer_oral', ) 'opponent_oral', 'reporter_writing', 'reporter_oral', )

View File

@ -53,23 +53,23 @@ class Command(BaseCommand):
pool1 = tournament.pools.filter(round=1, participations=team2).first() pool1 = tournament.pools.filter(round=1, participations=team2).first()
defender_passage_1 = Passage.objects.get(pool__tournament=tournament, pool__round=1, defender=team2) defender_passage_1 = Passage.objects.get(pool__tournament=tournament, pool__round=1, defender=team2)
opponent_passage_1 = Passage.objects.get(pool__tournament=tournament, pool__round=1, opponent=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) reporter_passage_1 = Passage.objects.get(pool__tournament=tournament, pool__round=1, reporter=team2)
pool2 = tournament.pools.filter(round=2, participations=team2).first() pool2 = tournament.pools.filter(round=2, participations=team2).first()
defender_passage_2 = Passage.objects.get(pool__tournament=tournament, pool__round=2, defender=team2) defender_passage_2 = Passage.objects.get(pool__tournament=tournament, pool__round=2, defender=team2)
opponent_passage_2 = Passage.objects.get(pool__tournament=tournament, pool__round=2, opponent=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) reporter_passage_2 = Passage.objects.get(pool__tournament=tournament, pool__round=2, reporter=team2)
line.append(team2.team.trigram) line.append(team2.team.trigram)
line.append(str(pool1.jury_president or "")) line.append(str(pool1.jury_president or ""))
line.append(f"Pb. {defender_passage_1.solution_number}") line.append(f"Pb. {defender_passage_1.solution_number}")
line.extend([defender_passage_1.average_defender_writing, defender_passage_1.average_defender_oral, line.extend([defender_passage_1.average_defender_writing, defender_passage_1.average_defender_oral,
opponent_passage_1.average_opponent_writing, opponent_passage_1.average_opponent_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]) reporter_passage_1.average_reporter_writing, reporter_passage_1.average_reporter_oral])
line.append(str(pool2.jury_president or "")) line.append(str(pool2.jury_president or ""))
line.append(f"Pb. {defender_passage_2.solution_number}") line.append(f"Pb. {defender_passage_2.solution_number}")
line.extend([defender_passage_2.average_defender_writing, defender_passage_2.average_defender_oral, line.extend([defender_passage_2.average_defender_writing, defender_passage_2.average_defender_oral,
opponent_passage_2.average_opponent_writing, opponent_passage_2.average_opponent_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]) reporter_passage_2.average_reporter_writing, reporter_passage_2.average_reporter_oral])
line.extend([score2, f"{score1:.1f} ({team1.team.trigram})", line.extend([score2, f"{score1:.1f} ({team1.team.trigram})",
f"{score3:.1f} ({team3.team.trigram})"]) f"{score3:.1f} ({team3.team.trigram})"])

View File

@ -1,91 +0,0 @@
# Generated by Django 5.0.6 on 2024-07-05 08:53
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
(
"participation",
"0017_alter_passage_solution_number_alter_pool_round_and_more",
),
]
operations = [
migrations.RenameField(
model_name="note",
old_name="reporter_oral",
new_name="reviewer_oral",
),
migrations.RenameField(
model_name="note",
old_name="reporter_writing",
new_name="reviewer_writing",
),
migrations.RenameField(
model_name="passage",
old_name="reporter",
new_name="reviewer",
),
migrations.AlterField(
model_name="note",
name="reviewer_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),
],
default=0,
verbose_name="reviewer oral note",
),
),
migrations.AlterField(
model_name="note",
name="reviewer_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),
],
default=0,
verbose_name="reviewer writing note",
),
),
migrations.AlterField(
model_name="passage",
name="reviewer",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to="participation.participation",
verbose_name="reviewer",
),
),
migrations.AlterField(
model_name="synthesis",
name="type",
field=models.PositiveSmallIntegerField(
choices=[(1, "opponent"), (2, "reviewer")]
),
),
]

View File

@ -858,7 +858,7 @@ class Participation(models.Model):
elif timezone.now() <= tournament.syntheses_first_phase_limit + timedelta(hours=2): 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) defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, defender=self)
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, opponent=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) reporter_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=1, reporter=self)
defender_text = _("<p>The solutions draw is ended. You can check the result on " defender_text = _("<p>The solutions draw is ended. You can check the result on "
"<a href='{draw_url}'>this page</a>.</p>" "<a href='{draw_url}'>this page</a>.</p>"
@ -878,21 +878,21 @@ class Participation(models.Model):
solution_url=solution_url, solution_url=solution_url,
problem=opponent_passage.solution_number, passage_url=passage_url) problem=opponent_passage.solution_number, passage_url=passage_url)
reviewer_text = _("<p>You will report the solution of the team {reviewer} on the " reporter_text = _("<p>You will report the solution of the team {reporter} on the "
"<a href='{solution_url}'>problem {problem}. " "<a href='{solution_url}'>problem {problem}. "
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>") "You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
solution_url = reviewer_passage.defended_solution.file.url solution_url = reporter_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,)) passage_url = reverse_lazy("participation:passage_detail", args=(reporter_passage.pk,))
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram, reporter_content = format_lazy(reporter_text, reporter=reporter_passage.defender.team.trigram,
solution_url=solution_url, solution_url=solution_url,
problem=reviewer_passage.solution_number, passage_url=passage_url) problem=reporter_passage.solution_number, passage_url=passage_url)
syntheses_template_begin = f"{settings.STATIC_URL}Fiche_synthèse." syntheses_template_begin = f"{settings.STATIC_URL}Fiche_synthèse."
syntheses_templates = "".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>" syntheses_templates = "".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
for ext in ["pdf", "tex", "odt", "docx"]) for ext in ["pdf", "tex", "odt", "docx"])
syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>" syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>"
content = defender_content + opponent_content + reviewer_content + syntheses_templates_content content = defender_content + opponent_content + reporter_content + syntheses_templates_content
informations.append({ informations.append({
'title': _("First round"), 'title': _("First round"),
'type': "info", 'type': "info",
@ -902,7 +902,7 @@ class Participation(models.Model):
elif timezone.now() <= tournament.syntheses_second_phase_limit + timedelta(hours=2): 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) defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, defender=self)
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, opponent=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) reporter_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=2, reporter=self)
defender_text = _("<p>For the second round, you will defend " defender_text = _("<p>For the second round, you will defend "
"<a href='{solution_url}'>your solution of the problem {problem}</a>.</p>") "<a href='{solution_url}'>your solution of the problem {problem}</a>.</p>")
@ -920,21 +920,21 @@ class Participation(models.Model):
solution_url=solution_url, solution_url=solution_url,
problem=opponent_passage.solution_number, passage_url=passage_url) problem=opponent_passage.solution_number, passage_url=passage_url)
reviewer_text = _("<p>You will report the solution of the team {reviewer} on the " reporter_text = _("<p>You will report the solution of the team {reporter} on the "
"<a href='{solution_url}'>problem {problem}. " "<a href='{solution_url}'>problem {problem}. "
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>") "You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
solution_url = reviewer_passage.defended_solution.file.url solution_url = reporter_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,)) passage_url = reverse_lazy("participation:passage_detail", args=(reporter_passage.pk,))
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram, reporter_content = format_lazy(reporter_text, reporter=reporter_passage.defender.team.trigram,
solution_url=solution_url, solution_url=solution_url,
problem=reviewer_passage.solution_number, passage_url=passage_url) problem=reporter_passage.solution_number, passage_url=passage_url)
syntheses_template_begin = f"{settings.STATIC_URL}Fiche_synthèse." syntheses_template_begin = f"{settings.STATIC_URL}Fiche_synthèse."
syntheses_templates = "".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>" syntheses_templates = "".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
for ext in ["pdf", "tex", "odt", "docx"]) for ext in ["pdf", "tex", "odt", "docx"])
syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>" syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>"
content = defender_content + opponent_content + reviewer_content + syntheses_templates_content content = defender_content + opponent_content + reporter_content + syntheses_templates_content
informations.append({ informations.append({
'title': _("Second round"), 'title': _("Second round"),
'type': "info", 'type': "info",
@ -945,7 +945,7 @@ class Participation(models.Model):
and timezone.now() <= tournament.syntheses_third_phase_limit + timedelta(hours=2): 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) defender_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, defender=self)
opponent_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, opponent=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) reporter_passage = Passage.objects.get(pool__tournament=self.tournament, pool__round=3, reporter=self)
defender_text = _("<p>For the third round, you will defend " defender_text = _("<p>For the third round, you will defend "
"<a href='{solution_url}'>your solution of the problem {problem}</a>.</p>") "<a href='{solution_url}'>your solution of the problem {problem}</a>.</p>")
@ -963,21 +963,21 @@ class Participation(models.Model):
solution_url=solution_url, solution_url=solution_url,
problem=opponent_passage.solution_number, passage_url=passage_url) problem=opponent_passage.solution_number, passage_url=passage_url)
reviewer_text = _("<p>You will report the solution of the team {reviewer} on the " reporter_text = _("<p>You will report the solution of the team {reporter} on the "
"<a href='{solution_url}'>problem {problem}. " "<a href='{solution_url}'>problem {problem}. "
"You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>") "You can upload your synthesis sheet on <a href='{passage_url}'>this page</a>.</p>")
solution_url = reviewer_passage.defended_solution.file.url solution_url = reporter_passage.defended_solution.file.url
passage_url = reverse_lazy("participation:passage_detail", args=(reviewer_passage.pk,)) passage_url = reverse_lazy("participation:passage_detail", args=(reporter_passage.pk,))
reviewer_content = format_lazy(reviewer_text, reviewer=reviewer_passage.defender.team.trigram, reporter_content = format_lazy(reporter_text, reporter=reporter_passage.defender.team.trigram,
solution_url=solution_url, solution_url=solution_url,
problem=reviewer_passage.solution_number, passage_url=passage_url) problem=reporter_passage.solution_number, passage_url=passage_url)
syntheses_template_begin = f"{settings.STATIC_URL}Fiche_synthèse." syntheses_template_begin = f"{settings.STATIC_URL}Fiche_synthèse."
syntheses_templates = "".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>" syntheses_templates = "".join(f"<a href='{syntheses_template_begin}{ext}'>{ext.upper()}</a>"
for ext in ["pdf", "tex", "odt", "docx"]) for ext in ["pdf", "tex", "odt", "docx"])
syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>" syntheses_templates_content = f"<p>{_('Templates:')} {syntheses_templates}</p>"
content = defender_content + opponent_content + reviewer_content + syntheses_templates_content content = defender_content + opponent_content + reporter_content + syntheses_templates_content
informations.append({ informations.append({
'title': _("Second round"), 'title': _("Second round"),
'type': "info", 'type': "info",
@ -1132,7 +1132,7 @@ class Pool(models.Model):
for passage in passages), start=["Problème", ""]), for passage in passages), start=["Problème", ""]),
sum(([f"Défenseur⋅se ({passage.defender.team.trigram})", "", sum(([f"Défenseur⋅se ({passage.defender.team.trigram})", "",
f"Opposant⋅e ({passage.opponent.team.trigram})", "", f"Opposant⋅e ({passage.opponent.team.trigram})", "",
f"Rapporteur⋅rice ({passage.reviewer.team.trigram})", ""] f"Rapporteur⋅rice ({passage.reporter.team.trigram})", ""]
for passage in passages), start=["Rôle", ""]), for passage in passages), start=["Rôle", ""]),
sum((["Écrit (/20)", "Oral (/20)", "Écrit (/10)", "Oral (/10)", "Écrit (/10)", "Oral (/10)"] sum((["Écrit (/20)", "Oral (/20)", "Écrit (/10)", "Oral (/10)", "Écrit (/10)", "Oral (/10)"]
for _passage in passages), start=["Juré⋅e", ""]), for _passage in passages), start=["Juré⋅e", ""]),
@ -1144,7 +1144,7 @@ class Pool(models.Model):
for passage in passages: for passage in passages:
note = passage.notes.filter(jury=jury).first() note = passage.notes.filter(jury=jury).first()
line.extend([note.defender_writing, note.defender_oral, note.opponent_writing, note.opponent_oral, line.extend([note.defender_writing, note.defender_oral, note.opponent_writing, note.opponent_oral,
note.reviewer_writing, note.reviewer_oral]) note.reporter_writing, note.reporter_oral])
notes.append(line) notes.append(line)
notes.append([]) # Add empty line to ensure pretty design notes.append([]) # Add empty line to ensure pretty design
@ -1204,18 +1204,18 @@ class Pool(models.Model):
opponent_row = 5 + opponent_passage.pool.juries.count() opponent_row = 5 + opponent_passage.pool.juries.count()
opponent_col = opponent_passage.position - 1 opponent_col = opponent_passage.position - 1
reviewer_passage = Passage.objects.get(reviewer=participation, reporter_passage = Passage.objects.get(reporter=participation,
pool__tournament=self.tournament, pool__round=self.round) pool__tournament=self.tournament, pool__round=self.round)
reviewer_row = 5 + reviewer_passage.pool.juries.count() reporter_row = 5 + reporter_passage.pool.juries.count()
reviewer_col = reviewer_passage.position - 1 reporter_col = reporter_passage.position - 1
formula = "=" formula = "="
formula += (f"'Poule {defender_passage.pool.short_name}'" formula += (f"'Poule {defender_passage.pool.short_name}'"
f"!{getcol(min_column + defender_col * passage_width)}{defender_row + 3}") # Defender f"!{getcol(min_column + defender_col * passage_width)}{defender_row + 3}") # Defender
formula += (f" + 'Poule {opponent_passage.pool.short_name}'" formula += (f" + 'Poule {opponent_passage.pool.short_name}'"
f"!{getcol(min_column + opponent_col * passage_width + 2)}{opponent_row + 3}") # Opponent f"!{getcol(min_column + opponent_col * passage_width + 2)}{opponent_row + 3}") # Opponent
formula += (f" + 'Poule {reviewer_passage.pool.short_name}'" formula += (f" + 'Poule {reporter_passage.pool.short_name}'"
f"!{getcol(min_column + reviewer_col * passage_width + 4)}{reviewer_row + 3}") # reviewer f"!{getcol(min_column + reporter_col * passage_width + 4)}{reporter_row + 3}") # Reporter
ranking.append([f"{participation.team.name} ({participation.team.trigram})", "", ranking.append([f"{participation.team.name} ({participation.team.trigram})", "",
f"='Poule {defender_passage.pool.short_name}'" f"='Poule {defender_passage.pool.short_name}'"
f"!${getcol(3 + defender_col * passage_width)}$1", f"!${getcol(3 + defender_col * passage_width)}$1",
@ -1553,10 +1553,10 @@ class Passage(models.Model):
related_name="+", related_name="+",
) )
reviewer = models.ForeignKey( reporter = models.ForeignKey(
Participation, Participation,
on_delete=models.PROTECT, on_delete=models.PROTECT,
verbose_name=_("reviewer"), verbose_name=_("reporter"),
related_name="+", related_name="+",
) )
@ -1603,16 +1603,16 @@ class Passage(models.Model):
return 0.9 * self.average_opponent_writing + 2 * self.average_opponent_oral return 0.9 * self.average_opponent_writing + 2 * self.average_opponent_oral
@property @property
def average_reviewer_writing(self) -> float: def average_reporter_writing(self) -> float:
return self.avg(note.reviewer_writing for note in self.notes.all()) return self.avg(note.reporter_writing for note in self.notes.all())
@property @property
def average_reviewer_oral(self) -> float: def average_reporter_oral(self) -> float:
return self.avg(note.reviewer_oral for note in self.notes.all()) return self.avg(note.reporter_oral for note in self.notes.all())
@property @property
def average_reviewer(self) -> float: def average_reporter(self) -> float:
return 0.9 * self.average_reviewer_writing + self.average_reviewer_oral return 0.9 * self.average_reporter_writing + self.average_reporter_oral
@property @property
def averages(self): def averages(self):
@ -1620,12 +1620,12 @@ class Passage(models.Model):
yield self.average_defender_oral yield self.average_defender_oral
yield self.average_opponent_writing yield self.average_opponent_writing
yield self.average_opponent_oral yield self.average_opponent_oral
yield self.average_reviewer_writing yield self.average_reporter_writing
yield self.average_reviewer_oral yield self.average_reporter_oral
def average(self, participation): def average(self, participation):
return self.average_defender if participation == self.defender else self.average_opponent \ return self.average_defender if participation == self.defender else self.average_opponent \
if participation == self.opponent else self.average_reviewer if participation == self.reviewer else 0 if participation == self.opponent else self.average_reporter if participation == self.reporter else 0
def get_absolute_url(self): def get_absolute_url(self):
return reverse_lazy("participation:passage_detail", args=(self.pk,)) return reverse_lazy("participation:passage_detail", args=(self.pk,))
@ -1637,9 +1637,9 @@ class Passage(models.Model):
if self.opponent not in self.pool.participations.all(): if self.opponent not in self.pool.participations.all():
raise ValidationError(_("Team {trigram} is not registered in the pool.") raise ValidationError(_("Team {trigram} is not registered in the pool.")
.format(trigram=self.opponent.team.trigram)) .format(trigram=self.opponent.team.trigram))
if self.reviewer 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.") raise ValidationError(_("Team {trigram} is not registered in the pool.")
.format(trigram=self.reviewer.team.trigram)) .format(trigram=self.reporter.team.trigram))
return super().clean() return super().clean()
def __str__(self): def __str__(self):
@ -1747,7 +1747,7 @@ class Synthesis(models.Model):
type = models.PositiveSmallIntegerField( type = models.PositiveSmallIntegerField(
choices=[ choices=[
(1, _("opponent"), ), (1, _("opponent"), ),
(2, _("reviewer"), ), (2, _("reporter"), ),
] ]
) )
@ -1811,14 +1811,14 @@ class Note(models.Model):
default=0, default=0,
) )
reviewer_writing = models.PositiveSmallIntegerField( reporter_writing = models.PositiveSmallIntegerField(
verbose_name=_("reviewer writing note"), verbose_name=_("reporter writing note"),
choices=[(i, i) for i in range(0, 11)], choices=[(i, i) for i in range(0, 11)],
default=0, default=0,
) )
reviewer_oral = models.PositiveSmallIntegerField( reporter_oral = models.PositiveSmallIntegerField(
verbose_name=_("reviewer oral note"), verbose_name=_("reporter oral note"),
choices=[(i, i) for i in range(0, 11)], choices=[(i, i) for i in range(0, 11)],
default=0, default=0,
) )
@ -1828,17 +1828,17 @@ class Note(models.Model):
yield self.defender_oral yield self.defender_oral
yield self.opponent_writing yield self.opponent_writing
yield self.opponent_oral yield self.opponent_oral
yield self.reviewer_writing yield self.reporter_writing
yield self.reviewer_oral yield self.reporter_oral
def set_all(self, defender_writing: int, defender_oral: int, opponent_writing: int, opponent_oral: int, def set_all(self, defender_writing: int, defender_oral: int, opponent_writing: int, opponent_oral: int,
reviewer_writing: int, reviewer_oral: int): reporter_writing: int, reporter_oral: int):
self.defender_writing = defender_writing self.defender_writing = defender_writing
self.defender_oral = defender_oral self.defender_oral = defender_oral
self.opponent_writing = opponent_writing self.opponent_writing = opponent_writing
self.opponent_oral = opponent_oral self.opponent_oral = opponent_oral
self.reviewer_writing = reviewer_writing self.reporter_writing = reporter_writing
self.reviewer_oral = reviewer_oral self.reporter_oral = reporter_oral
def update_spreadsheet(self): def update_spreadsheet(self):
if not self.has_any_note(): if not self.has_any_note():

View File

@ -118,7 +118,7 @@ class PassageTable(tables.Table):
def render_opponent(self, value): def render_opponent(self, value):
return value.team.trigram return value.team.trigram
def render_reviewer(self, value): def render_reporter(self, value):
return value.team.trigram return value.team.trigram
class Meta: class Meta:
@ -126,7 +126,7 @@ class PassageTable(tables.Table):
'class': 'table table-condensed table-striped text-center', 'class': 'table table-condensed table-striped text-center',
} }
model = Passage model = Passage
fields = ('defender', 'opponent', 'reviewer', 'solution_number', ) fields = ('defender', 'opponent', 'reporter', 'solution_number', )
class NoteTable(tables.Table): class NoteTable(tables.Table):
@ -155,4 +155,4 @@ class NoteTable(tables.Table):
} }
model = Note model = Note
fields = ('jury', 'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral', fields = ('jury', 'defender_writing', 'defender_oral', 'opponent_writing', 'opponent_oral',
'reviewer_writing', 'reviewer_oral', 'update',) 'reporter_writing', 'reporter_oral', 'update',)

View File

@ -31,8 +31,8 @@
<dt class="col-sm-3">{% trans "Opponent:" %}</dt> <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> <dd class="col-sm-9"><a href="{{ passage.opponent.get_absolute_url }}">{{ passage.opponent.team }}</a></dd>
<dt class="col-sm-3">{% trans "reviewer:" %}</dt> <dt class="col-sm-3">{% trans "Reporter:" %}</dt>
<dd class="col-sm-9"><a href="{{ passage.reviewer.get_absolute_url }}">{{ passage.reviewer.team }}</a></dd> <dd class="col-sm-9"><a href="{{ passage.reporter.get_absolute_url }}">{{ passage.reporter.team }}</a></dd>
<dt class="col-sm-3">{% trans "Defended solution:" %}</dt> <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> <dd class="col-sm-9"><a href="{{ passage.defended_solution.file.url }}">{{ passage.defended_solution }}</a></dd>
@ -98,16 +98,16 @@
<dd class="col-sm-4">{{ passage.average_opponent_oral|floatformat }}/10</dd> <dd class="col-sm-4">{{ passage.average_opponent_oral|floatformat }}/10</dd>
<dt class="col-sm-8"> <dt class="col-sm-8">
{% trans "Average points for the reviewer writing" %} {% trans "Average points for the reporter writing" %}
({{ passage.reviewer.team.trigram }}) : ({{ passage.reporter.team.trigram }}) :
</dt> </dt>
<dd class="col-sm-4">{{ passage.average_reviewer_writing|floatformat }}/10</dd> <dd class="col-sm-4">{{ passage.average_reporter_writing|floatformat }}/10</dd>
<dt class="col-sm-8"> <dt class="col-sm-8">
{% trans "Average points for the reviewer oral" %} {% trans "Average points for the reporter oral" %}
({{ passage.reviewer.team.trigram }}) : ({{ passage.reporter.team.trigram }}) :
</dt> </dt>
<dd class="col-sm-4">{{ passage.average_reviewer_oral|floatformat }}/10</dd> <dd class="col-sm-4">{{ passage.average_reporter_oral|floatformat }}/10</dd>
</dl> </dl>
<hr> <hr>
@ -126,10 +126,10 @@
<dd class="col-sm-4">{{ passage.average_opponent|floatformat }}/29</dd> <dd class="col-sm-4">{{ passage.average_opponent|floatformat }}/29</dd>
<dt class="col-sm-8"> <dt class="col-sm-8">
{% trans "reviewer points" %} {% trans "Reporter points" %}
({{ passage.reviewer.team.trigram }}) : ({{ passage.reporter.team.trigram }}) :
</dt> </dt>
<dd class="col-sm-4">{{ passage.average_reviewer|floatformat }}/19</dd> <dd class="col-sm-4">{{ passage.average_reporter|floatformat }}/19</dd>
</dl> </dl>
</div> </div>
</div> </div>

View File

@ -100,7 +100,7 @@
%%%%%%%%%%%%%%%%%%%%%%RAPPORTEUR.RICE %%%%%%%%%%%%%%%%%%%%%%RAPPORTEUR.RICE
\begin{tabular}{|c|p{24mm}|p{11cm}|c{% for passage in passages.all %}|p{2cm}{% endfor %}|}\hline \begin{tabular}{|c|p{24mm}|p{11cm}|c{% for passage in passages.all %}|p{2cm}{% endfor %}|}\hline
\multicolumn{4}{|l|}{{\bf Rapporteur\textperiodcentered{}rice} \normalsize \'evalue le d\'ebat entre læ D\'efenseur\textperiodcentered{}se et l'Opposant\textperiodcentered{}e.} {% for passage in passages.all %}& P.{{ forloop.counter }} - {{ passage.reviewer.team.trigram }} {% endfor %}\\ \hline \hline \multicolumn{4}{|l|}{{\bf Rapporteur\textperiodcentered{}rice} \normalsize \'evalue le d\'ebat entre læ D\'efenseur\textperiodcentered{}se et l'Opposant\textperiodcentered{}e.} {% for passage in passages.all %}& P.{{ forloop.counter }} - {{ passage.reporter.team.trigram }} {% endfor %}\\ \hline \hline
%ECRIT %ECRIT
\multirow{4}{3mm}{\centering\bf\'E\\ C\\ R\\ I\\ T} &\multirow{3}{20mm}{Partie scientifique} & Recul et esprit critique par rapport à la solution proposée & [0,3] {{ esp|safe }}\\ \cline{3-{{ passages.count|add:4 }}} \multirow{4}{3mm}{\centering\bf\'E\\ C\\ R\\ I\\ T} &\multirow{3}{20mm}{Partie scientifique} & Recul et esprit critique par rapport à la solution proposée & [0,3] {{ esp|safe }}\\ \cline{3-{{ passages.count|add:4 }}}

View File

@ -56,7 +56,7 @@ Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{% if pool.partici
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$ & \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$ & \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$
{% endfor %} & \hline {% endfor %} & \hline
\multirow{2}{35mm}{\LARGE Rapporteur\textperiodcentered{}rice} {% for passage in passages.all %}& \multicolumn{2}{c|}{\Large {{ passage.reviewer.team.trigram }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}} \multirow{2}{35mm}{\LARGE Rapporteur\textperiodcentered{}rice} {% 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 %} {% for passage in passages.all %}
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$ & \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$
& \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$ & \phantom{asd asd} \phantom{asd asd} \centering \normalsize$0\leq x\leq 10$

View File

@ -1507,11 +1507,11 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
header_role.addElement(opponent_tc) header_role.addElement(opponent_tc)
header_role.addElement(CoveredTableCell()) header_role.addElement(CoveredTableCell())
reviewer_tc = TableCell(valuetype="string", reporter_tc = TableCell(valuetype="string",
stylename=title_style_right) stylename=title_style_right)
reviewer_tc.addElement(P(text="Rapporteur⋅rice")) reporter_tc.addElement(P(text="Rapporteur⋅rice"))
reviewer_tc.setAttribute('numbercolumnsspanned', "2") reporter_tc.setAttribute('numbercolumnsspanned', "2")
header_role.addElement(reviewer_tc) header_role.addElement(reporter_tc)
header_role.addElement(CoveredTableCell()) header_role.addElement(CoveredTableCell())
# Add maximum notes on the third line # Add maximum notes on the third line
@ -1540,13 +1540,13 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
opponent_o_tc.addElement(P(text="Oral (/10)")) opponent_o_tc.addElement(P(text="Oral (/10)"))
header_notes.addElement(opponent_o_tc) header_notes.addElement(opponent_o_tc)
reviewer_w_tc = TableCell(valuetype="string", stylename=title_style_bot) reporter_w_tc = TableCell(valuetype="string", stylename=title_style_bot)
reviewer_w_tc.addElement(P(text="Écrit (/10)")) reporter_w_tc.addElement(P(text="Écrit (/10)"))
header_notes.addElement(reviewer_w_tc) header_notes.addElement(reporter_w_tc)
reviewer_o_tc = TableCell(valuetype="string", stylename=title_style_botright) reporter_o_tc = TableCell(valuetype="string", stylename=title_style_botright)
reviewer_o_tc.addElement(P(text="Oral (/10)")) reporter_o_tc.addElement(P(text="Oral (/10)"))
header_notes.addElement(reviewer_o_tc) header_notes.addElement(reporter_o_tc)
# Add a notation line for each jury # Add a notation line for each jury
for jury in self.object.juries.all(): for jury in self.object.juries.all():
@ -1617,13 +1617,13 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
opponent_o_tc.addElement(P(text="2")) opponent_o_tc.addElement(P(text="2"))
coeff_row.addElement(opponent_o_tc) coeff_row.addElement(opponent_o_tc)
reviewer_w_tc = TableCell(valuetype="float", value=0.9, stylename=style) reporter_w_tc = TableCell(valuetype="float", value=0.9, stylename=style)
reviewer_w_tc.addElement(P(text="1")) reporter_w_tc.addElement(P(text="1"))
coeff_row.addElement(reviewer_w_tc) coeff_row.addElement(reporter_w_tc)
reviewer_o_tc = TableCell(valuetype="float", value=1, stylename=style_right) reporter_o_tc = TableCell(valuetype="float", value=1, stylename=style_right)
reviewer_o_tc.addElement(P(text="1")) reporter_o_tc.addElement(P(text="1"))
coeff_row.addElement(reviewer_o_tc) coeff_row.addElement(reporter_o_tc)
# Add the subtotal on the next line # Add the subtotal on the next line
subtotal_row = TableRow() subtotal_row = TableRow()
@ -1656,12 +1656,12 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
rep_w_col = getcol(min_column + passage_width * i + 4) rep_w_col = getcol(min_column + passage_width * i + 4)
rep_o_col = getcol(min_column + passage_width * i + 5) rep_o_col = getcol(min_column + passage_width * i + 5)
reviewer_tc = TableCell(valuetype="float", value=passage.average_reviewer, stylename=style_botright) reporter_tc = TableCell(valuetype="float", value=passage.average_reporter, stylename=style_botright)
reviewer_tc.addElement(P(text=str(passage.average_reviewer))) reporter_tc.addElement(P(text=str(passage.average_reporter)))
reviewer_tc.setAttribute('numbercolumnsspanned', "2") reporter_tc.setAttribute('numbercolumnsspanned', "2")
reviewer_tc.setAttribute("formula", f"of:=[.{rep_w_col}{max_row + 1}] * [.{rep_w_col}{max_row + 2}]" reporter_tc.setAttribute("formula", f"of:=[.{rep_w_col}{max_row + 1}] * [.{rep_w_col}{max_row + 2}]"
f" + [.{rep_o_col}{max_row + 1}] * [.{rep_o_col}{max_row + 2}]") f" + [.{rep_o_col}{max_row + 1}] * [.{rep_o_col}{max_row + 2}]")
subtotal_row.addElement(reviewer_tc) subtotal_row.addElement(reporter_tc)
subtotal_row.addElement(CoveredTableCell()) subtotal_row.addElement(CoveredTableCell())
table.addElement(TableRow()) table.addElement(TableRow())
@ -1713,7 +1713,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
defender_pos = passage.position - 1 defender_pos = passage.position - 1
opponent_pos = self.object.passages.get(opponent=passage.defender).position - 1 opponent_pos = self.object.passages.get(opponent=passage.defender).position - 1
reviewer_pos = self.object.passages.get(reviewer=passage.defender).position - 1 reporter_pos = self.object.passages.get(reporter=passage.defender).position - 1
score_tc = TableCell(valuetype="float", value=self.object.average(passage.defender), score_tc = TableCell(valuetype="float", value=self.object.average(passage.defender),
stylename=style_bot if passage.position == pool_size else style) stylename=style_bot if passage.position == pool_size else style)
@ -1721,7 +1721,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
formula = "of:=" formula = "of:="
formula += getcol(min_column + defender_pos * passage_width) + str(max_row + 3) # Defender formula += getcol(min_column + defender_pos * passage_width) + str(max_row + 3) # Defender
formula += " + " + getcol(min_column + opponent_pos * passage_width + 2) + str(max_row + 3) # Opponent 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 formula += " + " + getcol(min_column + reporter_pos * passage_width + 4) + str(max_row + 3) # Reporter
score_tc.setAttribute("formula", formula) score_tc.setAttribute("formula", formula)
team_row.addElement(score_tc) team_row.addElement(score_tc)
@ -1931,7 +1931,7 @@ class PassageDetailView(LoginRequiredMixin, DetailView):
or reg in passage.pool.juries.all() or reg in passage.pool.juries.all()
or reg.pools_presided.filter(tournament=passage.pool.tournament).exists()) \ or reg.pools_presided.filter(tournament=passage.pool.tournament).exists()) \
or reg.participates and reg.team \ or reg.participates and reg.team \
and reg.team.participation in [passage.defender, passage.opponent, passage.reviewer]: and reg.team.participation in [passage.defender, passage.opponent, passage.reporter]:
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission() return self.handle_no_permission()
@ -1956,8 +1956,8 @@ class PassageDetailView(LoginRequiredMixin, DetailView):
context['notes'].columns['defender_oral'].column.verbose_name += f" ({passage.defender.team.trigram})" context['notes'].columns['defender_oral'].column.verbose_name += f" ({passage.defender.team.trigram})"
context['notes'].columns['opponent_writing'].column.verbose_name += f" ({passage.opponent.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['opponent_oral'].column.verbose_name += f" ({passage.opponent.team.trigram})"
context['notes'].columns['reviewer_writing'].column.verbose_name += f" ({passage.reviewer.team.trigram})" context['notes'].columns['reporter_writing'].column.verbose_name += f" ({passage.reporter.team.trigram})"
context['notes'].columns['reviewer_oral'].column.verbose_name += f" ({passage.reviewer.team.trigram})" context['notes'].columns['reporter_oral'].column.verbose_name += f" ({passage.reporter.team.trigram})"
return context return context
@ -1992,7 +1992,7 @@ class SynthesisUploadView(LoginRequiredMixin, FormView):
self.participation = self.request.user.registration.team.participation self.participation = self.request.user.registration.team.participation
self.passage = qs.get() self.passage = qs.get()
if self.participation not in [self.passage.opponent, self.passage.reviewer]: if self.participation not in [self.passage.opponent, self.passage.reporter]:
return self.handle_no_permission() return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
@ -2050,8 +2050,8 @@ class NoteUpdateView(VolunteerMixin, UpdateView):
form.fields['defender_oral'].label += f" ({self.object.passage.defender.team.trigram})" form.fields['defender_oral'].label += f" ({self.object.passage.defender.team.trigram})"
form.fields['opponent_writing'].label += f" ({self.object.passage.opponent.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['opponent_oral'].label += f" ({self.object.passage.opponent.team.trigram})"
form.fields['reviewer_writing'].label += f" ({self.object.passage.reviewer.team.trigram})" form.fields['reporter_writing'].label += f" ({self.object.passage.reporter.team.trigram})"
form.fields['reviewer_oral'].label += f" ({self.object.passage.reviewer.team.trigram})" form.fields['reporter_oral'].label += f" ({self.object.passage.reporter.team.trigram})"
return form return form
def form_valid(self, form): def form_valid(self, form):

View File

@ -839,7 +839,7 @@ class SolutionView(LoginRequiredMixin, View):
if user.registration.participates: if user.registration.participates:
passage_participant_qs = Passage.objects.filter(Q(defender=user.registration.team.participation) passage_participant_qs = Passage.objects.filter(Q(defender=user.registration.team.participation)
| Q(opponent=user.registration.team.participation) | Q(opponent=user.registration.team.participation)
| Q(reviewer=user.registration.team.participation), | Q(reporter=user.registration.team.participation),
defender=solution.participation, defender=solution.participation,
solution_number=solution.problem) solution_number=solution.problem)
else: else: