Compare commits
3 commits
master
...
ajout_comm
Author | SHA1 | Date | |
---|---|---|---|
|
a0fea58dab | ||
|
82c0d894ad | ||
|
bc94c5efe2 |
66 changed files with 485 additions and 1775 deletions
|
@ -35,7 +35,6 @@ ACCOUNT_CREATION_PASS = import_secret("ACCOUNT_CREATION_PASS")
|
|||
BASE_DIR = os.path.join(os.path.dirname(__file__), "..", "..")
|
||||
|
||||
INSTALLED_APPS = [
|
||||
"propositions",
|
||||
"trombonoscope",
|
||||
"actu",
|
||||
"colorful",
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
# Generated by Django 2.2.25 on 2022-01-06 12:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("actu", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="actu",
|
||||
name="rainbow",
|
||||
field=models.CharField(
|
||||
choices=[("y", "Oui"), ("n", "Non")],
|
||||
default="n",
|
||||
max_length=1,
|
||||
verbose_name="Actu en arc-en-ciel (ne pas mettre d'émoji, il prennent aussi la couleur et c'est moche)",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -7,15 +7,6 @@ class Actu(models.Model):
|
|||
text = models.TextField(_("Info"), null=True, blank=False)
|
||||
text_en = models.TextField(("Info en anglais"), null=True, blank=True)
|
||||
order = models.IntegerField(verbose_name=_("ordre"))
|
||||
rainbow = models.CharField(
|
||||
verbose_name=_(
|
||||
"Actu en arc-en-ciel (ne pas mettre d'émoji, il prennent aussi la couleur et c'est moche)"
|
||||
),
|
||||
max_length=1,
|
||||
choices=(("y", "Oui"), ("n", "Non")),
|
||||
default="n",
|
||||
blank=False,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.text
|
||||
|
|
|
@ -14,7 +14,7 @@ class ActuList(ChefRequiredMixin, ListView):
|
|||
|
||||
class ActuCreate(ChefRequiredMixin, CreateView):
|
||||
model = Actu
|
||||
fields = ["text", "order", "text_en", "rainbow"]
|
||||
fields = ["text", "order", "text_en"]
|
||||
template_name = "actu/create_actu.html"
|
||||
success_url = reverse_lazy("actu:liste")
|
||||
|
||||
|
@ -26,7 +26,7 @@ class ActuCreate(ChefRequiredMixin, CreateView):
|
|||
|
||||
class ActuUpdate(ChefRequiredMixin, UpdateView):
|
||||
model = Actu
|
||||
fields = ["text", "order", "text_en", "rainbow"]
|
||||
fields = ["text", "order", "text_en"]
|
||||
template_name = "actu/update_actu.html"
|
||||
success_url = reverse_lazy("actu:liste")
|
||||
|
||||
|
|
|
@ -2,27 +2,6 @@ from django.contrib import admin
|
|||
|
||||
from .models import Event, Participants
|
||||
|
||||
|
||||
class ParticipantsAdmin(admin.ModelAdmin):
|
||||
fields = [
|
||||
"event",
|
||||
"participant",
|
||||
"reponse",
|
||||
"instrument",
|
||||
"instrument_autre",
|
||||
"dont_play_main",
|
||||
"details",
|
||||
"creationDate",
|
||||
"updateDate",
|
||||
]
|
||||
readonly_fields = ["creationDate", "updateDate"]
|
||||
list_display = ["participant", "event", "reponse", "creationDate", "updateDate"]
|
||||
def has_add_permission(self, req):
|
||||
return False
|
||||
def has_change_permission(self,obj, change=False):
|
||||
return False
|
||||
|
||||
|
||||
# Add event by admin page return a 502 error
|
||||
admin.site.register(Event)
|
||||
admin.site.register(Participants, ParticipantsAdmin)
|
||||
admin.site.register(Participants)
|
||||
|
|
|
@ -22,11 +22,11 @@ class EventCalendar(HTMLCalendar):
|
|||
for ev in self.events[day]:
|
||||
body.append('<a href="/agenda/' + '%s"' % ev.id)
|
||||
if ev.calendrier == "C":
|
||||
body.append('style="color:#160083">' + esc(ev.nom))
|
||||
body.append('style="color:#160083">'+esc(ev.nom))
|
||||
elif ev.calendrier == "D":
|
||||
body.append('style="color:#770083">' + esc(ev.nom))
|
||||
body.append('style="color:#770083">'+esc(ev.nom))
|
||||
else:
|
||||
body.append(">" + esc(ev.nom))
|
||||
body.append('>'+esc(ev.nom))
|
||||
body.append("</a><br/>")
|
||||
return self.day_cell(
|
||||
cssclass,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from gestion.models import ErnestoUser
|
||||
|
||||
from calendrier.models import Event, Participants
|
||||
from gestion.models import ErnestoUser
|
||||
|
||||
|
||||
class ModifEventForm(forms.ModelForm):
|
||||
|
@ -37,13 +37,7 @@ class EventForm(forms.ModelForm):
|
|||
class ParticipantsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Participants
|
||||
fields = (
|
||||
"reponse",
|
||||
"details",
|
||||
"dont_play_main",
|
||||
"instrument",
|
||||
"instrument_autre",
|
||||
)
|
||||
fields = ("reponse", "details", "dont_play_main", "instrument","instrument_autre")
|
||||
widgets = {
|
||||
"details": forms.Textarea(attrs={"placeholder": _("50 caractères max")}),
|
||||
}
|
||||
|
|
|
@ -6,41 +6,23 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("calendrier", "0004_auto_20210606_1640"),
|
||||
('calendrier', '0004_auto_20210606_1640'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="event",
|
||||
name="calendrier",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("F", "Visible seulement par les fanfarons"),
|
||||
("T", "Afficher dans le calendrier pour tous"),
|
||||
("H", "Hall of fame"),
|
||||
("C", "Visible seulement par les cheff·e·s"),
|
||||
("D", "Visible seulement par les cheff·e·s et sur l'agenda public"),
|
||||
],
|
||||
default="F",
|
||||
max_length=1,
|
||||
),
|
||||
model_name='event',
|
||||
name='calendrier',
|
||||
field=models.CharField(choices=[('F', 'Visible seulement par les fanfarons'), ('T', 'Afficher dans le calendrier pour tous'), ('H', 'Hall of fame'), ('C', 'Visible seulement par les cheff·e·s'), ('D', "Visible seulement par les cheff·e·s et sur l'agenda public")], default='F', max_length=1),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="event",
|
||||
name="desc_users",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Infos (visible seulement des fanfaron·ne·s)",
|
||||
),
|
||||
model_name='event',
|
||||
name='desc_users',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='Infos (visible seulement des fanfaron·ne·s)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="event",
|
||||
name="desc_users_en",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name="Infos en anglais (visible seulement des fanfaron·ne·s",
|
||||
),
|
||||
model_name='event',
|
||||
name='desc_users_en',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='Infos en anglais (visible seulement des fanfaron·ne·s'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,36 +6,18 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("calendrier", "0005_auto_20210726_0949"),
|
||||
('calendrier', '0005_auto_20210726_0949'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="participants",
|
||||
name="instrument_autre",
|
||||
model_name='participants',
|
||||
name='instrument_autre',
|
||||
field=models.CharField(blank=True, max_length=50, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="participants",
|
||||
name="instrument",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("Clarinette", "Clarinette"),
|
||||
("Euphonium", "Euphonium"),
|
||||
("Percussion", "Percussion"),
|
||||
("Piccolo", "Piccolo"),
|
||||
("Saxophone Alto", "Saxophone Alto"),
|
||||
("Saxophone Ténor", "Saxophone Ténor"),
|
||||
("Saxophone Baryton", "Saxophone Baryton"),
|
||||
("Souba", "Souba"),
|
||||
("Trombone", "Trombone"),
|
||||
("Trompette", "Trompette"),
|
||||
("Autre", "Autre"),
|
||||
("ne sais pas", "Je ne sais pas encore"),
|
||||
],
|
||||
max_length=50,
|
||||
null=True,
|
||||
),
|
||||
model_name='participants',
|
||||
name='instrument',
|
||||
field=models.CharField(blank=True, choices=[('Clarinette', 'Clarinette'), ('Euphonium', 'Euphonium'), ('Percussion', 'Percussion'), ('Piccolo', 'Piccolo'), ('Saxophone Alto', 'Saxophone Alto'), ('Saxophone Ténor', 'Saxophone Ténor'), ('Saxophone Baryton', 'Saxophone Baryton'), ('Souba', 'Souba'), ('Trombone', 'Trombone'), ('Trompette', 'Trompette'), ('Autre', 'Autre'), ('ne sais pas', 'Je ne sais pas encore')], max_length=50, null=True),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
# Generated by Django 2.2.25 on 2022-03-14 23:20
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("calendrier", "0006_auto_20210929_1629"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="participants",
|
||||
name="creationDate",
|
||||
field=models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
default=django.utils.timezone.now,
|
||||
verbose_name="Date de création",
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="participants",
|
||||
name="updateDate",
|
||||
field=models.DateTimeField(
|
||||
auto_now=True, verbose_name="Dernière mise à jour"
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1,17 +0,0 @@
|
|||
# Generated by Django 2.2.27 on 2022-03-22 13:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('calendrier', '0007_auto_20220314_2320'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddConstraint(
|
||||
model_name='participants',
|
||||
constraint=models.UniqueConstraint(fields=('event', 'participant'), name='reponse unique aux event'),
|
||||
),
|
||||
]
|
|
@ -2,7 +2,9 @@ import uuid
|
|||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from gestion.models import INSTRU_CHOICES, ErnestoUser
|
||||
|
||||
from gestion.models import INSTRU_CHOICES
|
||||
from gestion.models import ErnestoUser
|
||||
|
||||
ANSWERS = (
|
||||
("oui", _("Oui")),
|
||||
|
@ -60,9 +62,7 @@ class Participants(models.Model):
|
|||
reponse = models.CharField(
|
||||
_("Réponse"), max_length=20, default="non", choices=ANSWERS
|
||||
)
|
||||
instrument = models.CharField(
|
||||
max_length=50, blank=True, null=True, choices=INSTRU_CHOICES
|
||||
)
|
||||
instrument = models.CharField(max_length=50, blank=True, null=True, choices=INSTRU_CHOICES)
|
||||
instrument_autre = models.CharField(max_length=50, blank=True, null=True)
|
||||
dont_play_main = models.CharField(
|
||||
_("Je veux jouer d'un instrument different de mon instrument principal:"),
|
||||
|
@ -72,11 +72,3 @@ class Participants(models.Model):
|
|||
choices=[("Non", _("Non")), ("Oui", _("Oui"))],
|
||||
)
|
||||
details = models.CharField(max_length=50, blank=True)
|
||||
creationDate = models.DateTimeField(
|
||||
auto_now_add=True, verbose_name=_("Date de création")
|
||||
)
|
||||
updateDate = models.DateTimeField(
|
||||
auto_now=True, verbose_name=_("Dernière mise à jour")
|
||||
)
|
||||
class Meta:
|
||||
constraints = [ models.UniqueConstraint(fields=['event', 'participant'], name='reponse unique aux event') ]
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<h4> <span class="ernestocouleur">{% blocktrans count counter=actu|length %}Actualité des chef·fe·s:{% plural %}Actualités des chef·fe·s:{% endblocktrans %}</span></h4>
|
||||
<ul>
|
||||
{% for a in actu %}
|
||||
<li>{% if a.rainbow == 'y' %}<span class="ernestocouleur font-weight-bold">{% endif %}{% autotranslate current_language a.text a.text_en %}{% if a.rainbow %}</span>{% endif %}</li>
|
||||
<li>{% autotranslate current_language a.text a.text_en %}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -223,9 +223,6 @@
|
|||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% if event.id == 573 %}
|
||||
<div class="fireworks" style="pointer-events: none; position:fixed; top: 0; left: 0; right: 0; bottom: 0; height: 100%; weight: 100%;"></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
<script>
|
||||
|
@ -267,13 +264,5 @@ singleEvent.setOption({ lang: 'fr' });
|
|||
singleEvent.setOption({ lang: 'en' });
|
||||
{% endifequal %}
|
||||
</script>
|
||||
{% if event.id == 573 %}
|
||||
<script src="https://unpkg.com/fireworks-js@2.x/dist/index.umd.js"></script>
|
||||
<script>
|
||||
const container = document.querySelector('.fireworks');
|
||||
const fireworks = new Fireworks.default(container);
|
||||
fireworks.updateOptions({ acceleration: 1.01, traceSpeed: 5 });
|
||||
fireworks.start();
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.contrib.auth import get_user_model
|
|||
from django.template.defaultfilters import urlencode
|
||||
from django.test import Client, TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from gestion.models import ErnestoUser
|
||||
|
||||
from ..models import Event
|
||||
|
|
|
@ -4,20 +4,20 @@ from calendar import monthrange
|
|||
from collections import defaultdict
|
||||
from datetime import date, datetime
|
||||
|
||||
from actu.models import Actu
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.views.generic import DeleteView, TemplateView, UpdateView
|
||||
from gestion.mixins import ChefEventRequiredMixin
|
||||
from gestion.models import Photo
|
||||
|
||||
from actu.models import Actu
|
||||
from calendrier.calend import EventCalendar
|
||||
from calendrier.forms import (ChangeDoodleName, EventForm, ModifEventForm,
|
||||
ParticipantsForm)
|
||||
from calendrier.models import Event, Participants
|
||||
from gestion.mixins import ChefRequiredMixin, ChefEventRequiredMixin
|
||||
from gestion.models import Photo
|
||||
|
||||
|
||||
def generer(*args):
|
||||
|
@ -76,13 +76,9 @@ class Calendar(LoginRequiredMixin, TemplateView):
|
|||
lMonth = self.pMonth
|
||||
lCalendarFromMonth = datetime(lYear, lMonth, 1)
|
||||
lCalendarToMonth = datetime(lYear, lMonth, monthrange(lYear, lMonth)[1])
|
||||
lEvents = (
|
||||
Event.objects.filter(
|
||||
lEvents = Event.objects.filter(
|
||||
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
|
||||
)
|
||||
.exclude(calendrier__iexact="C")
|
||||
.exclude(calendrier__iexact="D")
|
||||
)
|
||||
).exclude(calendrier__iexact="C").exclude(calendrier__iexact="D")
|
||||
lEvents_chef = Event.objects.filter(
|
||||
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
|
||||
)
|
||||
|
@ -174,6 +170,7 @@ class Calendar(LoginRequiredMixin, TemplateView):
|
|||
|
||||
|
||||
class Home(Calendar):
|
||||
|
||||
@property
|
||||
def pYear(self):
|
||||
lToday = datetime.now()
|
||||
|
@ -212,7 +209,6 @@ class ViewEvent(LoginRequiredMixin, TemplateView):
|
|||
else:
|
||||
instru = participant.instrument
|
||||
|
||||
instru = "" if instru is None else instru
|
||||
sure, maybe, namesoui, namespe, namesnon = instrument_count[instru]
|
||||
|
||||
if participant.reponse == "oui":
|
||||
|
@ -238,52 +234,25 @@ class ViewEvent(LoginRequiredMixin, TemplateView):
|
|||
namesnon += [participant.participant.get_doodlename()]
|
||||
instrument_count[instru] = (sure, maybe, namesoui, namespe, namesnon)
|
||||
instrument_count_l = []
|
||||
instru_order = [
|
||||
"Clarinette",
|
||||
"Piccolo",
|
||||
"Flute",
|
||||
"Glockenspiel",
|
||||
"Saxophone Alto",
|
||||
"Trompette",
|
||||
"Trombone",
|
||||
"Cor",
|
||||
"Saxophone Ténor",
|
||||
"Saxophone Baryton",
|
||||
"Clarinette Basse",
|
||||
"Euphonium",
|
||||
"Souba",
|
||||
"Percussion",
|
||||
]
|
||||
instru_order = ["Clarinette","Piccolo","Flute","Glockenspiel","Saxophone Alto","Trompette","Trombone","Cor","Saxophone Ténor","Saxophone Baryton","Clarinette Basse","Euphonium","Souba","Percussion"]
|
||||
for instrument in instru_order:
|
||||
if instrument in instrument_count.keys():
|
||||
(sure, maybe, namesoui, namespe, namesnon) = instrument_count[
|
||||
instrument
|
||||
]
|
||||
instrument_count_l.append(
|
||||
(
|
||||
instrument,
|
||||
sure,
|
||||
(sure,maybe,namesoui,namespe,namesnon) =instrument_count[instrument]
|
||||
instrument_count_l.append(( instrument, sure,
|
||||
maybe,
|
||||
namesoui,
|
||||
namespe,
|
||||
namesnon,
|
||||
)
|
||||
)
|
||||
))
|
||||
for instrument in sorted(instrument_count.keys()):
|
||||
if instrument not in instru_order:
|
||||
(sure, maybe, namesoui, namespe, namesnon) = instrument_count[
|
||||
instrument
|
||||
]
|
||||
instrument_count_l.append(
|
||||
(
|
||||
instrument,
|
||||
sure,
|
||||
(sure,maybe,namesoui,namespe,namesnon) =instrument_count[instrument]
|
||||
instrument_count_l.append(( instrument, sure,
|
||||
maybe,
|
||||
namesoui,
|
||||
namespe,
|
||||
namesnon,
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
context["event"] = event
|
||||
context["instrument_count"] = instrument_count_l
|
||||
|
@ -292,7 +261,7 @@ class ViewEvent(LoginRequiredMixin, TemplateView):
|
|||
context["nbpe"] = len(participants.filter(reponse="pe"))
|
||||
context["nbnon"] = len(participants.filter(reponse="non"))
|
||||
context["multi_instrumentistes"] = multi_instrumentistes
|
||||
context["chef_only"] = (event.calendrier == "C") | (event.calendrier == "D")
|
||||
context["chef_only"] = (event.calendrier == "C")|(event.calendrier == "D")
|
||||
return context
|
||||
|
||||
|
||||
|
@ -368,22 +337,20 @@ class ReponseEvent(LoginRequiredMixin, TemplateView):
|
|||
context["form"] = self.form_class()
|
||||
context["ev"] = get_object_or_404(Event, id=self.kwargs["id"])
|
||||
context["id"] = self.kwargs["id"]
|
||||
context["chef_only"] = (context["ev"].calendrier == "C") | (
|
||||
context["ev"].calendrier == "D"
|
||||
)
|
||||
context["chef_only"] = (context["ev"].calendrier == "C")|(context["ev"].calendrier == "D")
|
||||
return context
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
form = self.form_class(request.POST)
|
||||
ev = get_object_or_404(Event, id=self.kwargs["id"])
|
||||
part = request.user.profile
|
||||
if form.is_valid():
|
||||
try:
|
||||
p = Participants.objects.get(event=ev, participant=part)
|
||||
p.delete()
|
||||
except Participants.DoesNotExist:
|
||||
p = None
|
||||
form = self.form_class(request.POST, instance=p)
|
||||
if form.is_valid():
|
||||
pass
|
||||
obj = form.save(commit=False)
|
||||
# Si la participation existe déjà, ces 2 ligne sont redondantes
|
||||
obj.event = ev
|
||||
obj.participant = part
|
||||
obj.save()
|
||||
|
|
|
@ -1,24 +1,19 @@
|
|||
# Generated by Django 2.2.17 on 2021-06-08 10:29
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
import gestion.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("gestion", "0005_auto_20210427_1834"),
|
||||
('gestion', '0005_auto_20210427_1834'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="photo",
|
||||
name="image",
|
||||
field=models.ImageField(
|
||||
default=None,
|
||||
upload_to="trombonoscope/deco",
|
||||
validators=[gestion.models.Photo.validate_image],
|
||||
),
|
||||
model_name='photo',
|
||||
name='image',
|
||||
field=models.ImageField(default=None, upload_to='trombonoscope/deco', validators=[gestion.models.Photo.validate_image]),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,15 +6,13 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("gestion", "0006_auto_20210608_1029"),
|
||||
('gestion', '0006_auto_20210608_1029'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="ernestouser",
|
||||
name="is_chef_event",
|
||||
field=models.BooleanField(
|
||||
default=False, verbose_name="Respo événement Fanfare"
|
||||
),
|
||||
model_name='ernestouser',
|
||||
name='is_chef_event',
|
||||
field=models.BooleanField(default=False, verbose_name='Respo événement Fanfare'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -6,23 +6,23 @@ from django.db import migrations, models
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("gestion", "0007_ernestouser_is_chef_event"),
|
||||
('gestion', '0007_ernestouser_is_chef_event'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="ernestouser",
|
||||
name="is_chef_com",
|
||||
field=models.BooleanField(default=False, verbose_name="Respo com"),
|
||||
model_name='ernestouser',
|
||||
name='is_chef_com',
|
||||
field=models.BooleanField(default=False, verbose_name='Respo com'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="ernestouser",
|
||||
name="is_chef_instru",
|
||||
field=models.BooleanField(default=False, verbose_name="Respo instruments"),
|
||||
model_name='ernestouser',
|
||||
name='is_chef_instru',
|
||||
field=models.BooleanField(default=False, verbose_name='Respo instruments'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ernestouser",
|
||||
name="is_chef_event",
|
||||
field=models.BooleanField(default=False, verbose_name="Respo événements"),
|
||||
model_name='ernestouser',
|
||||
name='is_chef_event',
|
||||
field=models.BooleanField(default=False, verbose_name='Respo événements'),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.2.24 on 2022-01-11 15:12
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("gestion", "0008_auto_20211022_1923"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="ernestouser",
|
||||
name="is_chef_mu",
|
||||
field=models.BooleanField(default=False, verbose_name="Respo musique"),
|
||||
),
|
||||
]
|
|
@ -6,75 +6,32 @@ class ChefRequiredMixin(UserPassesTestMixin):
|
|||
user = self.request.user
|
||||
return (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
|
||||
|
||||
class ChefEventRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
user = self.request.user
|
||||
is_chef = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
)
|
||||
is_chef_event = (
|
||||
(user is not None)
|
||||
and hasattr(user, "profile")
|
||||
and user.profile.is_chef_event
|
||||
)
|
||||
is_chef = (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
is_chef_event = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_event
|
||||
return is_chef or is_chef_event
|
||||
|
||||
|
||||
class ChefInstruRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
user = self.request.user
|
||||
is_chef = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
)
|
||||
is_chef_instru = (
|
||||
(user is not None)
|
||||
and hasattr(user, "profile")
|
||||
and user.profile.is_chef_instru
|
||||
)
|
||||
is_chef = (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
is_chef_instru = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_instru
|
||||
return is_chef or is_chef_instru
|
||||
|
||||
|
||||
class ChefComRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
user = self.request.user
|
||||
is_chef = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
)
|
||||
is_chef_com = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_com
|
||||
)
|
||||
is_chef = (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
is_chef_com = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_com
|
||||
return is_chef or is_chef_com
|
||||
|
||||
|
||||
class ChefMuRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
user = self.request.user
|
||||
is_chef = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
)
|
||||
is_chef_mu = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_mu
|
||||
)
|
||||
return is_chef or is_chef_mu
|
||||
|
||||
|
||||
class AllChefRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
user = self.request.user
|
||||
is_chef = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
)
|
||||
is_chef = (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||
is_su = (user is not None) and user.is_superuser
|
||||
is_chef_com = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_com
|
||||
)
|
||||
is_chef_event = (
|
||||
(user is not None)
|
||||
and hasattr(user, "profile")
|
||||
and user.profile.is_chef_event
|
||||
)
|
||||
is_chef_mu = (
|
||||
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_mu
|
||||
)
|
||||
return is_chef or is_chef_com or is_chef_event or is_su or is_chef_mu
|
||||
is_chef_com = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_com
|
||||
is_chef_event = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_event
|
||||
return is_chef or is_chef_com or is_chef_event or is_su
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
|
||||
from colorful.fields import RGBColorField
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
import os
|
||||
from django.conf import settings
|
||||
|
||||
# Variable globale représentant les pupitres de la fanf
|
||||
INSTRU_CHOICES = [
|
||||
("Clarinette", _("Clarinette")),
|
||||
("Euphonium", _("Euphonium")),
|
||||
|
@ -22,10 +22,15 @@ INSTRU_CHOICES = [
|
|||
("Trompette", _("Trompette")),
|
||||
("Autre", _("Autre")),
|
||||
("ne sais pas", _("Je ne sais pas encore")),
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
class Photo(models.Model):
|
||||
"""
|
||||
Modèle qui représente les photos du site
|
||||
"""
|
||||
|
||||
|
||||
PHOTO_PLACEMENT = (
|
||||
("home_join", _("Rejoignez nous")),
|
||||
("home_contact", _("Nous Contacter")),
|
||||
|
@ -39,34 +44,47 @@ class Photo(models.Model):
|
|||
("instru", _("Instruments")),
|
||||
("n", _("N'apparait pas")),
|
||||
)
|
||||
"""Endroits du site où l'on peut mettre des photos"""
|
||||
|
||||
def validate_image(fieldfile_obj):
|
||||
"""
|
||||
Fonction qui vérifie si l'image est suffisament petite (probablement pour ne pas surcharger le serveur)
|
||||
"""
|
||||
filesize = fieldfile_obj.file.size
|
||||
mb_limit = 1.0
|
||||
if filesize > mb_limit * 1024 * 1024:
|
||||
raise ValidationError("La taille max est %sMB" % str(mb_limit))
|
||||
|
||||
name = models.CharField(max_length=127)
|
||||
"""Nom de la photo"""
|
||||
|
||||
cat = models.CharField(max_length=127, choices=PHOTO_PLACEMENT, default="n")
|
||||
auteur = models.CharField(
|
||||
max_length=127, verbose_name=_("Auteur de l'image"), null=True, blank=True
|
||||
)
|
||||
url = models.URLField(
|
||||
verbose_name=_("Lien vers le site de l'auteur"), null=True, blank=True
|
||||
)
|
||||
"""Memorise l'emplacement de la photo"""
|
||||
|
||||
auteur = models.CharField( max_length=127, verbose_name=_("Auteur de l'image"), null=True, blank=True)
|
||||
"""Nom de l'auteur"""
|
||||
|
||||
url = models.URLField(verbose_name=_("Lien vers le site de l'auteur"), null=True, blank=True)
|
||||
|
||||
color = RGBColorField(_("Couleur du nom de l'auteur"), default="#ffffff")
|
||||
image = models.ImageField(
|
||||
upload_to="trombonoscope/deco", default=None, validators=[validate_image]
|
||||
)
|
||||
"""Couleur pour que le copyright ressorte bien"""
|
||||
|
||||
image = models.ImageField(upload_to="trombonoscope/deco", default=None, validators=[validate_image])
|
||||
"""L'image en elle-même"""
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def delete(self):
|
||||
os.remove(self.image.path)
|
||||
# Pour supprimer une instance du modèle, il faut appeler la méthode delete du parent. Il me semble que les arguments de super ne servent pas et compliquent un éventuel rennomage de classe
|
||||
return super(Photo, self).delete()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
"""
|
||||
Permet d'enregistrer une photo. Si il s'agit d'un update, on remet à jour le chemin de la dossier MEDIA/trombonoscope/doc. Si ce n'est pas un update, il suffit d'enregistrer
|
||||
Pour comprendre bien le processus d'update, regarder la vue associée.
|
||||
"""
|
||||
try:
|
||||
this = Photo.objects.get(id=self.id)
|
||||
if this.image.path != self.image.path:
|
||||
|
@ -76,18 +94,31 @@ class Photo(models.Model):
|
|||
super(Photo, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
Classe de Metadonnées (cf la doc)
|
||||
"""
|
||||
verbose_name = _("Photo")
|
||||
verbose_name_plural = _("Photos")
|
||||
|
||||
|
||||
class ErnestoUser(models.Model):
|
||||
"""
|
||||
Modèle représentant un fanfaron, il est lié par un `OneToOneField` au modèle d'utilisateur de `django.contrib.auth`
|
||||
"""
|
||||
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
|
||||
"""Lien avec les utilisateurs de `django.contrib.auth`"""
|
||||
|
||||
is_ernesto = models.BooleanField(_("Membre de l'Ernestophone"), default=True)
|
||||
|
||||
is_chef = models.BooleanField(_("Chef Fanfare"), default=False)
|
||||
|
||||
is_chef_event = models.BooleanField(_("Respo événements"), default=False)
|
||||
|
||||
is_chef_com = models.BooleanField(_("Respo com"), default=False)
|
||||
|
||||
is_chef_instru = models.BooleanField(_("Respo instruments"), default=False)
|
||||
is_chef_mu = models.BooleanField(_("Respo musique"), default=False)
|
||||
|
||||
phone = models.CharField(
|
||||
_("Téléphone"),
|
||||
max_length=20,
|
||||
|
@ -95,16 +126,8 @@ class ErnestoUser(models.Model):
|
|||
help_text=_("seulement visible par les chef·fe·s"),
|
||||
)
|
||||
|
||||
COLORS_CHOICES = [
|
||||
("#e4522f#ffffff", _("Orange et Blanc")),
|
||||
("#ffffff#000000", _("Blanc et Noir")),
|
||||
("#A8107C#000000", _("Rose et Noir")),
|
||||
("#10A4A8#ffffff", _("Bleu et Blanc")),
|
||||
("#26A810#000000", _("Vert et Noir")),
|
||||
("#A81026#ffffff", _("Rouge et Blanc")),
|
||||
("#E3E54C#000000", _("Jaune et Noir")),
|
||||
("autre", _("Autre")),
|
||||
]
|
||||
|
||||
#Instruments du fanfaron
|
||||
|
||||
instru = models.CharField(
|
||||
_("Instrument joué"),
|
||||
|
@ -113,43 +136,10 @@ class ErnestoUser(models.Model):
|
|||
choices=INSTRU_CHOICES,
|
||||
default="ne sais pas",
|
||||
)
|
||||
|
||||
instru_autre = models.CharField(
|
||||
_("Lequel ?"), null=True, max_length=100, blank=True
|
||||
)
|
||||
slug = models.CharField(max_length=7, editable=False, unique=True)
|
||||
doodlename = models.CharField(_("Nom pour le doodle"), max_length=30, blank=True)
|
||||
|
||||
trombonoscope = models.CharField(
|
||||
_("Je souhaite apparaitre dans le trombonoscope:"),
|
||||
max_length=3,
|
||||
blank=False,
|
||||
null=True,
|
||||
choices=[
|
||||
("non", _("Non")),
|
||||
("o_a", _("Oui en tant que fanfaron actuel")),
|
||||
("o_v", _("Oui en tant que vie·ille·ux")),
|
||||
],
|
||||
default="non",
|
||||
)
|
||||
instru_trombonoscope = models.CharField(
|
||||
_("Instrument affiché sur le trombonoscope"), max_length=30, blank=True
|
||||
)
|
||||
nom_trombonoscope = models.CharField(
|
||||
_("Nom affiché sur le trombonoscope"), max_length=30, blank=True
|
||||
)
|
||||
trombonoscope_colors = models.CharField(
|
||||
_("Couleur du profil"),
|
||||
max_length=40,
|
||||
blank=False,
|
||||
choices=COLORS_CHOICES,
|
||||
default="OrangeBlanc",
|
||||
)
|
||||
trombonoscope_fond = RGBColorField(
|
||||
_("Couleur de fond du profil"), default="#e4522f"
|
||||
)
|
||||
trombonoscope_texte = RGBColorField(
|
||||
_("Couleur du texte du profil"), default="#ffffff"
|
||||
)
|
||||
|
||||
multi_instrumentiste = models.CharField(
|
||||
_("Je suis capable de jouer d'un autre instrument en manche :"),
|
||||
|
@ -163,7 +153,64 @@ class ErnestoUser(models.Model):
|
|||
_("Le·s·quel·s ?"), null=True, max_length=100, blank=True
|
||||
)
|
||||
|
||||
|
||||
slug = models.CharField(max_length=7, editable=False, unique=True)
|
||||
|
||||
doodlename = models.CharField(_("Nom pour le doodle"), max_length=30, blank=True)
|
||||
|
||||
#Paramètres pour le trombonoscope
|
||||
|
||||
COLORS_CHOICES = [
|
||||
("#e4522f#ffffff", _("Orange et Blanc")),
|
||||
("#ffffff#000000", _("Blanc et Noir")),
|
||||
("#A8107C#000000", _("Rose et Noir")),
|
||||
("#10A4A8#ffffff", _("Bleu et Blanc")),
|
||||
("#26A810#000000", _("Vert et Noir")),
|
||||
("#A81026#ffffff", _("Rouge et Blanc")),
|
||||
("#E3E54C#000000", _("Jaune et Noir")),
|
||||
("autre", _("Autre")),
|
||||
]
|
||||
|
||||
trombonoscope = models.CharField(
|
||||
_("Je souhaite apparaitre dans le trombonoscope:"),
|
||||
max_length=3,
|
||||
blank=False,
|
||||
null=True,
|
||||
choices=[
|
||||
("non", _("Non")),
|
||||
("o_a", _("Oui en tant que fanfaron actuel")),
|
||||
("o_v", _("Oui en tant que vie·ille·ux")),
|
||||
],
|
||||
default="non",
|
||||
)
|
||||
|
||||
instru_trombonoscope = models.CharField(
|
||||
_("Instrument affiché sur le trombonoscope"), max_length=30, blank=True
|
||||
)
|
||||
|
||||
nom_trombonoscope = models.CharField(
|
||||
_("Nom affiché sur le trombonoscope"), max_length=30, blank=True
|
||||
)
|
||||
trombonoscope_colors = models.CharField(
|
||||
_("Couleur du profil"),
|
||||
max_length=40,
|
||||
blank=False,
|
||||
choices=COLORS_CHOICES,
|
||||
default="OrangeBlanc",
|
||||
)
|
||||
|
||||
trombonoscope_fond = RGBColorField(
|
||||
_("Couleur de fond du profil"), default="#e4522f"
|
||||
)
|
||||
"""Prend la valeur associée au champs `trombonoscope_colors`"""
|
||||
|
||||
trombonoscope_texte = RGBColorField(
|
||||
_("Couleur du texte du profil"), default="#ffffff"
|
||||
)
|
||||
"""Prend la valeur associée au champs `trombonoscope_colors`"""
|
||||
|
||||
class Meta:
|
||||
"""Matadonnées"""
|
||||
verbose_name = _("Profil Ernestophoniste")
|
||||
verbose_name_plural = _("Profil Ernestophoniste")
|
||||
|
||||
|
@ -177,6 +224,7 @@ class ErnestoUser(models.Model):
|
|||
|
||||
|
||||
class VideoGallery(models.Model):
|
||||
"""Objet représentant une vidéo pour le caroussel de la page publique. Le site n'héberge pas de vidéos. On ne stocke que des urls d'iframe."""
|
||||
name = models.CharField(max_length=127)
|
||||
order = models.IntegerField(verbose_name=_("ordre"))
|
||||
url = models.URLField()
|
||||
|
|
|
@ -3704,11 +3704,10 @@ div.spoiler
|
|||
hsl(220, 100%, 50%),
|
||||
hsl(230, 100%, 50%),
|
||||
hsl(240, 100%, 50%),
|
||||
hsl(250, 100%, 50%)
|
||||
hsl(250, 100%, 50%),
|
||||
hsl(260, 100%, 50%),
|
||||
hsl(270, 100%, 50%),
|
||||
hsl(280, 100%, 50%)
|
||||
);
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
select[multiple] {
|
||||
height: 15em;
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 46 KiB |
|
@ -67,7 +67,7 @@
|
|||
<a class="dropdown-item" href="https://heyzine.com/flip-book/b2cf4809b7.html" target="_blank">{% trans "Year Book 2021" %}</a>
|
||||
</div>
|
||||
</li>
|
||||
{% if user.is_superuser or user.profile.is_chef or user.profile.is_chef_event or user.profile.is_chef_com or user.profile.is_chef_mu %}
|
||||
{% if user.is_superuser or user.profile.is_chef or user.profile.is_chef_event or user.profile.is_chef_com %}
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="{% url 'chef' %}" id="navbardrop" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<b>{% trans 'Le pouvoir des cheff·e·s'%}</b>
|
||||
|
@ -77,17 +77,17 @@
|
|||
<a class="dropdown-item" href="/admin/">{% trans "Administration" %}</a>
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef %}
|
||||
<a class="dropdown-item" href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a>
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef or user.profile.is_chef_event %}
|
||||
<a class="dropdown-item" href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a>
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef or user.profile.is_chef_com %}
|
||||
<a class="dropdown-item" href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a>
|
||||
<a class="dropdown-item" href="{% url 'liste_photo' %}">{% trans "Modifier les photos" %}</a>
|
||||
<a class="dropdown-item" href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a>
|
||||
|
||||
{% elif user.profile.is_chef_event %}
|
||||
<a class="dropdown-item" href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a>
|
||||
|
||||
{% elif user.profile.is_chef_com %}
|
||||
<a class="dropdown-item" href="{% url 'liste_photo' %}">{% trans "Modifier les photos" %}</a>
|
||||
<a class="dropdown-item" href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a>
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||
<a class="dropdown-item" href="{% url 'partitions:list_setlist' %}">{% trans "Gérer les programmes de répétition" %}</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
@ -145,10 +145,6 @@
|
|||
<!-- Footer -->
|
||||
<footer id="footer" style="background-color:rgb(228, 82, 47);">
|
||||
<div class="copyright">
|
||||
<ul class="icons">
|
||||
<li><a target="_blank" href="https://cvec.etudiant.gouv.fr/"><img alt="Logo de la CVEC" src='{% static "images/cvec.png" %}' width="100px"/></a></li>
|
||||
|
||||
</ul>
|
||||
<ul class="icons">
|
||||
<li><a target="_blank" href="https://www.facebook.com/ernestophone"
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
{% if user.profile.is_chef or user.is_superuser %}
|
||||
<li> <a href="/admin/">{% trans "Administration" %}</a></li>
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef %}
|
||||
<li><a href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a></li>
|
||||
|
@ -25,9 +24,6 @@
|
|||
<li><a href="{% url 'liste_photo' %}">{% trans "Modifier les photos" %}</a></li>
|
||||
<li><a href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a></li>
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||
<li> <a href="{% url 'partitions:list_setlist' %}">{% trans "Gérer les programmes de répétition" %}</a> </li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import os
|
||||
import random
|
||||
import string
|
||||
|
||||
|
@ -12,12 +11,12 @@ from django.urls import reverse_lazy
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import (CreateView, DeleteView, ListView,
|
||||
TemplateView, UpdateView)
|
||||
import os
|
||||
|
||||
from calendrier.forms import ChangeDoodleName
|
||||
from gestion.forms import (ChangeFormUser, ChangeMembreForm,
|
||||
InscriptionMembreForm, RegistrationFormUser)
|
||||
from gestion.mixins import (AllChefRequiredMixin, ChefComRequiredMixin,
|
||||
ChefRequiredMixin)
|
||||
from gestion.mixins import ChefRequiredMixin, AllChefRequiredMixin, ChefComRequiredMixin
|
||||
from gestion.models import ErnestoUser, Photo, VideoGallery
|
||||
from partitions.models import Category
|
||||
|
||||
|
@ -80,7 +79,6 @@ class Profil(LoginRequiredMixin, TemplateView):
|
|||
class Chef(AllChefRequiredMixin, TemplateView):
|
||||
template_name = "gestion/chef.html"
|
||||
|
||||
|
||||
class YearBook2021(TemplateView):
|
||||
template_name = "gestion/yearbook2021.html"
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.utils.safestring import mark_safe
|
|||
from django.views.generic import (CreateView, DeleteView, TemplateView,
|
||||
UpdateView)
|
||||
|
||||
from gestion.mixins import ChefInstruRequiredMixin, ChefRequiredMixin
|
||||
from gestion.mixins import ChefRequiredMixin, ChefInstruRequiredMixin
|
||||
from gestion.models import Photo
|
||||
from instruments.forms import ChefEditInstrumentForm, ChefReparationForm
|
||||
from instruments.models import Instrument, Reparation
|
||||
|
@ -28,17 +28,7 @@ class ListeInstru(LoginRequiredMixin, TemplateView):
|
|||
|
||||
class CreateInstru(ChefInstruRequiredMixin, CreateView):
|
||||
model = Instrument
|
||||
fields = [
|
||||
"owner",
|
||||
"user",
|
||||
"etat",
|
||||
"type",
|
||||
"marque",
|
||||
"model",
|
||||
"serial",
|
||||
"annee",
|
||||
"prix",
|
||||
]
|
||||
fields = ["owner","user", "etat", "type", "marque", "model", "serial", "annee", "prix"]
|
||||
template_name = "instruments/create_instru.html"
|
||||
success_url = reverse_lazy("instruments:liste")
|
||||
|
||||
|
@ -105,12 +95,11 @@ class FicheInstru(LoginRequiredMixin, TemplateView):
|
|||
def post(self, request, *args, **kwargs):
|
||||
instru = get_object_or_404(self.model, id=self.kwargs["pk"])
|
||||
form = ChefEditInstrumentForm(request.POST, instance=instru)
|
||||
if request.user.profile.is_chef or request.user.profile.is_chef_instru:
|
||||
if request.user.profile.is_chef:
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
context = self.get_context_data()
|
||||
context["form"] = form
|
||||
print(instru.user)
|
||||
return render(request, self.template_name, context)
|
||||
|
||||
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -4,7 +4,7 @@ from django.urls import reverse_lazy
|
|||
from django.utils import timezone
|
||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||
|
||||
from gestion.mixins import ChefEventRequiredMixin, ChefRequiredMixin
|
||||
from gestion.mixins import ChefRequiredMixin, ChefEventRequiredMixin
|
||||
from pads.models import Pad
|
||||
|
||||
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Category, Partition, PartitionSet, SetList
|
||||
|
||||
|
||||
class PartitionAdmin(admin.ModelAdmin):
|
||||
list_filter = ("morceau",)
|
||||
|
||||
from .models import Category, PartitionSet
|
||||
|
||||
admin.site.register(Category)
|
||||
admin.site.register(PartitionSet)
|
||||
admin.site.register(SetList)
|
||||
admin.site.register(Partition, PartitionAdmin)
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
# Generated by Django 2.2.25 on 2022-01-09 18:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("partitions", "0004_auto_20210331_1350"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="SetList",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("date", models.DateField(verbose_name="Date de la répétition")),
|
||||
(
|
||||
"is_current",
|
||||
models.CharField(
|
||||
choices=[("y", "Oui"), ("n", "Non")],
|
||||
default="y",
|
||||
max_length=1,
|
||||
verbose_name="Afficher le programme de répétition (les répétition vieilles de plus d'une semaine ne sont pas affiché d'office)",
|
||||
),
|
||||
),
|
||||
(
|
||||
"morceaux",
|
||||
models.ManyToManyField(
|
||||
to="partitions.PartitionSet",
|
||||
verbose_name="Morceaux de la répétition (ctrl ou cmd pour en selectionner plusieurs)",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
# Generated by Django 2.2.24 on 2022-01-18 14:25
|
||||
|
||||
import django.db.models.functions.text
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("partitions", "0005_setlist"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="partition",
|
||||
options={
|
||||
"ordering": (django.db.models.functions.text.Lower("nom"),),
|
||||
"verbose_name": "Partition",
|
||||
"verbose_name_plural": "Partitions",
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
# Generated by Django 2.2.24 on 2022-01-18 14:42
|
||||
|
||||
import django.db.models.functions.text
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("partitions", "0006_auto_20220118_1525"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="partitionset",
|
||||
options={
|
||||
"ordering": ("category", django.db.models.functions.text.Lower("nom")),
|
||||
"verbose_name": "Morceau",
|
||||
"verbose_name_plural": "Morceaux",
|
||||
},
|
||||
),
|
||||
]
|
|
@ -1,7 +1,6 @@
|
|||
import os
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.db import models
|
||||
from django.db.models.functions import Lower
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -34,8 +33,8 @@ class Partition(models.Model):
|
|||
super(Partition, self).delete(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Partition")
|
||||
verbose_name_plural = _("Partitions")
|
||||
verbose_name = _("Morceau")
|
||||
verbose_name_plural = _("Morceaux")
|
||||
ordering = (Lower("nom"),)
|
||||
|
||||
|
||||
|
@ -70,43 +69,4 @@ class PartitionSet(models.Model):
|
|||
class Meta:
|
||||
verbose_name = _("Morceau")
|
||||
verbose_name_plural = _("Morceaux")
|
||||
ordering = (
|
||||
"category",
|
||||
Lower("nom"),
|
||||
)
|
||||
|
||||
|
||||
from datetime import date as ddate
|
||||
from datetime import timedelta
|
||||
|
||||
|
||||
class SetList(models.Model):
|
||||
"""
|
||||
Modèle qui stocke les setlists de répétition (date et morceaux)
|
||||
"""
|
||||
|
||||
date = models.DateField(_("Date de la répétition"))
|
||||
is_current = models.CharField(
|
||||
verbose_name=_(
|
||||
"Afficher le programme de répétition (les répétition vieilles de plus d'une semaine ne sont pas affiché d'office)"
|
||||
),
|
||||
max_length=1,
|
||||
choices=(("y", "Oui"), ("n", "Non")),
|
||||
default="y",
|
||||
blank=False,
|
||||
)
|
||||
morceaux = models.ManyToManyField(
|
||||
"PartitionSet",
|
||||
verbose_name=_(
|
||||
"Morceaux de la répétition (ctrl ou cmd pour en selectionner plusieurs)"
|
||||
),
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return "%s - (%s)" % (
|
||||
self.date,
|
||||
", ".join(self.morceaux.all().values_list("nom", flat=True)),
|
||||
)
|
||||
|
||||
def is_visible(self):
|
||||
return self.is_current == "y" and self.date > ddate.today() - timedelta(days=7)
|
||||
ordering = (Lower("nom"),)
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<a href="{% url "partitions:listepart" partition.nom partition.auteur %}"
|
||||
class="fichier">{{ partition.nom }} - {{ partition.auteur }}</a>
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||
{% if user.profile.is_chef %}
|
||||
<a href="{% url "partitions:conf_delete_morc" partition.nom partition.auteur %}"
|
||||
class="supprimer">Supprimer</a>
|
||||
{% endif %}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{% endif %}
|
||||
|
||||
<div class="info_part">
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||
{% if user.profile.is_chef %}
|
||||
<form action="{% url "partitions:listepart" nom auteur %}" id="chef-edit-form" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
@ -40,7 +40,7 @@
|
|||
<a href="{% url "partitions:download" nom auteur p.id %}" class="telecharger">Télécharger</a>
|
||||
{% endif %}
|
||||
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||
{% if user.profile.is_chef %}
|
||||
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="supprimer">Supprimer</a>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -28,17 +28,15 @@
|
|||
<tbody>
|
||||
{% for p in part %}
|
||||
{% if user.is_authenticated and ".mscz" in p.part.url %}
|
||||
<tr>
|
||||
<td><p class="fichier">{{ p.nom }}</p></td>
|
||||
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<td> <a href="{% url "partitions:download" nom auteur p.id %}" class="button icon fa-download">{% trans "Télécharger" %}</a></td>
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %} <td>
|
||||
{% if user.profile.is_chef %} <td>
|
||||
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="button icon fa-deleate">{% trans "Supprimer" %}</a></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% for p in part %}
|
||||
|
@ -56,7 +54,7 @@
|
|||
{% if user.is_authenticated %}
|
||||
<td> <a href="{% url "partitions:download" nom auteur p.id %}" class="button icon fa-download">{% trans "Télécharger" %}</a></td>
|
||||
{% endif %}
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %} <td>
|
||||
{% if user.profile.is_chef %} <td>
|
||||
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="button icon fa-deleate">{% trans "Supprimer" %}</a></td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
|
@ -67,7 +65,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||
{% if user.profile.is_chef %}
|
||||
<p><a href="{% url "partitions:upload" p.nom p.auteur %}" class='button'>{% trans "Ajouter un média" %}</a></p>
|
||||
|
||||
{% if infos or infos_en %}
|
||||
|
@ -88,7 +86,7 @@
|
|||
<p></p>
|
||||
</div>
|
||||
<div class="6u 12u$(small)">
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||
{% if user.profile.is_chef %}
|
||||
<form action="{% url "partitions:listepart" nom auteur %}" id="chef-edit-form" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
|
|
@ -7,20 +7,6 @@
|
|||
{% block content %}
|
||||
<div id="main">
|
||||
<section class="wrapper style1">
|
||||
{% if user.is_authenticated and setlists %}
|
||||
<div class="inner">
|
||||
<div class="box" style="background-color:rgba(228,82,47,0.5)">
|
||||
{% for set_list in setlists %}
|
||||
<h4>{% blocktrans with set_list_date=set_list.date %}Programme de répétition de la semaine du {{ set_list_date }}: {% endblocktrans %}</h4>
|
||||
<ul class="pl-5">
|
||||
{% for morceau in set_list.morceaux.all %}
|
||||
<li><a href="{% url "partitions:listepart" morceau.nom morceau.auteur %}">{{ morceau.nom }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="inner">
|
||||
|
||||
<span class="image fit">
|
||||
|
@ -37,7 +23,7 @@
|
|||
<div class="icon fa-copyright" style="color:#000000"> Lucas Gierzack</div></div>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||
{% if user.profile.is_chef %}
|
||||
<a href="{% url "partitions:ajouter_morceau" %}" class="button alt big">{% trans "Ajouter un morceau" %}</a>   <a href="{% url "partitions:download_musecores" %}" class="button alt big">{% trans "Télécharger tous les musecores actifs" %}</a>
|
||||
{% elif user.is_authenticated %}
|
||||
<a href="{% url "partitions:download_musecores" %}" class="button alt big">{% trans "Télécharger tous les musecores actifs" %}</a>
|
||||
|
@ -80,7 +66,7 @@
|
|||
<td> <u><a href="{% url "partitions:listepart" partition.nom partition.auteur %}"
|
||||
class="fichier">{{ partition.nom }}</a> </td>
|
||||
<td> {{ partition.auteur }} </a></u> </td>
|
||||
{% if user.profile.is_chef or user.profile.is_chef_mu %}<td>
|
||||
{% if user.profile.is_chef %}<td>
|
||||
|
||||
<a href="{% url "partitions:conf_delete_morc" partition.nom partition.auteur %}"
|
||||
class="button small icon fa-trash">{% trans "Supprimer" %}</a></td>
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
{% extends "gestion/base.html" %}
|
||||
{% load i18n %}
|
||||
{% get_current_language as current_language %}
|
||||
{% load autotranslate %}
|
||||
{% block titre %}{% trans "Supprimer un programme de répétition" %}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div id="main">
|
||||
<section class="wrapper style1">
|
||||
<div class="inner">
|
||||
<h4>{% blocktrans with set_list_date=setlist.date %} Supprimer le programme de répétition du {{ set_list_date }} :{% endblocktrans %}</h4>
|
||||
<p>{% blocktrans with set_list=setlist %}Êtes-vous sûr.e de vouloir supprimer cette répétition : {{ set_list }}?{% endblocktrans %}</p>
|
||||
<form action="" method="POST">
|
||||
{% csrf_token %}
|
||||
<input class="button alt" type="submit" value="{% trans "Oui" %}">
|
||||
<a class="button alt" href="{% url 'partitions:list_setlist' %}">{% trans "Retour" %}</a>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,18 +0,0 @@
|
|||
{% extends "gestion/base.html" %}
|
||||
{% load i18n %}
|
||||
{%block titre %}{% trans "Ajout/modification d'un programme de répétition" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="main">
|
||||
<section class="wrapper style1">
|
||||
<div class="inner">
|
||||
<p><a href="{% url "partitions:list_setlist" %}" class="button alt">{% trans "Retour à la liste" %}</a></p>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="{% trans "Enregistrer" %}" />
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,31 +0,0 @@
|
|||
{% extends "gestion/base.html" %}
|
||||
{% load i18n %}
|
||||
{% get_current_language as current_language %}
|
||||
{% load autotranslate %}
|
||||
{% block titre %}{% trans "Liste des programmes de répétition" %}{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div id="main">
|
||||
<section class="wrapper style1">
|
||||
<div class="inner">
|
||||
<h4>{% trans "Liste des programmes de répétition" %} :</h4>
|
||||
|
||||
|
||||
<p><a href="{% url 'partitions:create_setlist' %}" class="button">{% trans "Ajouter un programme de répétition" %}</a></p>
|
||||
|
||||
<ul class="filelist">
|
||||
{% for a in setlist_list %}
|
||||
<li>
|
||||
<p>{% if a.is_visible %}[VISIBLE] - {% endif %}{{ a }}
|
||||
<a class="button alt" href="{% url 'partitions:update_setlist' a.pk %}">{% trans "Modifier" %}</a>
|
||||
<a class="button alt" href="{% url 'partitions:delete_setlist' a.pk %}">{% trans "Supprimer" %}</a></p>
|
||||
</li>
|
||||
|
||||
{% empty %}
|
||||
<p>{% trans "Pas de programme de répétition pour le moment" %}</p>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -6,14 +6,6 @@ app_name = "partitions"
|
|||
urlpatterns = [
|
||||
path("", views.Repertoire.as_view(), name="liste"),
|
||||
path("download", views.download_musecores, name="download_musecores"),
|
||||
path("setlist/", views.SetListListView.as_view(), name="list_setlist"),
|
||||
path("setlist/create", views.SetListCreate.as_view(), name="create_setlist"),
|
||||
path(
|
||||
"setlist/<int:pk>/update", views.SetListUpdate.as_view(), name="update_setlist"
|
||||
),
|
||||
path(
|
||||
"setlist/<int:pk>/delete", views.SetListDelete.as_view(), name="delete_setlist"
|
||||
),
|
||||
path("<str:nom>/<str:auteur>/upload", views.Upload.as_view(), name="upload"),
|
||||
path("<str:nom>/<str:auteur>", views.Morceau.as_view(), name="listepart"),
|
||||
path("<str:nom>/<str:auteur>/see/<int:partition_id>", views.see, name="see"),
|
||||
|
|
|
@ -7,17 +7,15 @@ from django.core.files import File
|
|||
from django.db.models import Q
|
||||
from django.http import Http404
|
||||
from django.shortcuts import HttpResponse, get_object_or_404, redirect, render
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import (CreateView, DeleteView, ListView,
|
||||
TemplateView, UpdateView)
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from gestion.mixins import ChefMuRequiredMixin
|
||||
from gestion.mixins import ChefRequiredMixin
|
||||
from gestion.models import Photo
|
||||
from partitions.forms import UploadFileForm, UploadMorceauForm
|
||||
from partitions.models import Category, Partition, PartitionSet, SetList
|
||||
from partitions.models import Category, Partition, PartitionSet
|
||||
|
||||
from .forms import ChefEditMorceauForm
|
||||
|
||||
|
@ -71,21 +69,11 @@ def download_musecores(request):
|
|||
return resp
|
||||
|
||||
|
||||
from datetime import date, timedelta
|
||||
|
||||
|
||||
class Repertoire(TemplateView):
|
||||
template_name = "partitions/repertoire.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["setlists"] = (
|
||||
SetList.objects.filter(
|
||||
is_current="y", date__gt=(date.today() - timedelta(days=7))
|
||||
)
|
||||
.order_by("date")
|
||||
.prefetch_related("morceaux")
|
||||
)
|
||||
context["categories"] = Category.objects.prefetch_related(
|
||||
"partitionset_set"
|
||||
).order_by("order")
|
||||
|
@ -106,6 +94,7 @@ class Morceau(LoginRequiredMixin, TemplateView):
|
|||
form = self.form_class(instance=p)
|
||||
infos = mark_safe(p.infos)
|
||||
infos_en = mark_safe(p.infos_en)
|
||||
|
||||
context["p"] = p
|
||||
context["infos"] = infos
|
||||
context["infos_en"] = infos_en
|
||||
|
@ -128,7 +117,7 @@ class Morceau(LoginRequiredMixin, TemplateView):
|
|||
return render(request, self.template_name, context)
|
||||
|
||||
|
||||
class Upload(ChefMuRequiredMixin, TemplateView):
|
||||
class Upload(ChefRequiredMixin, TemplateView):
|
||||
form_class = UploadFileForm
|
||||
template_name = "partitions/upload.html"
|
||||
|
||||
|
@ -208,7 +197,7 @@ def see(request, nom, auteur, partition_id):
|
|||
return redirect("login")
|
||||
|
||||
|
||||
class DeletePart(ChefMuRequiredMixin, TemplateView):
|
||||
class DeletePart(ChefRequiredMixin, TemplateView):
|
||||
model = PartitionSet
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
@ -225,7 +214,7 @@ class DeletePart(ChefMuRequiredMixin, TemplateView):
|
|||
)
|
||||
|
||||
|
||||
class CreateMorc(ChefMuRequiredMixin, TemplateView):
|
||||
class CreateMorc(ChefRequiredMixin, TemplateView):
|
||||
form_class = UploadMorceauForm
|
||||
template_name = "partitions/new.html"
|
||||
|
||||
|
@ -270,7 +259,7 @@ class CreateMorc(ChefMuRequiredMixin, TemplateView):
|
|||
return render(request, self.template_name, context)
|
||||
|
||||
|
||||
class ConfDelete(ChefMuRequiredMixin, TemplateView):
|
||||
class ConfDelete(ChefRequiredMixin, TemplateView):
|
||||
template_name = "partitions/conf_delete.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -281,7 +270,7 @@ class ConfDelete(ChefMuRequiredMixin, TemplateView):
|
|||
return context
|
||||
|
||||
|
||||
class DeleteMorc(ChefMuRequiredMixin, TemplateView):
|
||||
class DeleteMorc(ChefRequiredMixin, TemplateView):
|
||||
model = PartitionSet
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
@ -295,7 +284,7 @@ class DeleteMorc(ChefMuRequiredMixin, TemplateView):
|
|||
return redirect("partitions:liste")
|
||||
|
||||
|
||||
class ConfDeleteMorc(ChefMuRequiredMixin, TemplateView):
|
||||
class ConfDeleteMorc(ChefRequiredMixin, TemplateView):
|
||||
template_name = "partitions/conf_delete_morc.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
@ -324,27 +313,3 @@ def download(request, nom, auteur, partition_id):
|
|||
return response
|
||||
else:
|
||||
return redirect("login")
|
||||
|
||||
|
||||
class SetListListView(ChefMuRequiredMixin, ListView):
|
||||
model = SetList
|
||||
|
||||
def get_queryset(self):
|
||||
return SetList.objects.all().order_by("-date")
|
||||
|
||||
|
||||
class SetListCreate(ChefMuRequiredMixin, CreateView):
|
||||
model = SetList
|
||||
fields = ["date", "morceaux", "is_current"]
|
||||
success_url = reverse_lazy("partitions:list_setlist")
|
||||
|
||||
|
||||
class SetListUpdate(ChefMuRequiredMixin, UpdateView):
|
||||
model = SetList
|
||||
fields = ["date", "morceaux", "is_current"]
|
||||
success_url = reverse_lazy("partitions:list_setlist")
|
||||
|
||||
|
||||
class SetListDelete(ChefMuRequiredMixin, DeleteView):
|
||||
model = SetList
|
||||
success_url = reverse_lazy("partitions:list_setlist")
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gestion', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Prop',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
|
||||
('nom', models.CharField(max_length=100)),
|
||||
('artiste', models.CharField(max_length=100, blank=True)),
|
||||
('lien', models.URLField(blank=True)),
|
||||
('nboui', models.IntegerField(verbose_name='oui', default=0)),
|
||||
('nbnon', models.IntegerField(verbose_name='non', default=0)),
|
||||
('user', models.ForeignKey(verbose_name='Proposé par', to='gestion.ErnestoUser', on_delete=models.CASCADE)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Proposition',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Reponses',
|
||||
fields=[
|
||||
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
|
||||
('reponse', models.CharField(verbose_name='Réponse', choices=[('oui', 'Oui'), ('non', 'Non')], max_length=20, blank=True)),
|
||||
('part', models.ForeignKey(to='gestion.ErnestoUser', on_delete=models.CASCADE)),
|
||||
('prop', models.ForeignKey(to='propositions.Prop', on_delete=models.CASCADE)),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.2.9 on 2020-01-04 23:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('propositions', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='prop',
|
||||
name='nom',
|
||||
field=models.CharField(max_length=100, verbose_name='nom du morceau'),
|
||||
),
|
||||
]
|
|
@ -1,75 +0,0 @@
|
|||
# Generated by Django 2.2.9 on 2020-01-05 13:32
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def move_profile_to_user(apps, schema_editor):
|
||||
Reponses = apps.get_model("propositions", "reponses")
|
||||
for answer in Reponses.objects.all():
|
||||
answer.user = answer.part.user
|
||||
answer.save()
|
||||
|
||||
|
||||
def move_user_to_profile(apps, schema_editor):
|
||||
# One should do something similar to ``move_profile_to_user`` AND make the
|
||||
# ``part`` field temporarily nullable in the operations below.
|
||||
# => Grosse flemme
|
||||
raise NotImplementedError("Who uses migrations backwards anyway?")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("gestion", "0001_initial"),
|
||||
("propositions", "0002_nom_verbose_name"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="reponses",
|
||||
options={
|
||||
"verbose_name": "Réponse à une proposition",
|
||||
"verbose_name_plural": "Réponses à une proposition",
|
||||
},
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="reponses", old_name="prop", new_name="proposition",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="reponses",
|
||||
name="user",
|
||||
field=models.ForeignKey(
|
||||
on_delete=models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.RunPython(move_profile_to_user, move_user_to_profile),
|
||||
migrations.AlterField(
|
||||
model_name="reponses",
|
||||
name="user",
|
||||
field=models.ForeignKey(
|
||||
on_delete=models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
null=False,
|
||||
),
|
||||
),
|
||||
migrations.RemoveField(model_name="reponses", name="part"),
|
||||
migrations.AddField(
|
||||
model_name="reponses",
|
||||
name="answer",
|
||||
field=models.CharField(
|
||||
choices=[("oui", "Oui"), ("non", "Non")],
|
||||
default="non",
|
||||
max_length=3,
|
||||
verbose_name="Réponse",
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name="reponses", unique_together={("proposition", "user")},
|
||||
),
|
||||
migrations.RemoveField(model_name="reponses", name="reponse",),
|
||||
migrations.RenameModel(old_name="reponses", new_name="answer"),
|
||||
]
|
|
@ -1,43 +0,0 @@
|
|||
# Generated by Django 2.2.9 on 2020-01-05 14:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("propositions", "0003_reponse_renaming_and_cleaning"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="prop",
|
||||
options={
|
||||
"verbose_name": "Proposition de morceau",
|
||||
"verbose_name_plural": "Propositions de morceaux",
|
||||
},
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name="prop", old_name="artiste", new_name="artist",
|
||||
),
|
||||
migrations.RenameField(model_name="prop", old_name="lien", new_name="link"),
|
||||
migrations.RenameField(model_name="prop", old_name="nom", new_name="name"),
|
||||
migrations.RenameField(model_name="prop", old_name="nbnon", new_name="nb_no"),
|
||||
migrations.RenameField(model_name="prop", old_name="nboui", new_name="nb_yes"),
|
||||
migrations.AlterField(
|
||||
model_name="prop",
|
||||
name="nb_no",
|
||||
field=models.IntegerField(default=0, verbose_name="nombre de réponses non"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="prop",
|
||||
name="nb_yes",
|
||||
field=models.IntegerField(default=0, verbose_name="nombre de réponses oui"),
|
||||
),
|
||||
migrations.RenameModel(old_name="prop", new_name="proposition"),
|
||||
migrations.AlterField(
|
||||
model_name='answer',
|
||||
name='proposition',
|
||||
field=models.ForeignKey(on_delete=models.deletion.CASCADE, to='propositions.Proposition'),
|
||||
),
|
||||
]
|
|
@ -1,24 +0,0 @@
|
|||
# Generated by Django 2.2.9 on 2020-01-05 15:26
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("propositions", "0004_prop_renaming_and_cleaning"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(model_name="proposition", name="nb_no",),
|
||||
migrations.RemoveField(model_name="proposition", name="nb_yes",),
|
||||
migrations.AlterField(
|
||||
model_name="answer",
|
||||
name="proposition",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="propositions.Proposition",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1,53 +0,0 @@
|
|||
# Generated by Django 2.2.9 on 2020-01-05 16:28
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def move_profile_to_user(apps, schema_editor):
|
||||
Proposition = apps.get_model("propositions", "Proposition")
|
||||
for proposition in Proposition.objects.all():
|
||||
proposition.user = proposition.profile.user
|
||||
proposition.save()
|
||||
|
||||
|
||||
def move_user_to_profile(apps, schema_editor):
|
||||
# One should do something similar to ``move_profile_to_user`` AND make the
|
||||
# ``profile`` field temporarily nullable in the operations below.
|
||||
# => Grosse flemme
|
||||
raise NotImplementedError("Who uses migrations backwards anyway?")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("propositions", "0005_remove_nb_yes_no_fields"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="proposition", old_name="user", new_name="profile"
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="proposition",
|
||||
name="user",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Proposé par",
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.RunPython(move_profile_to_user, move_user_to_profile),
|
||||
migrations.RemoveField(model_name="proposition", name="profile"),
|
||||
migrations.AlterField(
|
||||
model_name="proposition",
|
||||
name="user",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Proposé par",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1,19 +0,0 @@
|
|||
# Generated by Django 2.2.27 on 2022-03-22 13:55
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('propositions', '0006_proposition_profile_to_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='answer',
|
||||
name='proposition',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='propositions.Proposition'),
|
||||
),
|
||||
]
|
|
@ -1,19 +0,0 @@
|
|||
# Generated by Django 2.2.27 on 2022-09-14 10:44
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('propositions', '0007_auto_20220322_1455'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='answer',
|
||||
name='proposition',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='propositions.Proposition'),
|
||||
),
|
||||
]
|
|
@ -1,19 +0,0 @@
|
|||
# Generated by Django 2.2.28 on 2024-06-15 13:03
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('propositions', '0008_auto_20220914_1244'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='answer',
|
||||
name='proposition',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='propositions.Proposition'),
|
||||
),
|
||||
]
|
|
@ -1,34 +0,0 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.db import models
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class Proposition(models.Model):
|
||||
name = models.CharField(max_length=100, verbose_name="nom du morceau")
|
||||
artist = models.CharField(blank=True, max_length=100)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Proposé par")
|
||||
link = models.URLField(blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Proposition de morceau"
|
||||
verbose_name_plural = "Propositions de morceaux"
|
||||
|
||||
|
||||
class Answer(models.Model):
|
||||
YES = "oui"
|
||||
NO = "non"
|
||||
|
||||
REP_CHOICES = [(YES, "Oui"), (NO, "Non")]
|
||||
|
||||
proposition = models.ForeignKey(Proposition, on_delete=models.CASCADE)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
answer = models.CharField("Réponse", max_length=3, choices=REP_CHOICES)
|
||||
|
||||
class Meta:
|
||||
unique_together = ("proposition", "user")
|
||||
verbose_name = "Réponse à une proposition"
|
||||
verbose_name_plural = "Réponses à une proposition"
|
|
@ -1,14 +0,0 @@
|
|||
{% extends "gestion/base.html" %}
|
||||
|
||||
{% block titre %}Proposition de morceau{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p><a href="{% url "propositions:list" %}">Retour aux propositions</a></p>
|
||||
<form action="{% url "propositions:create" %}" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<input type="submit" value="Enregistrer" />
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -1,10 +0,0 @@
|
|||
{% extends "gestion/base.html" %}
|
||||
|
||||
{% block titre %}Suppression d'une proposition{% endblock %}
|
||||
{% block content %}<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<p><a href="{% url "propositions:list" %}">Retour aux propositions</a></p>
|
||||
<p>Voulez vous vraiment supprimer la proposition {{ object }}?</p>
|
||||
<input type="submit" value="Oui" />
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,44 +0,0 @@
|
|||
{% extends "gestion/base.html" %}
|
||||
|
||||
{% block titre %}Propositions de morceau{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Liste des propositions</h1>
|
||||
|
||||
<p><a href="{% url "propositions:create" %}">Proposer un morceau</a></p>
|
||||
|
||||
{% if propositions.exists %}
|
||||
<table>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Oui</th>
|
||||
<th>Non</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% for p in propositions %}
|
||||
<tr class="prop">
|
||||
<td>
|
||||
{% if p.link %}<a href={{ p.link }}>{% endif %}
|
||||
<b>{{ p.name }}</b>{% if p.artist %} - {{ p.artist }}{% endif %}
|
||||
{% if p.link %}</a>{% endif %}
|
||||
</td>
|
||||
<td>{{ p.nb_yes }}</td>
|
||||
<td>{{ p.nb_no }}</td>
|
||||
<td><a href="{% url "propositions:oui" p.id %}">Oui</a></td>
|
||||
<td><a href="{% url "propositions:non" p.id %}">Non</a></td>
|
||||
<td>{% if p.user_answer %}Vous avez voté {{ p.user_answer }}{% endif %}</td>
|
||||
<td>
|
||||
{% if p.user == request.user or request.user.profile.is_chef %}
|
||||
<a class="supprimer" href="{% url "propositions:delete" p.id %}">Supprimer</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% else %}
|
||||
Pas de proposition pour le moment
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -1,165 +0,0 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse_lazy, reverse
|
||||
|
||||
from gestion.models import ErnestoUser
|
||||
from propositions.models import Answer, Proposition
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
def new_user(username):
|
||||
u = User.objects.create_user(username=username)
|
||||
ErnestoUser.objects.create(user=u, slug=username, is_ernesto=True)
|
||||
return u
|
||||
|
||||
|
||||
class PropositionCreateTest(TestCase):
|
||||
url = reverse_lazy("propositions:create")
|
||||
|
||||
def test_anonymous_cannot_get(self):
|
||||
response = Client().get(self.url)
|
||||
self.assertRedirects(response, "/login?next={}".format(self.url))
|
||||
|
||||
def test_ernesto_user_can_get(self):
|
||||
user = new_user("toto")
|
||||
client = Client()
|
||||
client.force_login(user)
|
||||
|
||||
response = client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_ernesto_user_can_post(self):
|
||||
user = new_user("toto")
|
||||
client = Client()
|
||||
client.force_login(user)
|
||||
|
||||
data = {"name": "foo", "artist": "bar", "link": "example.com"}
|
||||
client.post(self.url, data)
|
||||
proposition = Proposition.objects.all()
|
||||
self.assertEqual(1, proposition.count())
|
||||
|
||||
proposition = proposition.get()
|
||||
self.assertEqual(proposition.name, "foo")
|
||||
self.assertEqual(proposition.artist, "bar")
|
||||
self.assertEqual(proposition.link, "http://example.com")
|
||||
self.assertEqual(proposition.user, user)
|
||||
|
||||
|
||||
class PropositionDeleteTest(TestCase):
|
||||
def setUp(self):
|
||||
self.owner = new_user("owner")
|
||||
self.random_user = new_user("toto")
|
||||
self.chef = new_user("chef")
|
||||
self.chef.profile.is_chef = True
|
||||
self.chef.profile.save()
|
||||
|
||||
proposition = Proposition.objects.create(name="prop", user=self.owner)
|
||||
self.url = reverse("propositions:delete", args=(proposition.id,))
|
||||
|
||||
def test_anonymous_cannot_get(self):
|
||||
response = Client().get(self.url)
|
||||
self.assertRedirects(response, "/login?next={}".format(self.url))
|
||||
|
||||
def test_anonymous_cannot_post(self):
|
||||
response = Client().post(self.url, {})
|
||||
self.assertRedirects(response, "/login?next={}".format(self.url))
|
||||
self.assertTrue(Proposition.objects.exists())
|
||||
|
||||
def test_random_user_cannot_get(self):
|
||||
client = Client()
|
||||
client.force_login(self.random_user)
|
||||
response = client.get(self.url)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
def test_not_owner_cannot_post(self):
|
||||
client = Client()
|
||||
client.force_login(self.random_user)
|
||||
response = client.post(self.url, {})
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertTrue(Proposition.objects.exists())
|
||||
|
||||
def test_chef_can_get(self):
|
||||
client = Client()
|
||||
client.force_login(self.chef)
|
||||
response = client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_chef_can_post(self):
|
||||
client = Client()
|
||||
client.force_login(self.chef)
|
||||
client.post(self.url, {})
|
||||
self.assertFalse(Proposition.objects.exists())
|
||||
|
||||
def test_owner_can_get(self):
|
||||
client = Client()
|
||||
client.force_login(self.owner)
|
||||
response = client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_owner_can_post(self):
|
||||
client = Client()
|
||||
client.force_login(self.owner)
|
||||
client.post(self.url, {})
|
||||
self.assertFalse(Proposition.objects.exists())
|
||||
|
||||
|
||||
class PropositionListTest(TestCase):
|
||||
url = reverse_lazy("propositions:list")
|
||||
|
||||
def setUp(self):
|
||||
self.user = new_user("toto")
|
||||
for name in ["foo", "bar", "baz"]:
|
||||
p = Proposition.objects.create(name=name, user=self.user)
|
||||
Answer.objects.create(proposition=p, user=self.user, answer=Answer.YES)
|
||||
for name in ["oof", "rab", "zab"]:
|
||||
p = Proposition.objects.create(name=name, user=self.user)
|
||||
Answer.objects.create(proposition=p, user=self.user, answer=Answer.NO)
|
||||
|
||||
def test_anonymous_cannot_get(self):
|
||||
response = Client().get(self.url)
|
||||
self.assertRedirects(response, "/login?next={}".format(self.url))
|
||||
|
||||
def test_ernesto_user_can_get(self):
|
||||
client = Client()
|
||||
client.force_login(self.user)
|
||||
|
||||
response = client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class ReponseTest(TestCase):
|
||||
def setUp(self):
|
||||
self.user = new_user("toto")
|
||||
self.prop = Proposition.objects.create(name="foo", user=self.user)
|
||||
|
||||
def _url(self, rep):
|
||||
assert rep in Answer.REP_CHOICES
|
||||
return reverse("propositions:{}".format(rep), args=(self.prop.id,))
|
||||
|
||||
def test_anonymous_cannot_get(self):
|
||||
client = Client()
|
||||
|
||||
url = reverse("propositions:oui", args=(self.prop.id,))
|
||||
response = client.get(url)
|
||||
self.assertRedirects(response, "/login?next={}".format(url))
|
||||
|
||||
url = reverse("propositions:non", args=(self.prop.id,))
|
||||
response = client.get(url)
|
||||
self.assertRedirects(response, "/login?next={}".format(url))
|
||||
|
||||
def test_ernesto_user_can_get(self):
|
||||
client = Client()
|
||||
client.force_login(self.user)
|
||||
|
||||
client.get(reverse("propositions:oui", args=(self.prop.id,)))
|
||||
self.prop.refresh_from_db()
|
||||
self.assertEqual(
|
||||
list(self.prop.answer_set.values_list("answer", flat=True)), [Answer.YES],
|
||||
)
|
||||
|
||||
client.get(reverse("propositions:non", args=(self.prop.id,)))
|
||||
self.prop.refresh_from_db()
|
||||
self.assertEqual(
|
||||
list(self.prop.answer_set.values_list("answer", flat=True)), [Answer.NO]
|
||||
)
|
|
@ -1,13 +0,0 @@
|
|||
from django.urls import path
|
||||
|
||||
from propositions import views
|
||||
from propositions.models import Answer
|
||||
|
||||
app_name = "propositions"
|
||||
urlpatterns = [
|
||||
path("", views.PropositionList.as_view(), name="list"),
|
||||
path("new", views.PropositionCreate.as_view(), name="create"),
|
||||
path("<int:id>/oui", views.answer, {"ans": "oui"}, name=Answer.YES),
|
||||
path("<int:id>/non", views.answer, {"ans": "non"}, name=Answer.NO),
|
||||
path("<int:pk>/supprimer", views.PropositionDelete.as_view(), name="delete"),
|
||||
]
|
|
@ -1,8 +0,0 @@
|
|||
import string
|
||||
import random
|
||||
|
||||
|
||||
def generer(*args):
|
||||
caracteres = string.ascii_letters + string.digits
|
||||
aleatoire = [random.choice(caracteres) for _ in range(6)]
|
||||
return ''.join(aleatoire)
|
|
@ -1,63 +0,0 @@
|
|||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.urls import reverse_lazy
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
from django.db.models import Count, OuterRef, Q, Subquery
|
||||
from django.views.generic import CreateView, DeleteView, ListView
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
from propositions.models import Answer, Proposition
|
||||
|
||||
|
||||
class PropositionCreate(LoginRequiredMixin, CreateView):
|
||||
template_name = "propositions/create.html"
|
||||
success_url = reverse_lazy("propositions:list")
|
||||
model = Proposition
|
||||
fields = ["name", "artist", "link"]
|
||||
|
||||
def form_valid(self, form):
|
||||
proposition = form.save(commit=False)
|
||||
proposition.user = self.request.user
|
||||
proposition.save()
|
||||
return HttpResponseRedirect(self.success_url)
|
||||
|
||||
|
||||
class PropositionList(LoginRequiredMixin, ListView):
|
||||
template_name = "propositions/liste.html"
|
||||
context_object_name = "propositions"
|
||||
model = Proposition
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
user_answers = (
|
||||
Answer.objects
|
||||
.filter(proposition=OuterRef("id"), user=user)
|
||||
.values_list("answer", flat=True)
|
||||
)
|
||||
return (
|
||||
Proposition.objects
|
||||
.annotate(nb_yes=Count("answer", filter=Q(answer__answer=Answer.YES)))
|
||||
.annotate(nb_no=Count("answer", filter=Q(answer__answer=Answer.NO)))
|
||||
.annotate(user_answer=Subquery(user_answers[:1]))
|
||||
.order_by("-nb_yes", "nb_no", "name")
|
||||
)
|
||||
|
||||
|
||||
class PropositionDelete(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
|
||||
model = Proposition
|
||||
template_name = "propositions/delete.html"
|
||||
success_url = reverse_lazy("propositions:list")
|
||||
|
||||
def test_func(self):
|
||||
proposition = self.get_object()
|
||||
user = self.request.user
|
||||
return (proposition.user == user or user.profile.is_chef)
|
||||
|
||||
|
||||
@login_required
|
||||
def answer(request, id, ans):
|
||||
proposition = get_object_or_404(Proposition, id=id)
|
||||
user = request.user
|
||||
Answer.objects.filter(proposition=proposition, user=user).delete()
|
||||
Answer.objects.create(proposition=proposition, user=user, answer=ans)
|
||||
return redirect("propositions:list")
|
|
@ -1,8 +1,8 @@
|
|||
Django==2.2.28
|
||||
django-appconf==1.0.4
|
||||
django-avatar==5.0.0
|
||||
django-colorful==1.3
|
||||
gunicorn==20.1.0
|
||||
Pillow==9.2.0
|
||||
#Pour le prod
|
||||
#psycopg2==2.8.6
|
||||
Django==2.2.*
|
||||
|
||||
# Pour la prod
|
||||
#psycopg2
|
||||
gunicorn
|
||||
django-colorful
|
||||
Pillow
|
||||
django-avatar==5.0.*
|
||||
|
|
Loading…
Reference in a new issue