Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • mediatek/site-interludes
  • aeltheos/site-kwei
  • mediatek/site-kwei
3 results
Show changes
Commits on Source (54)
Showing
with 321 additions and 109 deletions
# Change Log
## Version ??? - Coming soon
## Version 2.0.0-beta - Coming soon
- Added a form that allows admins to send emails to all users
- Added a form for users to submit activities
- Added a changeable caption for the planning
- Added fixes/improvement from 48h des jeux:
- bug fixed in activity submission form
- new validator that checks the number of slots for each activity in the planning
- fixed room display on activity page
- fixed planning info displayed on activity even when planning hidden
- added boolean field to show host email on activity
- added boolean field to separate showing slot on planning and next to activity
## Version 1.2.8 - 2021-05-06
......
......@@ -6,7 +6,8 @@ SECRET := interludes/secret.py
.PHONY: help
help: ## Show this help
@egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
@echo "make: list of useful targets :"
@egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}'
.PHONY: install
install: ## Install requirements
......
......@@ -2,6 +2,8 @@
Ce répo contient le sites des interludes. Ce site est en ligne à [https://interludes.ens.fr](https://interludes.ens.fr).
Ce répo est une copie du répo initial sur le [git interne de l'ENS Ulm](https://git.eleves.ens.fr/dlesbre/site-interludes).
Ce répo est diffusé sous une [license MIT](https://choosealicense.com/licenses/mit/).
**Contenu:**
......@@ -17,7 +19,7 @@ Ce répo est diffusé sous une [license MIT](https://choosealicense.com/licenses
Pour installer toutes les dépendances et lancer le serveur :
git clone https://git.eleves.ens.fr/dlesbre/site-interludes.git &&
git clone https://gitlab.crans.org/mediatek/site-interludes.git &&
cd site-interlude &&
python3 -m venv venv &&
source venv/bin/activate &&
......@@ -110,7 +112,7 @@ Le site se gère depuis deux pages d'administration:
## En production
Le serveur a besoin d'être configuré pour HTTPS et d'être configuré pour livrer directement les fichiers situés des `/static/`.
Le serveur a besoin d'être configuré pour HTTPS et d'être configuré pour livrer directement les fichiers situés dans `/static/` et `/media/`.
1. Installer les dépendances `make install`
......@@ -136,5 +138,10 @@ A.K.A. la liste des trucs utiles que j'ai pas eu le temps d'ajouter
## Liens divers
- [Le site des interludes 2021](https://interludes.ens.fr)
- [Le répo initial](https://git.eleves.ens.fr/dlesbre/site-interludes) sur le gitlab de l'ENS Ulm
- [Le github de l'algorithme de répartition](https://github.com/Imakoala/InterludesMatchings)
- [Le wiki de Paris-Saclay](https://wiki.crans.org/VieBdl/InterLudes) qui recensent les visuels, sites webs et photos des interludes passées.
- [Le wiki de Paris-Saclay](https://wiki.crans.org/VieBdl/InterLudes) qui recense les visuels, sites webs et photos des interludes passées.
- [Le gitlab du site des 48h des jeux](https://git.eleves.ens.fr/dlesbre/48h-des-jeux) un événement très similaire intra-ENS Ulm, c'est fork de ce répo.
- [Le site des 48h des jeux](https://48hdesjeux.cof.ens.fr/)
- [Le site du club jeu d'Ulm](https://jeux.cof.ens.fr/)
- [le site des interludes 2023](https://interludes.crans.org/)
# Generated by Django 3.2.7 on 2021-09-13 17:01
# Generated by Django 3.2.7 on 2021-10-05 18:45
from django.db import migrations, models
import django.utils.timezone
......
{% extends 'base.html' %}
{% block "content" %}
<h2>Mot de passe oublié ?</h2>
<p>Saissisez votre adresse email ci-dessous pour recevoir un lien de réinitialisation du mot de passe.</p>
<h2>Mot de passe oublié ?</h2>
<p>Saissisez votre adresse email ci-dessous pour recevoir un lien de réinitialisation du mot de passe.</p>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<div class="flex">
<input type="submit" value="Valider">
<input type="submit" value="Valider">
<a class="button" href="{% url 'accounts:login' %}">Annuler</a>
</div>
</form>
</form>
{% endblock %}
......@@ -6,12 +6,12 @@
<h2>Saissisez un nouveau mot de passe</h2>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<div class="flex">
<input type="submit" value="Changer mon mot de passe">
<a class="button" href="{% url 'accounts:login' %}">Annuler</a>
</div>
{% csrf_token %}
{{ form.as_p }}
<div class="flex">
<input type="submit" value="Changer mon mot de passe">
<a class="button" href="{% url 'accounts:login' %}">Annuler</a>
</div>
</form>
{% else %}
......@@ -19,8 +19,8 @@
<h2>Lien invalide</h2>
<p>Le lien de réinitialisation est invalide, peut-être a-t-il déjà été utilisé.
Veuillez <a href="{% url 'accounts:password_reset' %}">demander un nouveau lien</a>.
Veuillez <a href="{% url 'accounts:password_reset' %}">demander un nouveau lien</a>.
</p>
{% endif %}
{% endblock %}
\ No newline at end of file
{% endblock %}
......@@ -31,10 +31,12 @@
<li>Fermeture : {{ settings.inscriptions_end|default:"non fixée" }}</li>
</ul>
</li>
<li>Les emails des orgas sont {% if settings.show_host_emails %}affichés sur la page activité{% else %}masqués{% endif %}.</li>
<li>Le planning {% if settings.display_planning %}est affiché{% else %}n'est pas affiché{% endif %}.</li>
<li>La répartition des activités {% if settings.activities_allocated %}est effectuée et affichée{% else %}n'est pas faite/affichée{% endif %}.</li>
<li>{% if settings.global_message %}Un message global est affiché{% else %}Aucun message global{% endif %}.</li>
<li>Le lien du serveur discord {% if settings.discord_link %}est affiché{% else %}n'est pas affiché{% endif %}.</li>
<li>L'envoi d'email en masse est {% if settings.allow_mass_email %}activé{% else %}désactivé{% endif %}</li>
</ul>
<h2>Métriques</h2>
......@@ -68,8 +70,12 @@
<div class="qty">Dormeurs</div>
<div class="nb_small">{{ metrics.sleeps }}</div>
</div>
<div class="stat">
<div class="qty">Payé⋅es</div>
<div class="nb_small">{{ metrics.paid }}</div>
</div>
</div>
<!--
<div class="flex wrap lines">
<div class="stat">
<div class="qty">Repas</div>
......@@ -99,8 +105,12 @@
<div class="qty">D midi</div>
<div class="nb_small">{{ metrics.meal6 }}</div>
</div>
<div class="stat">
<div class="qty">D soir</div>
<div class="nb_small">{{ metrics.meal7 }}</div>
</div>
</div>
-->
<div class="flex wrap lines">
<div class="stat">
<div class="qty">Activités</div>
......@@ -167,6 +177,10 @@
<h2>Prévisualisation du planning</h2>
<ul class="messagelist">
{{ planning_validation|safe }}
</ul>
<p>Vous pouver uploader une version PDF dans le réglages (depuis django-admin)</p>
{% include "_planning.html" %}
......
......@@ -13,6 +13,7 @@ from home import models
from home.views import get_planning_context
from site_settings.models import Colors, SiteSettings
from shared.views import CSVWriteView, SuperuserRequiredMixin
from interludes import settings as site_settings
from admin_pages.forms import Recipients, SendEmailForm
......@@ -42,6 +43,7 @@ class AdminView(SuperuserRequiredMixin, TemplateView):
non_registered = EmailUser.objects.filter(is_active=True).count() - participants
# mugs = registered.filter(mug=True).count()
sleeps = registered.filter(sleeps=True).count()
paid = registered.filter(paid=True).count()
meal1 = registered.filter(meal_friday_evening=True).count()
meal2 = registered.filter(meal_saturday_morning=True).count()
......@@ -49,6 +51,7 @@ class AdminView(SuperuserRequiredMixin, TemplateView):
meal4 = registered.filter(meal_saturday_evening=True).count()
meal5 = registered.filter(meal_sunday_morning=True).count()
meal6 = registered.filter(meal_sunday_midday=True).count()
meal7 = registered.filter(meal_sunday_evening=True).count()
meals = meal1 + meal2 + meal3 + meal4 + meal5 + meal6
activites = acts.count()
......@@ -169,6 +172,24 @@ class AdminView(SuperuserRequiredMixin, TemplateView):
)
return '<li class="success">Aucun inscrit plusieurs fois à une même activité</li>'
def planning_validation(self):
"""Vérifie que toutes les activités ont le bon nombre de créneaux
dans le planning"""
errors = ""
activities = models.ActivityModel.objects.all()
for activity in activities:
nb_wanted = activity.desired_slot_nb
nb_got = activity.slots.count()
if nb_wanted != nb_got:
errors += '<br> &bullet;&ensp; "{}" souhaite {} crénaux mais en a {}.'.format(
activity.title, nb_wanted, nb_got
)
if errors:
return '<li class="error">Certaines activités ont trop/pas assez de crénaux :{}</li>'.format(
errors
)
return '<li class="success">Toutes les activités ont le bon nombre de crénaux</li>'
def validate_activity_allocation(self):
settings = SiteSettings.load()
validations = '<ul class="messagelist">'
......@@ -207,7 +228,8 @@ class AdminView(SuperuserRequiredMixin, TemplateView):
"validations": validations,
"user_email_nb": user_email_nb,
"orga_email_nb": orga_email_nb,
"validation_errors": '<li class="error">' in validations
"validation_errors": '<li class="error">' in validations,
"planning_validation": self.planning_validation(),
}
def get_context_data(self, *args, **kwargs):
......@@ -230,7 +252,7 @@ class ExportActivities(SuperuserRequiredMixin, CSVWriteView):
# The key is "host_id" but listed as "host" in auto-found field names
# which leads to an error...
'id', 'display', 'title', 'act_type', 'game_type', 'description',
'desc_as_html', 'host_id', 'host_name', 'host_email', 'host_info',
'desc_as_html', 'host_id', 'host_name', 'host_email', 'host_info', 'show_email',
'must_subscribe', 'communicate_participants', 'max_participants',
'min_participants', 'duration', 'desired_slot_nb',
'available_friday_evening', 'available_friday_night',
......@@ -244,7 +266,7 @@ class ExportSlots(SuperuserRequiredMixin, CSVWriteView):
filename = "créneaux_interludes"
headers = [
"Titre", "Début", "Salle",
"Ouverte aux inscriptions", "Affichée sur le planning",
"Ouverte aux inscriptions", "Affiché sur le planning", "Affiché sur l'activité",
"Couleur", "Durée", "Durée activité",
]
......@@ -254,8 +276,8 @@ class ExportSlots(SuperuserRequiredMixin, CSVWriteView):
for slot in slots:
rows.append([
str(slot), slot.start, slot.room,
slot.subscribing_open, slot.on_planning,
Colors(slot.color).name, slot.duration, slot.activity.duration ,
slot.subscribing_open, slot.on_planning, slot.on_activity,
Colors(slot.color).name, slot.duration, slot.activity.duration,
])
return rows
......@@ -264,7 +286,8 @@ class ExportParticipants(SuperuserRequiredMixin, CSVWriteView):
headers = [
"id", "mail", "prénom", "nom", "ENS", "Dors sur place", #"Tasse",
"Repas vendredi", "Repas S matin", "Repas S midi", "Repas S soir",
"Repas D matin", "Repas D soir"
"Repas D matin", "Repas D midi", "Reaps D soir", "Payé⋅e", "Prix",
"Montant payé"
]
def get_rows(self):
profiles = models.ParticipantModel.objects.filter(
......@@ -286,6 +309,10 @@ class ExportParticipants(SuperuserRequiredMixin, CSVWriteView):
profile.meal_saturday_evening,
profile.meal_sunday_morning,
profile.meal_sunday_midday,
profile.meal_sunday_evening,
profile.paid,
profile.cost,
profile.amount_paid
])
return rows
......@@ -333,7 +360,7 @@ class SendUserEmail(SendEmailBase):
def get_emails(self):
"""genere les mails a envoyer"""
participants = models.ParticipantModel.objects.filter(
is_registered=True, participant__user__is_active=True
is_registered=True, user__is_active=True
)
emails = []
settings = SiteSettings.load()
......@@ -346,7 +373,7 @@ class SendUserEmail(SendEmailBase):
"my_choices": my_choices.filter(accepted=True),
})
emails.append((
settings.USER_EMAIL_SUBJECT_PREFIX + "Vos activités", # subject
site_settings.USER_EMAIL_SUBJECT_PREFIX + "Vos activités", # subject
message,
self.from_address, # From:
[participant.user.email], # To:
......@@ -367,7 +394,7 @@ class SendUserEmail(SendEmailBase):
"Emails de répartition envoyés aux participants",
"Les participants ont reçu un mail leur communiquant la répartition des activités\n"
"Nombre total de mail envoyés: {}\n\n"
"{}".format(nb_sent, settings.EMAIL_SIGNATURE)
"{}".format(nb_sent, site_settings.EMAIL_SIGNATURE)
)
messages.success(self.request, "{} mails envoyés aux utilisateurs".format(nb_sent))
......@@ -390,7 +417,7 @@ class SendOrgaEmail(SendEmailBase):
"slots": slots,
})
emails.append((
settings.USER_EMAIL_SUBJECT_PREFIX +
site_settings.USER_EMAIL_SUBJECT_PREFIX +
"Liste d'inscrits à votre activité {}".format(activity.title), # subject
message,
self.from_address, # From:
......@@ -412,7 +439,7 @@ class SendOrgaEmail(SendEmailBase):
"Listes d'inscrits envoyés aux orgas",
"Les mails communiquant aux organisateurs leur listes d'inscrit ont été envoyés\n"
"Nombre total de mail envoyés: {}\n\n"
"{}".format(nb_sent, settings.EMAIL_SIGNATURE)
"{}".format(nb_sent, site_settings.EMAIL_SIGNATURE)
)
messages.success(self.request, "{} mails envoyés aux orgas".format(nb_sent))
......@@ -469,7 +496,7 @@ class NewEmail(SuperuserRequiredMixin, FormView):
"{}\n\n"
"{}".format(
Recipients(dest).label, nb_sent, subject, text,
settings.EMAIL_SIGNATURE
site_settings.EMAIL_SIGNATURE
)
)
messages.success(self.request, "{} mails envoyés".format(nb_sent))
......
......@@ -19,7 +19,7 @@ class ActivityModelAdmin(ExportCsvMixin, admin.ModelAdmin):
list_editable = ("display",)
fields = (
"title", "display",
("host_name", "host_email"),
("host_name", "host_email"), "show_email",
"host_info",
"act_type", "game_type",
"description", "desc_as_html",
......@@ -46,7 +46,7 @@ class ActivityModelAdmin(ExportCsvMixin, admin.ModelAdmin):
# The key is "host_id" but listed as "host" in auto-found field names
# which leads to an error...
'id', 'display', 'title', 'act_type', 'game_type', 'description',
'desc_as_html', 'host_id', 'host_name', 'host_email', 'host_info',
'desc_as_html', 'host_id', 'host_name', 'host_email', 'show_email', 'host_info',
'must_subscribe', 'communicate_participants', 'max_participants',
'min_participants', 'duration', 'desired_slot_nb',
'available_friday_evening', 'available_friday_night',
......@@ -61,9 +61,14 @@ class ActivityModelAdmin(ExportCsvMixin, admin.ModelAdmin):
class SlotModelAdmin(ExportCsvMixin, admin.ModelAdmin):
"""option d'affichage des créneaux dans la vue d'admin"""
filename = "export_slots.csv"
list_display = ("__str__", "start", "room", "subscribing_open", "on_planning",)
list_filter = ("subscribing_open", "on_planning", "activity__display",)
list_editable = ("subscribing_open", "on_planning",)
csv_export_fields = (
"activity_id", "title",
"start", "duration", "room",
"on_planning", "on_activity", "color",
)
list_display = ("__str__", "start", "room", "subscribing_open", "on_planning", "on_activity",)
list_filter = ("subscribing_open", "on_planning", "on_activity", "activity__display",)
list_editable = ("subscribing_open", "on_planning", "on_activity",)
ordering = ("activity", "title", "start",)
......@@ -71,11 +76,19 @@ class SlotModelAdmin(ExportCsvMixin, admin.ModelAdmin):
class ParticipantModelAdmin(ExportCsvMixin, admin.ModelAdmin):
"""option d'affichage des participant dans la vue django admin"""
filename = "export_participants.csv"
list_display = ("user", "school", "is_registered")
fields = (
"user", "school", "is_registered",
("meal_friday_evening", "meal_saturday_morning", "meal_saturday_midday",
"meal_saturday_evening", "meal_sunday_morning", "meal_sunday_midday",
"meal_sunday_evening"),
"sleeps", "nb_murder", "paid", "amount_paid", "comment"
)
list_display = ("user", "school", "is_registered", "comment")
list_filter = (
"school", "is_registered", "sleeps",
"meal_friday_evening", "meal_saturday_morning", "meal_saturday_midday",
"meal_saturday_evening", "meal_sunday_morning", "meal_sunday_midday",
"meal_sunday_evening", "nb_murder", "paid"
)
ordering = ("user",)
list_per_page = 200
......
......@@ -12,14 +12,16 @@ class InscriptionForm(FormRenderMixin, forms.ModelForm):
fields = (
"school", "sleeps", # "mug",
"meal_friday_evening", "meal_saturday_morning", "meal_saturday_midday",
"meal_saturday_evening", "meal_sunday_morning", "meal_sunday_midday",
"meal_saturday_evening", "meal_sunday_morning", "meal_sunday_midday", "meal_sunday_evening",
"paid","nb_murder", "comment"
)
field_groups = [["school"], ["sleeps"], #["mug"],
[
"meal_friday_evening", "meal_saturday_morning", "meal_saturday_midday",
"meal_saturday_evening", "meal_sunday_morning", "meal_sunday_midday",
]
"meal_saturday_evening", "meal_sunday_morning", "meal_sunday_midday", "meal_sunday_evening"
],
["paid"],["nb_murder"], ["comment"]
]
def save(self, *args, commit=True, **kwargs):
......@@ -66,7 +68,7 @@ class ActivitySubmissionForm(FormRenderMixin, forms.ModelForm):
fields = (
"title", "act_type", "game_type", "description",
"host_info",
"host_name", "host_email", "host_info",
"must_subscribe", "communicate_participants",
"max_participants", "min_participants",
......@@ -82,7 +84,8 @@ class ActivitySubmissionForm(FormRenderMixin, forms.ModelForm):
"available_sunday_afternoon",
"constraints",
"status", "needs",
#"status",
"needs",
"comments",
)
......@@ -98,12 +101,10 @@ class ActivitySubmissionForm(FormRenderMixin, forms.ModelForm):
)
return cleaned_data
def save(self, user, *args, commit=True, **kwargs):
def save(self, *args, commit=True, **kwargs):
"""Enregistre l'activité dans la base de données"""
activity = models.ActivityModel(
**self.cleaned_data,
host=user, host_email=user.email,
host_name=(user.first_name + user.last_name)
)
if commit:
activity.save()
......
# Generated by Django 3.2.7 on 2021-09-13 17:01
# Generated by Django 3.2.7 on 2021-10-05 18:45
from django.conf import settings
from django.db import migrations, models
......@@ -20,6 +20,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('display', models.BooleanField(default=False, help_text="Si vrai, s'affiche sur la page activités", verbose_name='afficher dans la liste')),
('show_email', models.BooleanField(default=True, help_text="Si l'affichage d'email global et cette case sont vrai, affiche l'email de l'orga", verbose_name="afficher l'email de l'orga")),
('title', models.CharField(max_length=200, verbose_name='Titre')),
('act_type', models.CharField(choices=[('1 partie', 'Une partie'), ('2+ parties', 'Quelques parties'), ('Tournoi', 'Tournoi'), ('freeplay', 'Freeplay'), ('other', 'Autre')], max_length=12, verbose_name="Type d'activité")),
('game_type', models.CharField(choices=[('jeu cartes', 'Jeu de cartes'), ('jeu plateau', 'Jeu de société'), ('table RPG', 'Jeu de rôle sur table'), ('large RPG', 'Jeu de rôle grandeur nature'), ('videogame', 'Jeu vidéo'), ('partygame', 'Party game'), ('puzzle', 'Puzzle ou analogue'), ('secret roles', 'Jeu à rôles secrets'), ('coop', 'Jeu coopératif'), ('other', 'Autre')], max_length=12, verbose_name='Type de jeu')),
......@@ -60,9 +61,10 @@ class Migration(migrations.Migration):
('start', models.DateTimeField(verbose_name='début')),
('duration', models.DurationField(blank=True, help_text="Format 00:00:00. Laisser vide pour prendre la durée de l'activité correspondante", null=True, verbose_name='durée')),
('room', models.CharField(blank=True, max_length=100, null=True, verbose_name='salle')),
('on_planning', models.BooleanField(default=False, help_text='Nécessite de salle et heure de début non vide', verbose_name='afficher sur le planning')),
('on_planning', models.BooleanField(default=True, verbose_name='afficher sur le planning')),
('on_activity', models.BooleanField(default=True, verbose_name="afficher dans la description de l'activité")),
('subscribing_open', models.BooleanField(default=False, help_text="Si vrai, apparaît dans la liste du formulaire d'inscription", verbose_name='ouvert aux inscriptions')),
('color', models.CharField(choices=[('a', 'Rouge'), ('b', 'Orange'), ('c', 'Jaune'), ('d', 'Vert'), ('e', 'Bleu'), ('f', 'Bleu foncé'), ('g', 'Noir')], default='f', help_text='La légende des couleurs est modifiable dans les paramètres', max_length=1, verbose_name='Couleur')),
('color', models.CharField(choices=[('a', 'Rouge'), ('b', 'Orange'), ('c', 'Jaune'), ('d', 'Vert'), ('e', 'Bleu'), ('f', 'Bleu foncé'), ('g', 'Noir')], default='a', help_text='La légende des couleurs est modifiable dans les paramètres', max_length=1, verbose_name='Couleur')),
('activity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='home.activitymodel', verbose_name='Activité')),
],
options={
......
# Generated by Django 3.2.16 on 2022-11-08 18:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='participantmodel',
name='comment',
field=models.TextField(blank=True, max_length=2000, null=True, verbose_name='Commentaire'),
),
migrations.AddField(
model_name='participantmodel',
name='nb_murder',
field=models.PositiveIntegerField(default=0, verbose_name='Nombre de murder réalisées'),
),
]
# Generated by Django 3.2.16 on 2022-11-15 09:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0002_auto_20221108_1943'),
]
operations = [
migrations.AlterField(
model_name='activitymodel',
name='status',
field=models.CharField(blank=True, choices=[('P', 'En présentiel uniquement'), ('D', 'En distanciel uniquement'), ('2', 'Les deux')], default='P', max_length=1, verbose_name='Présentiel/distanciel'),
),
]
# Generated by Django 3.2.16 on 2022-11-17 20:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0003_alter_activitymodel_status'),
]
operations = [
migrations.AddField(
model_name='participantmodel',
name='paid',
field=models.BooleanField(default=False, verbose_name='payé(e)'),
),
]
# Generated by Django 3.2.16 on 2022-12-09 09:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0004_participantmodel_paid'),
]
operations = [
migrations.AddField(
model_name='participantmodel',
name='meal_sunday_evening',
field=models.BooleanField(default=False, verbose_name='repas de dimanche soir'),
),
migrations.AlterField(
model_name='participantmodel',
name='meal_sunday_midday',
field=models.BooleanField(default=False, verbose_name='repas de dimanche midi'),
),
]
# Generated by Django 3.2.16 on 2022-12-09 10:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('home', '0005_auto_20221209_1028'),
]
operations = [
migrations.AddField(
model_name='participantmodel',
name='amount_paid',
field=models.PositiveIntegerField(default=0, verbose_name='Montant payé'),
),
]
......@@ -54,6 +54,10 @@ class ActivityModel(models.Model):
display = models.BooleanField("afficher dans la liste", default=False,
help_text="Si vrai, s'affiche sur la page activités"
)
show_email = models.BooleanField("afficher l'email de l'orga", default=True,
help_text="Si l'affichage d'email global et cette case sont vrai, affiche l'email de l'orga"
)
title = models.CharField("Titre", max_length=200)
......@@ -138,7 +142,10 @@ class ActivityModel(models.Model):
"Contraintes particulières", max_length=2000, blank=True, null=True
)
status = models.CharField("Présentiel/distanciel", choices=Status.choices, max_length=1)
status = models.CharField(
"Présentiel/distanciel", choices=Status.choices, max_length=1,
default=Status.PRESENT, blank=True
)
needs = models.TextField(
"Besoin particuliers", max_length=2000, blank=True, null=True
)
......@@ -167,15 +174,9 @@ class ActivityModel(models.Model):
@property
def pretty_type(self) -> str:
type = self.Types(self.act_type).label
return type
# status = self.Status(self.status)
# status_repr = "présentiel ou distanciel"
# if status == self.Status.DISTANT:
# status_repr = "distanciel"
# elif status == self.Status.PRESENT:
# status_repr = "présentiel"
# return "{} ({})".format(type, status_repr)
type = self.ActivityTypes(self.act_type).label
game = self.GameTypes(self.game_type).label
return "{}, {}".format(game, type.lower())
@property
def slug(self) -> str:
......@@ -185,7 +186,7 @@ class ActivityModel(models.Model):
@property
def slots(self):
"""Returns a list of slots related to self"""
return SlotModel.objects.filter(activity=self, on_planning=True).order_by("start")
return SlotModel.objects.filter(activity=self, on_activity=True).order_by("start")
def __str__(self):
return self.title
......@@ -214,14 +215,16 @@ class SlotModel(models.Model):
)
room = models.CharField("salle", max_length=100, null=True, blank=True)
on_planning = models.BooleanField(
"afficher sur le planning", default=False,
help_text="Nécessite de salle et heure de début non vide",
"afficher sur le planning", default=True,
)
on_activity = models.BooleanField(
"afficher dans la description de l'activité", default=True,
)
subscribing_open = models.BooleanField("ouvert aux inscriptions", default=False,
help_text="Si vrai, apparaît dans la liste du formulaire d'inscription"
)
color = models.CharField(
"Couleur", choices=Colors.choices, max_length=1, default=Colors.DARK_BLUE,
"Couleur", choices=Colors.choices, max_length=1, default=Colors.RED,
help_text="La légende des couleurs est modifiable dans les paramètres"
)
......@@ -318,12 +321,21 @@ class ParticipantModel(models.Model):
meal_saturday_midday = models.BooleanField("repas de samedi midi", default=False)
meal_saturday_evening = models.BooleanField("repas de samedi soir", default=False)
meal_sunday_morning = models.BooleanField("repas de dimanche matin", default=False)
meal_sunday_midday = models.BooleanField("repas de dimanche soir", default=False)
meal_sunday_midday = models.BooleanField("repas de dimanche midi", default=False)
meal_sunday_evening = models.BooleanField("repas de dimanche soir", default=False)
sleeps = models.BooleanField("dormir sur place", default=False)
paid = models.BooleanField("payé(e)", default=False)
# mug = models.BooleanField("commander une tasse", default=False)
nb_murder = models.PositiveIntegerField("Nombre de murder réalisées", default=0)
comment = models.TextField("Commentaire", max_length=2000, blank=True, null=True)
amount_paid = models.PositiveIntegerField("Montant payé", default=0)
def __str__(self) -> str:
school = self.ENS(self.school).label.replace("ENS ", "") if self.school else ""
return "{} {} ({})".format(self.user.first_name, self.user.last_name, school)
......@@ -332,7 +344,13 @@ class ParticipantModel(models.Model):
def nb_meals(self) -> int:
return (
self.meal_friday_evening + self.meal_saturday_evening + self.meal_saturday_midday +
self.meal_saturday_morning + self.meal_sunday_midday + self.meal_sunday_morning
self.meal_saturday_morning + self.meal_sunday_midday + self.meal_sunday_morning +
self.meal_sunday_evening
)
@property
def cost(self) -> int:
return (
(self.is_registered*2 + self.nb_meals) * (2+self.paid) - (self.paid*self.meal_sunday_evening)
)
class Meta:
......
......@@ -98,7 +98,7 @@ header #head_main_infos {
div.easter_egg {
display: inline-block;
}
#circle {
-webkit-clip-path: circle(50% at 50% 50%);
clip-path: circle(50% at 50% 50%)
......@@ -135,6 +135,10 @@ nav a:hover {
background-color: var(--color_bg_3);
transition-duration: 0.5s;
}
nav a:focus {
background-color: var(--color_bg_3);
}
nav a.current {
background-color: var(--color_bg_1);
......@@ -224,6 +228,10 @@ main p {
strong {
font-weight: bold;
}
.underline {
text-decoration: underline;
}
main a:link {
text-decoration: underline;
......@@ -443,40 +451,54 @@ ul.messagelist li.info:before {
height: 35px;
margin: 0 5px 0 0;
}
#transport-metro-icon,
#transport-metro-stop,
#transport-bus-1-icon,
#transport-bus-1-stop {
#transport-ratp-metro-icon,
#transport-ratp-metro-stop,
#transport-ratp-bus-1-icon,
#transport-ratp-bus-1-stop,
#transport-tcl-metro,
#transport-tcl-bus-1 {
grid-row: 1;
}
#transport-rer-icon,
#transport-rer-stop,
#transport-bus-2-icon,
#transport-bus-2-stop {
#transport-ratp-rer-icon,
#transport-ratp-rer-stop,
#transport-ratp-bus-2-icon,
#transport-ratp-bus-2-stop,
#transport-tcl-tram-1,
#transport-tcl-bus-2,
#transport-tcl-stop {
grid-row: 2;
}
#transport-noctilien-icon,
#transport-noctilien-stop {
#transport-ratp-noctilien-icon,
#transport-ratp-noctilien-stop,
#transport-tcl-tram-2,
#transport-tcl-bus-3 {
grid-row: 3;
}
#transport-metro-icon,
#transport-rer-icon {
#transport-ratp-metro-icon,
#transport-ratp-rer-icon{
grid-column: 1;
justify-self: end;
}
#transport-metro-stop,
#transport-rer-stop {
#transport-ratp-metro-stop,
#transport-ratp-rer-stop,
#transport-tcl-stop {
grid-column: 2;
}
#transport-bus-1-icon,
#transport-bus-2-icon,
#transport-noctilien-icon {
#transport-ratp-bus-1-icon,
#transport-ratp-bus-2-icon,
#transport-ratp-noctilien-icon,
#transport-tcl-metro,
#transport-tcl-tram-1,
#transport-tcl-tram-2 {
grid-column: 3;
justify-self: end;
}
#transport-bus-1-stop,
#transport-bus-2-stop,
#transport-noctilien-stop {
#transport-ratp-bus-1-stop,
#transport-ratp-bus-2-stop,
#transport-ratp-noctilien-stop,
#transport-tcl-bus-1,
#transport-tcl-bus-2,
#transport-tcl-bus-3 {
grid-column: 4;
}
......@@ -489,39 +511,39 @@ ul.messagelist li.info:before {
grid-template-rows: auto auto auto auto auto;
align-items: center;
}
#transport-metro-icon,
#transport-metro-stop {
#transport-ratp-metro-icon,
#transport-ratp-metro-stop {
grid-row: 1;
}
#transport-rer-icon,
#transport-rer-stop {
#transport-ratp-rer-icon,
#transport-ratp-rer-stop {
grid-row: 2;
}
#transport-bus-1-icon,
#transport-bus-1-stop {
#transport-ratp-bus-1-icon,
#transport-ratp-bus-1-stop {
grid-row: 3;
}
#transport-bus-2-icon,
#transport-bus-2-stop {
#transport-ratp-bus-2-icon,
#transport-ratp-bus-2-stop {
grid-row: 4;
}
#transport-noctilien-icon,
#transport-noctilien-stop {
#transport-ratp-noctilien-icon,
#transport-ratp-noctilien-stop {
grid-row: 5;
}
#transport-metro-icon,
#transport-rer-icon,
#transport-bus-1-icon,
#transport-bus-2-icon,
#transport-noctilien-icon {
#transport-ratp-metro-icon,
#transport-ratp-rer-icon,
#transport-ratp-bus-1-icon,
#transport-ratp-bus-2-icon,
#transport-ratp-noctilien-icon {
grid-column: 1;
justify-self: end;
}
#transport-metro-stop,
#transport-rer-stop,
#transport-bus-1-stop,
#transport-bus-2-stop,
#transport-noctilien-stop {
#transport-ratp-metro-stop,
#transport-ratp-rer-stop,
#transport-ratp-bus-1-stop,
#transport-ratp-bus-2-stop,
#transport-ratp-noctilien-stop {
grid-column: 2;
}
}
......