mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-09-06 11:03:53 +02:00
Compare commits
3 Commits
main
...
2dd1a6429c
Author | SHA1 | Date | |
---|---|---|---|
|
2dd1a6429c | ||
|
dde1baa25c | ||
|
7a7ee47e0b |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -48,7 +48,6 @@ backups/
|
||||
env/
|
||||
venv/
|
||||
db.sqlite3
|
||||
shell.nix
|
||||
|
||||
# ansibles customs host
|
||||
ansible/host_vars/*.yaml
|
||||
|
@@ -10,7 +10,6 @@ from django.contrib.auth.forms import AuthenticationForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import transaction
|
||||
from django.forms import CheckboxSelectMultiple
|
||||
from phonenumber_field.formfields import PhoneNumberField
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from note.models import NoteSpecial, Alias
|
||||
@@ -46,11 +45,6 @@ class ProfileForm(forms.ModelForm):
|
||||
A form for the extras field provided by the :model:`member.Profile` model.
|
||||
"""
|
||||
# Remove widget=forms.HiddenInput() if you want to use report frequency.
|
||||
phone_number = PhoneNumberField(
|
||||
widget=forms.TextInput(attrs={"type": "tel", "class": "form-control"}),
|
||||
required=False
|
||||
)
|
||||
|
||||
report_frequency = forms.IntegerField(required=False, initial=0, label=_("Report frequency"))
|
||||
|
||||
last_report = forms.DateTimeField(required=False, disabled=True, label=_("Last report date"))
|
||||
@@ -78,12 +72,7 @@ class ProfileForm(forms.ModelForm):
|
||||
if not self.instance.section or (("department" in self.changed_data
|
||||
or "promotion" in self.changed_data) and "section" not in self.changed_data):
|
||||
self.instance.section = self.instance.section_generated
|
||||
instance = super().save(commit=False)
|
||||
if instance.phone_number:
|
||||
instance.phone_number = instance.phone_number.as_e164
|
||||
if commit:
|
||||
instance.save()
|
||||
return instance
|
||||
return super().save(commit)
|
||||
|
||||
class Meta:
|
||||
model = Profile
|
||||
|
@@ -11,8 +11,9 @@
|
||||
<dt class="col-xl-6">{% trans 'family'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">
|
||||
{% if families %}
|
||||
test
|
||||
{% for fam in families %}
|
||||
<a href="{% url 'family:family_detail' fam.pk %}">{{ fam.name }}</a>{% if not forloop.last %}, {% endif %}
|
||||
<a href="{% url 'family:family_detail' fam.pk %}">asfafs{{ fam.name }}</a>{% if not forloop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<span class="text-muted">Aucune</span>
|
||||
|
@@ -10,7 +10,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{{ title }}
|
||||
</h3>
|
||||
<div class="card-body">
|
||||
<form method="post" id="profile-form">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form | crispy }}
|
||||
{{ profile_form | crispy }}
|
||||
@@ -21,45 +21,3 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<!-- intl-tel-input CSS/JS -->
|
||||
<script>
|
||||
(() => {
|
||||
const input = document.querySelector("input[name='phone_number']");
|
||||
const form = document.querySelector("#profile-form");
|
||||
|
||||
if (!input || !form) {
|
||||
console.error("Input phone_number ou form introuvable.");
|
||||
}
|
||||
|
||||
const iti = window.intlTelInput(input, {
|
||||
initialCountry: "auto",
|
||||
nationalMode: false,
|
||||
autoPlaceholder: "off",
|
||||
geoIpLookup: callback => {
|
||||
fetch("https://ipapi.co/json")
|
||||
.then(res => res.json())
|
||||
.then(data => callback(data.country_code))
|
||||
.catch(() => callback("fr"));
|
||||
},
|
||||
loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@25.5.2/build/js/utils.js"),
|
||||
});
|
||||
|
||||
form.addEventListener("submit", function(e){
|
||||
if (!input.value.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const number = iti.getNumber(intlTelInput.utils.numberFormat.E164);
|
||||
if (number) {
|
||||
input.value = number;
|
||||
form.submit();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
@@ -17,7 +17,7 @@ from ...models import WEIMembership, Bus
|
||||
|
||||
WORDS = {
|
||||
'list': [
|
||||
'Fiesta', 'Graillance', 'Move it move it', 'Calme', 'Nerd et geek', 'Jeux de rôles et danse rock',
|
||||
'Fiesta', 'Graillance', 'Move it move it', 'Calme', 'Nert 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',
|
||||
@@ -57,7 +57,7 @@ WORDS = {
|
||||
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",
|
||||
45: "",
|
||||
44: "Une 86 et un caisson pour taper du pied",
|
||||
46: "Une épée, un ballon et une tireuse",
|
||||
43: "Des lunettes de soleil",
|
||||
@@ -176,33 +176,7 @@ WORDS = {
|
||||
49: "Soirée raclette !"
|
||||
}
|
||||
]
|
||||
},
|
||||
'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 = {
|
||||
@@ -261,7 +235,7 @@ class WEISurveyForm2025(forms.Form):
|
||||
all_preferred_words = WORDS['list']
|
||||
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):
|
||||
@@ -277,15 +251,6 @@ class WEISurveyForm2025(forms.Form):
|
||||
widget=OptionalImageRadioSelect(images=IMAGES.get(q, {})),
|
||||
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']
|
||||
@@ -412,7 +377,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 +385,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 +394,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()
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
@@ -11,7 +11,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{{ title }}
|
||||
</h3>
|
||||
<div class="card-body">
|
||||
<form id="registration-form" method="post">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
{{ membership_form|crispy }}
|
||||
@@ -22,46 +22,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<!-- intl-tel-input CSS/JS -->
|
||||
<script>
|
||||
(() => {
|
||||
const input = document.querySelector("input[name='emergency_contact_phone']");
|
||||
const form = document.querySelector("#registration-form");
|
||||
|
||||
if (!input || !form) {
|
||||
console.error("Input phone_number ou form introuvable.");
|
||||
}
|
||||
|
||||
const iti = window.intlTelInput(input, {
|
||||
initialCountry: "auto",
|
||||
nationalMode: false,
|
||||
autoPlaceholder: "off",
|
||||
geoIpLookup: callback => {
|
||||
fetch("https://ipapi.co/json")
|
||||
.then(res => res.json())
|
||||
.then(data => callback(data.country_code))
|
||||
.catch(() => callback("fr"));
|
||||
},
|
||||
loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@25.5.2/build/js/utils.js"),
|
||||
});
|
||||
|
||||
form.addEventListener("submit", function(e){
|
||||
if (!input.value.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const number = iti.getNumber(intlTelInput.utils.numberFormat.E164);
|
||||
if (number) {
|
||||
input.value = number;
|
||||
form.submit();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
{% if not object.membership %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
|
@@ -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)
|
||||
|
@@ -770,7 +770,7 @@ msgstr "Créer une famille ou un défi"
|
||||
|
||||
#: apps/family/templates/family/manage.html:96
|
||||
msgid "Add a family"
|
||||
msgstr "Fonder une famille"
|
||||
msgstr "Ajouter une famille"
|
||||
|
||||
#: apps/family/templates/family/manage.html:101
|
||||
msgid "Add a challenge"
|
||||
|
@@ -306,8 +306,8 @@ PIC_WIDTH = 200
|
||||
PIC_RATIO = 1
|
||||
|
||||
# Custom phone number format
|
||||
PHONENUMBER_DB_FORMAT = 'E164'
|
||||
PHONENUMBER_DEFAULT_REGION = None
|
||||
PHONENUMBER_DB_FORMAT = 'NATIONAL'
|
||||
PHONENUMBER_DEFAULT_REGION = 'FR'
|
||||
|
||||
# We add custom information to CAS, in order to give a normalized name to other services
|
||||
CAS_AUTH_CLASS = 'member.auth.CustomAuthUser'
|
||||
|
@@ -30,8 +30,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
<link rel="stylesheet" href="{% static "font-awesome/css/font-awesome.min.css" %}">
|
||||
<link rel="stylesheet" href="{% static "css/custom.css" %}">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/intl-tel-input@25.5.2/build/css/intlTelInput.css">
|
||||
|
||||
{# JQuery, Bootstrap and Turbolinks JavaScript #}
|
||||
<script src="{% static "jquery/jquery.min.js" %}"></script>
|
||||
<script src="{% static "popper.js/umd/popper.min.js" %}"></script>
|
||||
@@ -43,8 +41,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{# Translation in javascript files #}
|
||||
<script src="{% static "js/jsi18n/"|add:LANGUAGE_CODE|add:".js" %}"></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/intl-tel-input@25.5.2/build/js/intlTelInput.min.js"></script>
|
||||
|
||||
{# If extra ressources are needed for a form, load here #}
|
||||
{% if form.media %}
|
||||
{{ form.media }}
|
||||
|
@@ -19,7 +19,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
|
||||
<form method="post" id="profile_form">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
{{ profile_form|crispy }}
|
||||
@@ -31,45 +31,3 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<!-- intl-tel-input CSS/JS -->
|
||||
<script>
|
||||
(() => {
|
||||
const input = document.querySelector("input[name='phone_number']");
|
||||
const form = document.querySelector("#profile_form");
|
||||
|
||||
if (!input || !form) {
|
||||
console.error("Input phone_number ou form introuvable.");
|
||||
}
|
||||
|
||||
const iti = window.intlTelInput(input, {
|
||||
initialCountry: "auto",
|
||||
nationalMode: false,
|
||||
autoPlaceholder: "off",
|
||||
geoIpLookup: callback => {
|
||||
fetch("https://ipapi.co/json")
|
||||
.then(res => res.json())
|
||||
.then(data => callback(data.country_code))
|
||||
.catch(() => callback("fr"));
|
||||
},
|
||||
loadUtils: () => import("https://cdn.jsdelivr.net/npm/intl-tel-input@25.5.2/build/js/utils.js"),
|
||||
});
|
||||
|
||||
form.addEventListener("submit", function(e){
|
||||
if (!input.value.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const number = iti.getNumber(intlTelInput.utils.numberFormat.E164);
|
||||
if (number) {
|
||||
input.value = number;
|
||||
form.submit();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
34
shell-static.nix
Executable file
34
shell-static.nix
Executable file
@@ -0,0 +1,34 @@
|
||||
# This is a workaround meant for use with the nix package manager. If you don't know what it is or don't use it, please ignore this file.
|
||||
#
|
||||
# The nk20 javascript static location are hardcoded for imperative system.
|
||||
# This make ./manage.py collectstatic hard to use with nixos.
|
||||
#
|
||||
# A workaround is to enter a FHSUserEnv with the static placed under /share/javascript/<static>.
|
||||
# This emulate a debian like system and enable collecting static normally with ./manage.py collectstatics.
|
||||
# The regular shell.nix should be enough for other configurations.
|
||||
#
|
||||
# Warning, you are still supposed to use pip package with a venv !
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
(pkgs.buildFHSUserEnv {
|
||||
name = "pipzone";
|
||||
targetPkgs = pkgs: (with pkgs;
|
||||
let
|
||||
fhs-static = stdenv.mkDerivation {
|
||||
name = "fhs-static";
|
||||
buildCommand = ''
|
||||
mkdir -p $out/share/javascript/bootstrap4
|
||||
mkdir -p $out/share/javascript/jquery
|
||||
ln -s ${python39Packages.xstatic-bootstrap}/lib/python3.9/site-packages/xstatic/pkg/bootstrap/data/* $out/share/javascript/bootstrap4
|
||||
ln -s ${python39Packages.xstatic-jquery}/lib/python3.9/site-packages/xstatic/pkg/jquery/data/* $out/share/javascript/jquery
|
||||
'';
|
||||
};
|
||||
in [
|
||||
fhs-static
|
||||
python39
|
||||
gettext
|
||||
python39Packages.pip
|
||||
python39Packages.virtualenv
|
||||
python39Packages.setuptools
|
||||
]);
|
||||
runScript = "bash";
|
||||
}).env
|
23
shell.nix
Executable file
23
shell.nix
Executable file
@@ -0,0 +1,23 @@
|
||||
# This is meant for use with the nix package manager. If you don't know what it is or don't use it, please ignore this file.
|
||||
#
|
||||
# This shell.nix contains all dependencies require to create a venv and pip install -r requirements.txt.
|
||||
#
|
||||
# Please check shell-static.nix for running ./manage.py collectstatics.
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
python39
|
||||
python39Packages.pip
|
||||
python39Packages.setuptools
|
||||
gettext
|
||||
|
||||
];
|
||||
shellHook = ''
|
||||
# Tells pip to put packages into $PIP_PREFIX instead of the usual locations.
|
||||
# See https://pip.pypa.io/en/stable/user_guide/#environment-variables.
|
||||
export PIP_PREFIX=$(pwd)/_build/pip_packages
|
||||
export PYTHONPATH="$PIP_PREFIX/${pkgs.python39.sitePackages}:$PYTHONPATH"
|
||||
export PATH="$PIP_PREFIX/bin:$PATH"
|
||||
unset SOURCE_DATE_EPOCH
|
||||
'';
|
||||
}
|
Reference in New Issue
Block a user