1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-09-25 10:58:17 +02:00

Compare commits

..

12 Commits

Author SHA1 Message Date
ehouarn
e55a6ae407 Merge branch 'wei' into 'main'
Wei

See merge request bde/nk20!338
2025-08-03 01:38:27 +02:00
ehouarn
fc0071144e Merge branch 'wei' into 'main'
More robust algorithm

See merge request bde/nk20!337
2025-08-02 17:34:45 +02:00
ehouarn
da30382f41 Merge branch 'wei' into 'main'
Soge credit fixed

See merge request bde/nk20!336
2025-08-02 16:50:24 +02:00
ehouarn
3b7f8b87c4 Merge branch 'wei' into 'main'
Wei

See merge request bde/nk20!335
2025-08-01 23:38:46 +02:00
ehouarn
0992a8a7ee Merge branch 'wei' into 'main'
Wei

See merge request bde/nk20!334
2025-07-24 15:39:51 +02:00
quark
12477b33cb Merge branch 'fix_activity_form' into 'main'
fix organizer field error

See merge request bde/nk20!333
2025-07-22 18:55:27 +02:00
quark
8c3ae338ea fix organizer field error 2025-07-22 18:20:05 +02:00
ehouarn
4975c1ab6f Merge branch 'translations' into 'main'
Translations

See merge request bde/nk20!332
2025-07-19 18:29:18 +02:00
Ehouarn
61999a31a5 Wei details 2025-07-19 18:04:14 +02:00
ehouarn
b217f7ceec Merge branch 'wei' into 'main'
Wei

See merge request bde/nk20!331
2025-07-19 17:27:20 +02:00
Ehouarn
03c1bb41b6 First of many 2025-07-18 23:49:34 +02:00
ehouarn
f03c13a4b8 Merge branch 'wei' into 'main'
Wei

See merge request bde/nk20!330
2025-07-15 19:26:32 +02:00
10 changed files with 148 additions and 255 deletions

View File

@@ -32,7 +32,7 @@ class ActivityForm(forms.ModelForm):
def clean_organizer(self):
organizer = self.cleaned_data['organizer']
if not organizer.note.is_active:
self.add_error('organiser', _('The note of this club is inactive.'))
self.add_error('organizer', _('The note of this club is inactive.'))
return organizer
def clean_date_end(self):

View File

@@ -16,7 +16,7 @@ def save_user_profile(instance, created, raw, **_kwargs):
def update_wei_registration_fee_on_membership_creation(sender, instance, created, **kwargs):
if not hasattr(instance, "_no_signal") and created:
if created:
from wei.models import WEIRegistration
if instance.club.id == 1 or instance.club.id == 2:
registrations = WEIRegistration.objects.filter(
@@ -24,16 +24,14 @@ def update_wei_registration_fee_on_membership_creation(sender, instance, created
wei__year=instance.date_start.year,
)
for r in registrations:
r._force_save = True
r.save()
def update_wei_registration_fee_on_club_change(sender, instance, **kwargs):
from wei.models import WEIRegistration
if not hasattr(instance, "_no_signal") and (instance.id == 1 or instance.id == 2):
if instance.id == 1 or instance.id == 2:
registrations = WEIRegistration.objects.filter(
wei__year=instance.membership_start.year,
)
for r in registrations:
r._force_save = True
r.save()

View File

@@ -69,7 +69,7 @@ class WEIRegistrationForm(forms.ModelForm):
class WEIChooseBusForm(forms.Form):
bus = forms.ModelMultipleChoiceField(
queryset=Bus.objects,
label=_("bus"),
label=_("Bus"),
help_text=_("This choice is not definitive. The WEI organizers are free to attribute for you a bus and a team,"
+ " in particular if you are a free eletron."),
widget=CheckboxSelectMultiple(),

View File

@@ -10,225 +10,145 @@ from django import forms
from django.db import transaction
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from django.utils.safestring import mark_safe
from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInformation
from ...models import WEIMembership, Bus
WORDS = {
'list': [
'Fiesta', 'Graillance', 'Move it move it', 'Calme', 'Nerd et geek', 'Jeux de rôles et danse rock',
'Strass et paillettes', 'Spectaculaire', 'Splendide', 'Flow inégalable', 'Rap', 'Battles légendaires',
'Techno', 'Alcool', 'Kiffeur·euse', 'Rugby', 'Médiéval', 'Festif',
'Stylé', 'Chipie', 'Rétro', 'Vache', 'Farfadet', 'Fanfare',
'13 organisé', '3ième mi temps', 'Années 2000', 'Apéro', 'BBQ', 'BP', 'Beauf', 'Binge drinking', 'Bon enfant',
'Cartouche', 'Catacombes', 'Chansons paillardes', 'Chansons populaires', 'Chanteur', 'Chartreuse', 'Chill',
'Core', 'DJ', 'Dancefloor', 'Danse', 'David Guetta', 'Disco', 'Eau de vie', 'Électro', 'Escalade', 'Familial',
'Fanfare', 'Fracassage', 'Féria', 'Hard rock', 'Hoeggarden', 'House', 'Huit-six', 'IPA', 'Inclusif', 'Inferno',
'Introverti', 'Jager bomb', 'Jazz', 'Jeux d\'alcool', 'Jeux de rôles', 'Jeux vidéo', 'Jul', 'Jus de fruit',
'Karaoké', 'LGBTQI+', 'Lady Gaga', 'Loup garou', 'Morning beer', 'Métal', 'Nuit blanche', 'Ovalie', 'Psychedelic',
'Pétanque', 'Rave', 'Reggae', 'Rhum', 'Ricard', 'Rock', 'Rosé', 'Rétro', 'Séducteur', 'Techno', 'Thérapie taxi',
'Théâtre', 'Trap', 'Turn up', 'Underground', 'Volley', 'Wati B', 'Zinédine Zidane',
],
'questions': {
"alcool": [
"""Sur une échelle allant de 0 (= 0 alcool ou très peu) à 5 (= la fontaine de jouvence alcoolique),
quel niveau de consommation dalcool souhaiterais-tu ?""",
'Question 1': [
'Description 1',
{
42: 4,
47: 1,
48: 3,
45: 3.5,
44: 4,
46: 5,
43: 3,
49: 3
3: 'Réponse 1 Madagas[car]',
4: 'Réponse 1 Y2[KAR]',
2: 'Réponse 1 Tcherno[bus]',
5: 'Réponse 1 [Kar]tier',
1: 'Réponse 1 [Car]cassonne',
6: 'Réponse 1 O[car]ina',
7: 'Réponse 1 Show[bus]',
8: 'Réponse 1 [Car]ioca'
}
],
"voie_post_bac": [
"""Si la DA du bus de ton choix correspondait à une voie post-bac, laquelle serait-elle ?""",
'Question 2': [
'Description 2',
{
42: "Double licence cuisine/arts du cirque option burger",
47: "BTS Exploration de donjon",
48: "Ecole des stars en herbe",
45: "Déscolarisation précoce",
44: "Rattrapage pour excès de kiff",
46: "Double cursus STAPS / Licence dhistoire",
43: "Recherche active dun sugar daddy/dun sugar mommy",
49: "Licence de musicologie"
3: 'Réponse 2 Madagas[car]',
4: 'Réponse 2 Y2[KAR]',
2: 'Réponse 2 Tcherno[bus]',
5: 'Réponse 2 [Kar]tier',
1: 'Réponse 2 [Car]cassonne',
6: 'Réponse 2 O[car]ina',
7: 'Réponse 2 Show[bus]',
8: 'Réponse 2 [Car]ioca'
}
],
"boite": [
"""Tu es seul·e sur une île déserte et devant toi il y a une sombre boîte de taille raisonnable.
Quy a-t-il à lintérieur ?""",
'Question 3': [
'Description 3',
{
42: "Un burgouzz de valouzz",
47: "Un ocarina (pour me téléporter hors de ce bourbier)",
48: "Des paillettes, un micro de karaoké et une enceinte bluetooth",
45: "Un kebab",
44: "Une 86 et un caisson pour taper du pied",
46: "Une épée, un ballon et une tireuse",
43: "Des lunettes de soleil",
49: "Mon instrument de musique"
3: 'Réponse 3 Madagas[car]',
4: 'Réponse 3 Y2[KAR]',
2: 'Réponse 3 Tcherno[bus]',
5: 'Réponse 3 [Kar]tier',
1: 'Réponse 3 [Car]cassonne',
6: 'Réponse 3 O[car]ina',
7: 'Réponse 3 Show[bus]',
8: 'Réponse 3 [Car]ioca'
}
],
"tardif": [
"""Il est 00h, tu as passé la journée à la plage avec tes copains et iels te proposent de prolonger parce
quaprès tout, il ny a plus personne sur la plage à cette heure-ci. Tu nhabites pas loin mais tenchaînes
demain avec une journée similaire avec un autre groupe damis parce que tes trop #busy. Que fais-tu ?""",
'Question 4': [
'Description 4',
{
42: "On veut se déchaîner toute la nuit !!",
47: "Je prends une glace et chill un moment avant daller dormir",
48: "Jenfile mes boogie shoes pour enflammer le dancefloor avec elleux et lancer un concours de slay, le perdant finit la bouteille de rhum",
45: "La fête continuuuuue",
44: "Soirée sangria plage → boîte → lever de soleil sur la plage",
46: "Minuit ? Cest lheure du genepi. On commence les alcools forts !!",
43: "Tenchaînes direct (faut pas les priver de ta présence)",
49: "On continue en mode chill (soirée potins)"
3: 'Réponse 4 Madagas[car]',
4: 'Réponse 4 Y2[KAR]',
2: 'Réponse 4 Tcherno[bus]',
5: 'Réponse 4 [Kar]tier',
1: 'Réponse 4 [Car]cassonne',
6: 'Réponse 4 O[car]ina',
7: 'Réponse 4 Show[bus]',
8: 'Réponse 4 [Car]ioca'
}
],
"cohesion": [
"""Cest la rentrée de Seconde et tu découvres ta classe, tes camarades et ta prof principale!!!
qui vous propose une activité de cohésion. Laquelle est-elle ?""",
'Question 5': [
'Description 5',
{
42: "Un relais cubi en ventriglisse",
47: "Un jeu de rôle",
48: "Organiser la soirée de lannée dans le lycée. Le thème : SLAY (Spotlight, Love, Amaze/All-night, Yeah), paillettes, disco",
45: "La prof de français propose un slam parce qu'elle pense que c'est du rap littéraire qui fera plaisir aux élèves",
44: "Ptit escape game + apéro",
46: "Joute avec des boucliers Gilbert",
43: "Tournage dun clip de confessions nocturnes de Diams",
49: "Je sais pas jai raté mon BAFA"
3: 'Réponse 5 Madagas[car]',
4: 'Réponse 5 Y2[KAR]',
2: 'Réponse 5 Tcherno[bus]',
5: 'Réponse 5 [Kar]tier',
1: 'Réponse 5 [Car]cassonne',
6: 'Réponse 5 O[car]ina',
7: 'Réponse 5 Show[bus]',
8: 'Réponse 5 [Car]ioca'
}
],
"artiste": [
"""Cest lété et la saison des festivals a commencé. Tu regardes la programmation du festival
pas loin de chez toi et tu découvres avec joie la présence dun·e artiste. De qui sagit-il ?""",
'Question 6': [
'Description 6',
{
42: "Moto-Moto (il chantera son fameux tube “je les aime grosses, je les aime bombées”)",
47: "Hatsune Miku",
48: "Rihanna",
45: "Vald",
44: "Qui connaît vraiment les noms des artistes de tech ?",
46: "Perceval",
43: "Fatal bazooka",
49: "Måneskin"
3: 'Réponse 6 Madagas[car]',
4: 'Réponse 6 Y2[KAR]',
2: 'Réponse 6 Tcherno[bus]',
5: 'Réponse 6 [Kar]tier',
1: 'Réponse 6 [Car]cassonne',
6: 'Réponse 6 O[car]ina',
7: 'Réponse 6 Show[bus]',
8: 'Réponse 6 [Car]ioca'
}
],
"annonce_noel": [
"""Cest Noël et tu revois toute ta famille, oncles, tantes, cousin·e·s, grands-parents, la totale.
Dun coup, tu te lèves, tapotes de manière pompeuse sur ton verre avec un de tes couverts.
Quannonces-tu ?""",
'Question 7': [
'Description 7',
{
42: """« Chère famille. Je sais bien que nous avions dit : pas de politique à table.
Je ne peux toutefois me retenir de vous annoncer une grande nouvelle…
jai décidé de quitter la ville pour consacrer ma vie au culte du Roi Julian.
A moi la jungle luxuriante, là où le soleil chaud caresse les palmiers,
où les lémuriens dansent avec frénésie et où chaque repas est une ode au burger sauvage.
Longue vie à Sa Majesté le Roi Julian ! »""",
47: "« Jai perdu »",
48: "« Mes chers parents je pars, jarrête lENS pour devenir DJ slay à Ibiza »",
45: "Jinterromps le repas pour rapper les 6min de bande organisée",
44: "« Digestif ? Pétanque ? Les deux ? »",
46: "« Montjoie St Denis à bas la Macronie »",
43: "« Je suis enceinte » (cest faux jai juste besoin dattention)",
49: """Discours de remerciement :
je lance un powerpoint de 65 slides et sors une feuille A4 blanche (je fais semblant de lire mon discours dessus)"""
3: 'Réponse 7 Madagas[car]',
4: 'Réponse 7 Y2[KAR]',
2: 'Réponse 7 Tcherno[bus]',
5: 'Réponse 7 [Kar]tier',
1: 'Réponse 7 [Car]cassonne',
6: 'Réponse 7 O[car]ina',
7: 'Réponse 7 Show[bus]',
8: 'Réponse 7 [Car]ioca'
}
],
"vacances": [
"""Les vacances sont là et taimerais bien partir quelque part, mais où ?""",
'Question 8': [
'Description 8',
{
42: "A Madagascar, à bord dun bus conduit par des pingouins",
47: "Dans ma chambre",
48: "Rio de Janeiro",
45: "N'importe où tant qu'on peut sortir tous les soirs",
44: "Tu suis les plans du club ski ou de piratens",
46: "Carcassonne",
43: "Coachella",
49: "Dans les montagnes de la république populaire dAuvergne-Rhônes-Alpes pour profiter de la fraîcheur, de la nature et de mes ami·e·s"
3: 'Réponse 8 Madagas[car]',
4: 'Réponse 8 Y2[KAR]',
2: 'Réponse 8 Tcherno[bus]',
5: 'Réponse 8 [Kar]tier',
1: 'Réponse 8 [Car]cassonne',
6: 'Réponse 8 O[car]ina',
7: 'Réponse 8 Show[bus]',
8: 'Réponse 8 [Car]ioca'
}
],
"loisir": [
"""Tas fini ta journée de cours et tu tapprêtes à profiter dune activité/hobby/loisir de ton choix.
Laquelle est-ce ?""",
'Question 9': [
'Description 9',
{
42: "Cueillir des noix de coco",
47: "Essayer de travailler puis chill avec des potes autour dun jeu en buvant du thé",
48: "Repet du nouveau spectacle de mon club, before (potins) puis sortie avec les potes jusquau bout de la night",
45: "Zoner avec les copaings jusquà pas dheure",
44: "Go Kfet pour se faire traquenard jusquà 3h du mat",
46: "Déterminer ce qui est le plus solide entre mon crâne et une ecocup",
43: "Revoir pour la 6e fois gossip girl au fond de ton lit",
49: "Jouer de mon instrument préféré avec les copains/copines pour préparer le prochain concert #solidays"
}
],
"plan": [
"""Tu reçois un message sur la conversation de groupe que tu partages avec tes potes :
vous êtes chaud·e·s pour vous retrouver. Quel plan tattire le plus ?""",
{
42: """Après-midi piscine, puis before arrosé de mojito,
avant daller séclater en pot avec toute la savane et de finir sur un after spécial pina colada""",
47: """(matin) : Ptit jeu de rôle
(repas) : le traditionnel poké-tacos
(juste après le repas) : combat avec des épées en mousse avec les copains!
(16h00) : pause thé
(fin daprès midi) : initiation à la danse rock
(soirée) : découverte dun jeu de société avec des règles obscures
""",
48: "Soirée champagne and chic : spectacle et dîner au moulin rouge puis soirée sur les champs",
45: "Se regrouper pour une soirée, même si il nest encore que 10h",
44: "Ptit poké qui termine en koin koin avec after poker",
46: "Une dégustation de bière, un rugby et toute autre activité joviale",
43: "Un brunch de pour papoter puis friperies",
49: "Soirée raclette !"
3: 'Réponse 9 Madagas[car]',
4: 'Réponse 9 Y2[KAR]',
2: 'Réponse 9 Tcherno[bus]',
5: 'Réponse 9 [Kar]tier',
1: 'Réponse 9 [Car]cassonne',
6: 'Réponse 9 O[car]ina',
7: 'Réponse 9 Show[bus]',
8: 'Réponse 9 [Car]ioca'
}
]
},
'stats': [
{
"question": """Le WEI est structuré par bus, et au sein de chaque bus, par équipes.
Pour toi, être dans une équipe où tout le monde reste sobre (primo-entrants comme encadrants) c'est :""",
"answers": [
(1, "Inenvisageable"),
(2, "À contre cœur"),
(3, "Pourquoi pas"),
(4, "Souhaitable"),
(5, "Nécessaire"),
],
"help_text": "(De toute façon aucun alcool n'est consommé pendant les trajets du bus, ni aller, ni retour.)",
},
{
"question": "Faire partie d'un bus qui n'apporte pas de boisson alcoolisée pour ses membres, pour toi c'est :",
"answers": [
(1, "Inenvisageable"),
(2, "À contre cœur"),
(3, "Pourquoi pas"),
(4, "Souhaitable"),
(5, "Nécessaire"),
],
"help_text": """(Tout les bus apportent de l'alcool cette année, cette question sert à l'organisation pour l'année prochaine.
De plus il y aura de toute façon de l'alcool commun au WEI et aucun alcool n'est consommé pendant les trajets en bus.)""",
},
]
}
IMAGES = {
"vacances": {
49: "/static/wei/img/logo_auvergne_rhone_alpes.jpg",
}
}
NB_WORDS = 5
class OptionalImageRadioSelect(forms.RadioSelect):
def __init__(self, images=None, *args, **kwargs):
self.images = images or {}
super().__init__(*args, **kwargs)
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
option = super().create_option(name, value, label, selected, index, subindex=subindex, attrs=attrs)
img_url = self.images.get(value)
if img_url:
option['label'] = mark_safe(f'{label} <img src="{img_url}" style="height:32px;vertical-align:middle;">')
else:
option['label'] = label
return option
class WEISurveyForm2025(forms.Form):
"""
Survey form for the year 2025.
@@ -250,7 +170,7 @@ class WEISurveyForm2025(forms.Form):
if information.step == 0:
self.fields["words"] = forms.MultipleChoiceField(
label=_(f"Select {NB_WORDS} words that describe the WEI experience you want to have."),
label=_(f"Choose {NB_WORDS} words:"),
choices=[(w, w) for w in WORDS['list']],
widget=forms.CheckboxSelectMultiple(),
required=True,
@@ -258,34 +178,38 @@ class WEISurveyForm2025(forms.Form):
if self.is_valid():
return
all_preferred_words = WORDS['list']
buses = WEISurveyAlgorithm2025.get_buses()
informations = {bus: WEIBusInformation2025(bus) for bus in buses}
scores = sum((list(informations[bus].scores.values()) for bus in buses), [])
if scores:
average_score = sum(scores) / len(scores)
else:
average_score = 0
preferred_words = {
bus: [word for word in WORDS['list'] if informations[bus].scores[word] >= average_score]
for bus in buses
}
all_preferred_words = set()
for bus_words in preferred_words.values():
all_preferred_words.update(bus_words)
all_preferred_words = list(all_preferred_words)
rng.shuffle(all_preferred_words)
self.fields["words"].choices = [(w, w) for w in all_preferred_words]
elif information.step <= len(WORDS['questions']):
else:
questions = list(WORDS['questions'].items())
idx = information.step - 1
if idx < len(questions):
q, (desc, answers) = questions[idx]
if q == 'alcool':
choices = [(i / 2, str(i / 2)) for i in range(11)]
else:
choices = [(k, v) for k, v in answers.items()]
rng.shuffle(choices)
choices = [(k, v) for k, v in answers.items()]
rng.shuffle(choices)
self.fields[q] = forms.ChoiceField(
label=desc,
choices=choices,
widget=OptionalImageRadioSelect(images=IMAGES.get(q, {})),
widget=forms.RadioSelect,
required=True,
)
elif information.step == len(WORDS['questions']) + 1:
for i, v in enumerate(WORDS['stats']):
self.fields[f'stat_{i}'] = forms.ChoiceField(
label=v['question'],
choices=v['answers'],
widget=forms.RadioSelect(),
required=False,
help_text=_(v.get('help_text', ''))
)
def clean_words(self):
data = self.cleaned_data['words']
@@ -302,6 +226,8 @@ class WEIBusInformation2025(WEIBusInformation):
def __init__(self, bus):
self.scores = {}
for word in WORDS['list']:
self.scores[word] = 0
super().__init__(bus)
@@ -309,9 +235,7 @@ class BusInformationForm2025(forms.ModelForm):
class Meta:
model = Bus
fields = ['information_json']
widgets = {
'information_json': forms.HiddenInput(),
}
widgets = {}
def __init__(self, *args, words=None, **kwargs):
super().__init__(*args, **kwargs)
@@ -333,7 +257,7 @@ class BusInformationForm2025(forms.ModelForm):
label=word,
choices=choices,
coerce=int,
initial=initial_scores.get(word, 0) if word in initial_scores else None,
initial=initial_scores.get(word, 0),
required=True,
widget=forms.RadioSelect,
help_text=_("Rate between 0 and 5."),
@@ -361,7 +285,7 @@ class WEISurveyInformation2025(WEISurveyInformation):
step = 0
def __init__(self, registration):
for i in range(1, NB_WORDS + 1):
for i in range(1, 5):
setattr(self, "word" + str(i), None)
for q in WORDS['questions']:
setattr(self, q, None)
@@ -373,7 +297,7 @@ class WEISurveyInformation2025(WEISurveyInformation):
"""
self.step = 0
self.seed = 0
for i in range(1, NB_WORDS + 1):
for i in range(1, 5):
setattr(self, f"word{i}", None)
for q in WORDS['questions']:
setattr(self, q, None)
@@ -412,7 +336,7 @@ class WEISurvey2025(WEISurvey):
setattr(self.information, "word" + str(i), word)
self.information.step += 1
self.save()
elif 1 <= self.information.step <= len(WORDS['questions']):
else:
questions = list(WORDS['questions'].keys())
idx = self.information.step - 1
if idx < len(questions):
@@ -420,13 +344,6 @@ class WEISurvey2025(WEISurvey):
setattr(self.information, q, form.cleaned_data[q])
self.information.step += 1
self.save()
else:
for i, __ in enumerate(WORDS['stats']):
ans = form.cleaned_data.get(f'stat_{i}')
if ans is not None:
setattr(self.information, f'stat_{i}', ans)
self.information.step += 1
self.save()
@classmethod
def get_algorithm_class(cls):
@@ -436,7 +353,7 @@ class WEISurvey2025(WEISurvey):
"""
The survey is complete once the bus is chosen.
"""
return self.information.step > len(WORDS['questions']) + 1
return self.information.step > len(WORDS['questions'])
@classmethod
@lru_cache()
@@ -454,9 +371,8 @@ class WEISurvey2025(WEISurvey):
"""
if not self.is_complete():
raise ValueError("Survey is not ended, can't calculate score")
s = sum(1 for q in WORDS['questions'] if q != 'alcool' and getattr(self.information, q) == bus.pk)
if 'alcool' in WORDS['questions'] and bus.pk in WORDS['questions']['alcool'][1] and hasattr(self.information, 'alcool'):
s -= abs(float(self.information.alcool) - float(WORDS['questions']['alcool'][1][bus.pk]))
# Score is the given score by the bus subtracted to the mid-score of the buses.
s = sum(1 for q in WORDS['questions'] if getattr(self.information, q) == bus.pk)
return s
@lru_cache()
@@ -480,7 +396,7 @@ class WEISurvey2025(WEISurvey):
@lru_cache()
def ordered_buses(self):
"""
Order the buses by the score_questions of the survey.
Force the choice of bus to be in the 3 preferred buses according to the words
"""
values = list(self.scores_per_bus().items())
values.sort(key=lambda item: -item[1][0])
@@ -597,7 +513,7 @@ class WEISurveyAlgorithm2025(WEISurveyAlgorithm):
for survey2 in surveys:
if not survey2.information.valid or survey2.information.get_selected_bus() != bus:
continue
score2 = survey2.score_words(bus)
score2 = survey2.score_questions(bus)
if current_scores[1] <= score2: # Ignore better students
continue
if least_preferred_survey is None or score2 < least_score:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -22,8 +22,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endif %}
<a class="btn btn-primary btn-sm my-1" href="{% url 'wei:update_bus' pk=object.pk %}"
data-turbolinks="false">{% trans "Edit" %}</a>
<a class="btn btn-primary btn-sm my-1" href="{% url 'wei:update_bus_info' pk=object.pk %}"
data-turbolinks="false">{% trans "Edit information for survey" %}</a>
<a class="btn btn-primary btn-sm my-1" href="{% url 'wei:update_bus_info' pk=object.pk %}"
data-turbolinks="false">{% trans "Edit information" %}</a>
<a class="btn btn-primary btn-sm my-1" href="{% url 'wei:add_team' pk=object.pk %}"
data-turbolinks="false">{% trans "Add team" %}</a>
</div>

View File

@@ -31,24 +31,15 @@ SPDX-License-Identifier: GPL-3.0-or-later
<a class="btn btn-success" href="{% url "wei:wei_register_1A_myself" wei_pk=club.pk %}" data-turbolinks="false">
{% trans "Register to the WEI! 1A" %}
</a>
{% else %}
<a class="btn btn-success" href="{% url "wei:wei_register_2A_myself" wei_pk=club.pk %}" data-turbolinks="false">
{% trans "Register to the WEI! 2A+" %}
</a>
{% endif %}
<a class="btn btn-success" href="{% url "wei:wei_register_2A_myself" wei_pk=club.pk %}" data-turbolinks="false">
{% trans "Register to the WEI! 2A+" %}</a>
{% else %}
{% if registration.validated %}
<a class="btn btn-warning" href="{% url "wei:wei_update_registration" pk=my_registration.pk %}"
data-turbolinks="false">
{% trans "Update my registration" %}
</a>
{% endif %}
{% if my_registration.first_year %}
{% if not survey_complete %}
<a class="btn btn-warning" href="{% url "wei:wei_survey" pk=my_registration.pk %}" data-turbolinks="false">
{% trans "Continue survey" %}
</a>
{% endif %}
{% if not not_first_year %}
<a class="btn btn-warning" href="{% url "wei:wei_survey" pk=my_registration.pk %}?reset=true" data-turbolinks="false">
{% trans "Restart survey" %}
</a>

View File

@@ -53,11 +53,9 @@ class TestWEIAlgorithm(TestCase):
birth_date='2000-01-01',
)
information = WEISurveyInformation2025(registration)
for j in range(1, 1 + NB_WORDS):
for j in range(1, 21):
setattr(information, f'word{j}', random.choice(WORDS['list']))
for q in WORDS['questions']:
setattr(information, q, random.choice(list(WORDS['questions'][q][1].keys())))
information.step = len(WORDS['questions']) + 2
information.step = 20
information.save(registration)
registration.save()
@@ -89,7 +87,7 @@ class TestWEIAlgorithm(TestCase):
setattr(information, f'word{j}', random.choice(WORDS['list']))
for q in WORDS['questions']:
setattr(information, q, random.choice(list(WORDS['questions'][q][1].keys())))
information.step = len(WORDS['questions']) + 2
information.step = len(WORDS['questions']) + 1
information.save(registration)
registration.save()
survey = WEISurvey2025(registration)
@@ -107,6 +105,8 @@ class TestWEIAlgorithm(TestCase):
survey = WEISurvey2025(r)
chosen_bus = survey.information.get_selected_bus()
buses = survey.ordered_buses()
'''print(buses)
print(chosen_bus)'''
self.assertIn(chosen_bus, [x[0] for x in buses])
score_questions, score_words = next(scores for bus, scores in buses if bus == chosen_bus)
max_score_questions = max(buses[i][1][0] for i in range(len(buses)))

View File

@@ -166,7 +166,6 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, D
my_registration = WEIRegistration.objects.filter(wei=club, user=self.request.user)
if my_registration.exists():
my_registration = my_registration.get()
context["survey_complete"] = CurrentSurvey(my_registration).is_complete()
else:
my_registration = None
context["my_registration"] = my_registration
@@ -214,8 +213,6 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, D
context["not_first_year"] = WEIMembership.objects.filter(user=self.request.user).exists()
context["registration_validated"] = WEIMembership.objects.filter(registration=my_registration).exists() if my_registration else False
qs = WEIMembership.objects.filter(club=club, registration__first_year=True, bus__isnull=True)
context["can_validate_1a"] = PermissionBackend.check_perm(
self.request, "wei.change_weimembership_bus", qs.first()) if qs.exists() else False
@@ -1234,6 +1231,7 @@ class WEIUpdateMembershipView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateVi
return form
def get_success_url(self):
print("get_success_url")
return reverse_lazy("wei:wei_detail", kwargs={"pk": self.object.registration.wei.pk})

View File

@@ -3152,10 +3152,8 @@ msgid "Note transaction"
msgstr "Transaction Note"
#: apps/wei/models.py:217
#, fuzzy
#| msgid "Credit type"
msgid "deposit type"
msgstr "Type de rechargement"
msgstr "type de caution"
#: apps/wei/models.py:221 apps/wei/templates/wei/weimembership_form.html:64
msgid "birth date"
@@ -4095,14 +4093,6 @@ msgstr "La note est indisponible pour le moment"
msgid "Thank you for your understanding -- The Respos Info of BDE"
msgstr "Merci de votre compréhension -- Les Respos Info du BDE"
#: note_kfet/templates/base_search.html:15
msgid "Search by attribute such as name..."
msgstr "Chercher par un attribut tel que le nom..."
#: note_kfet/templates/base_search.html:23
msgid "There is no results."
msgstr "Il n'y a pas de résultat."
#: note_kfet/templates/cas/logged.html:8
msgid ""
"<h3>Log In Successful</h3>You have successfully logged into the Central "