Compare commits
47 commits
ajout_comm
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
f886f3c98f | ||
|
02d07cb83d | ||
|
fbb7cbe11a | ||
|
98a6f98fda | ||
|
0aae767a3e | ||
|
d88768311e | ||
|
abc6c62a89 | ||
|
3e065f30c0 | ||
|
0ee798a64e | ||
|
1e8b993739 | ||
|
8398805b54 | ||
|
56d7490879 | ||
|
aa430fa4d2 | ||
|
5eb27e2171 | ||
|
31f6dc0961 | ||
|
764ffea61f | ||
|
7122c1c0c4 | ||
|
14e8d963d6 | ||
|
99e3438ead | ||
|
8a36b051a1 | ||
|
07d2e30b32 | ||
|
f88ed9ece6 | ||
|
5062a1e84e | ||
|
bc7430cb5d | ||
|
a7851ff123 | ||
|
50f888a07c | ||
|
343eaeb72e | ||
|
5aebd7bbe1 | ||
|
cb2577c04b | ||
|
bd42fe6fb9 | ||
|
bbff984513 | ||
|
9aed5d1758 | ||
|
f961722fa8 | ||
|
904f9fc74a | ||
|
280e0c625d | ||
|
8e6ca0cc86 | ||
|
0673e64083 | ||
|
82bc6c1e1b | ||
|
26bd2484a2 | ||
|
4d8b97c2cb | ||
|
b62d6f47a4 | ||
|
10159393f1 | ||
|
d217a74da5 | ||
|
079e0d1c3f | ||
|
45fdd4683b | ||
|
95cf80c234 | ||
|
e6f9173c62 |
81 changed files with 1941 additions and 502 deletions
1
.credentials/SECRET_KEY
Normal file
1
.credentials/SECRET_KEY
Normal file
|
@ -0,0 +1 @@
|
||||||
|
insecure-secret_key
|
|
@ -1,40 +1,28 @@
|
||||||
import os
|
from pathlib import Path
|
||||||
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from loadcredential import Credentials
|
||||||
|
|
||||||
try:
|
credentials = Credentials(env_prefix="ERNESTOPHONE_")
|
||||||
from . import secret
|
|
||||||
except ImportError:
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
raise ImportError(
|
|
||||||
"The secret.py file is missing.\n"
|
DEBUG = credentials.get_json("DEBUG", False)
|
||||||
"For a development environment, simply copy secret_example.py"
|
|
||||||
)
|
ALLOWED_HOSTS = credentials.get_json("ALLOWED_HOSTS", [])
|
||||||
|
|
||||||
|
SECRET_KEY = credentials["SECRET_KEY"]
|
||||||
|
|
||||||
|
ADMINS = credentials.get_json("ADMINS", [])
|
||||||
|
|
||||||
|
SERVER_EMAIL = credentials.get("SERVER_EMAIL", "ernesto@localhost")
|
||||||
|
|
||||||
|
|
||||||
def import_secret(name):
|
ACCOUNT_CREATION_PASS = credentials.get("ACCOUNT_CREATION_PASS", "dummy")
|
||||||
"""
|
|
||||||
Shorthand for importing a value from the secret module and raising an
|
|
||||||
informative exception if a secret is missing.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return getattr(secret, name)
|
|
||||||
except AttributeError:
|
|
||||||
raise RuntimeError("Secret missing: {}".format(name))
|
|
||||||
|
|
||||||
|
|
||||||
SECRET_KEY = import_secret("SECRET_KEY")
|
|
||||||
ADMINS = import_secret("ADMINS")
|
|
||||||
SERVER_EMAIL = import_secret("SERVER_EMAIL")
|
|
||||||
|
|
||||||
DBNAME = import_secret("DBNAME")
|
|
||||||
DBUSER = import_secret("DBUSER")
|
|
||||||
DBPASSWD = import_secret("DBPASSWD")
|
|
||||||
|
|
||||||
ACCOUNT_CREATION_PASS = import_secret("ACCOUNT_CREATION_PASS")
|
|
||||||
|
|
||||||
BASE_DIR = os.path.join(os.path.dirname(__file__), "..", "..")
|
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
"propositions",
|
||||||
"trombonoscope",
|
"trombonoscope",
|
||||||
"actu",
|
"actu",
|
||||||
"colorful",
|
"colorful",
|
||||||
|
@ -89,15 +77,22 @@ TEMPLATES = [
|
||||||
|
|
||||||
WSGI_APPLICATION = "Ernestophone.wsgi.application"
|
WSGI_APPLICATION = "Ernestophone.wsgi.application"
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
|
###
|
||||||
|
# Database configuration
|
||||||
|
# -> https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||||
|
|
||||||
|
DATABASES = credentials.get_json(
|
||||||
|
"DATABASES",
|
||||||
|
{
|
||||||
"default": {
|
"default": {
|
||||||
"ENGINE": "django.db.backends.postgresql",
|
"ENGINE": "django.db.backends.sqlite3",
|
||||||
"NAME": DBNAME,
|
"NAME": BASE_DIR / "db.sqlite3",
|
||||||
"USER": DBUSER,
|
|
||||||
"PASSWORD": DBPASSWD,
|
|
||||||
"HOST": "localhost",
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
)
|
||||||
|
|
||||||
AUTH_PASSWORD_VALIDATORS = [
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
{
|
{
|
||||||
|
@ -128,7 +123,7 @@ USE_L10N = True
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),)
|
LOCALE_PATHS = (BASE_DIR / "locale",)
|
||||||
|
|
||||||
|
|
||||||
AUTH_PROFILE_MODEL = "gestion.ErnestoUser"
|
AUTH_PROFILE_MODEL = "gestion.ErnestoUser"
|
||||||
|
@ -149,3 +144,18 @@ AVATAR_PROVIDERS = (
|
||||||
"avatar.providers.DefaultAvatarProvider",
|
"avatar.providers.DefaultAvatarProvider",
|
||||||
)
|
)
|
||||||
AVATAR_THUMB_FORMAT = "JPEG"
|
AVATAR_THUMB_FORMAT = "JPEG"
|
||||||
|
|
||||||
|
###
|
||||||
|
# Staticfiles configuration
|
||||||
|
|
||||||
|
STATIC_ROOT = credentials["STATIC_ROOT"]
|
||||||
|
STATIC_URL = "/static/"
|
||||||
|
|
||||||
|
MEDIA_ROOT = credentials.get("MEDIA_ROOT", BASE_DIR / "media")
|
||||||
|
MEDIA_URL = "/media/"
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
|
|
||||||
|
INSTALLED_APPS += ["debug_toolbar"]
|
||||||
|
MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE
|
|
@ -1,23 +0,0 @@
|
||||||
import os
|
|
||||||
|
|
||||||
from .common import * # noqa
|
|
||||||
from .common import BASE_DIR, INSTALLED_APPS, MIDDLEWARE
|
|
||||||
|
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
|
||||||
|
|
||||||
DEBUG = True
|
|
||||||
|
|
||||||
INSTALLED_APPS += ["debug_toolbar"]
|
|
||||||
MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE
|
|
||||||
|
|
||||||
STATIC_URL = "/static/"
|
|
||||||
STATIC_ROOT = "static"
|
|
||||||
MEDIA_URL = "/media/"
|
|
||||||
MEDIA_ROOT = "media"
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
"default": {
|
|
||||||
"ENGINE": "django.db.backends.sqlite3",
|
|
||||||
"NAME": os.path.join(BASE_DIR, "db.sqlite3"),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
import os
|
|
||||||
|
|
||||||
from .common import * # noqa
|
|
||||||
from .common import BASE_DIR
|
|
||||||
|
|
||||||
DEBUG = False
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = [
|
|
||||||
"ernestophone.ens.fr",
|
|
||||||
"www.ernestophone.ens.fr",
|
|
||||||
]
|
|
||||||
|
|
||||||
STATIC_URL = "/static/"
|
|
||||||
STATIC_ROOT = os.path.join(BASE_DIR, "..", "..", "public", "ernesto", "static")
|
|
||||||
|
|
||||||
MEDIA_URL = "/media/"
|
|
||||||
MEDIA_ROOT = os.path.join(BASE_DIR, "..", "media")
|
|
|
@ -1,9 +0,0 @@
|
||||||
SECRET_KEY = "vpb%-1@$ha98w5^ji#@9v2_kxj)zdk5+e!9!fqniu2$#eg+46="
|
|
||||||
ADMINS = None
|
|
||||||
SERVER_EMAIL = "ernesto@localhost"
|
|
||||||
|
|
||||||
DBNAME = "ernesto"
|
|
||||||
DBUSER = "ernesto"
|
|
||||||
DBPASSWD = "YNp2rrXowJnDAFF3"
|
|
||||||
|
|
||||||
ACCOUNT_CREATION_PASS = "dummy"
|
|
|
@ -13,13 +13,13 @@ Including another URLconf
|
||||||
1. Import the include() function: from django.urls import include, path
|
1. Import the include() function: from django.urls import include, path
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.i18n import i18n_patterns
|
from django.conf.urls.i18n import i18n_patterns
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
from gestion import views as gestion_views
|
from gestion import views as gestion_views
|
||||||
|
|
||||||
urlpatterns = []
|
urlpatterns = []
|
||||||
|
@ -69,4 +69,5 @@ urlpatterns += i18n_patterns(
|
||||||
),
|
),
|
||||||
prefix_default_language=False,
|
prefix_default_language=False,
|
||||||
)
|
)
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
if settings.DEBUG:
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
23
actu/migrations/0002_actu_rainbow.py
Normal file
23
actu/migrations/0002_actu_rainbow.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# 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,6 +7,15 @@ class Actu(models.Model):
|
||||||
text = models.TextField(_("Info"), null=True, blank=False)
|
text = models.TextField(_("Info"), null=True, blank=False)
|
||||||
text_en = models.TextField(("Info en anglais"), null=True, blank=True)
|
text_en = models.TextField(("Info en anglais"), null=True, blank=True)
|
||||||
order = models.IntegerField(verbose_name=_("ordre"))
|
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):
|
def __str__(self):
|
||||||
return self.text
|
return self.text
|
||||||
|
|
|
@ -14,7 +14,7 @@ class ActuList(ChefRequiredMixin, ListView):
|
||||||
|
|
||||||
class ActuCreate(ChefRequiredMixin, CreateView):
|
class ActuCreate(ChefRequiredMixin, CreateView):
|
||||||
model = Actu
|
model = Actu
|
||||||
fields = ["text", "order", "text_en"]
|
fields = ["text", "order", "text_en", "rainbow"]
|
||||||
template_name = "actu/create_actu.html"
|
template_name = "actu/create_actu.html"
|
||||||
success_url = reverse_lazy("actu:liste")
|
success_url = reverse_lazy("actu:liste")
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class ActuCreate(ChefRequiredMixin, CreateView):
|
||||||
|
|
||||||
class ActuUpdate(ChefRequiredMixin, UpdateView):
|
class ActuUpdate(ChefRequiredMixin, UpdateView):
|
||||||
model = Actu
|
model = Actu
|
||||||
fields = ["text", "order", "text_en"]
|
fields = ["text", "order", "text_en", "rainbow"]
|
||||||
template_name = "actu/update_actu.html"
|
template_name = "actu/update_actu.html"
|
||||||
success_url = reverse_lazy("actu:liste")
|
success_url = reverse_lazy("actu:liste")
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,27 @@ from django.contrib import admin
|
||||||
|
|
||||||
from .models import Event, Participants
|
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
|
# Add event by admin page return a 502 error
|
||||||
admin.site.register(Event)
|
admin.site.register(Event)
|
||||||
admin.site.register(Participants)
|
admin.site.register(Participants, ParticipantsAdmin)
|
||||||
|
|
|
@ -22,11 +22,11 @@ class EventCalendar(HTMLCalendar):
|
||||||
for ev in self.events[day]:
|
for ev in self.events[day]:
|
||||||
body.append('<a href="/agenda/' + '%s"' % ev.id)
|
body.append('<a href="/agenda/' + '%s"' % ev.id)
|
||||||
if ev.calendrier == "C":
|
if ev.calendrier == "C":
|
||||||
body.append('style="color:#160083">'+esc(ev.nom))
|
body.append('style="color:#160083">' + esc(ev.nom))
|
||||||
elif ev.calendrier == "D":
|
elif ev.calendrier == "D":
|
||||||
body.append('style="color:#770083">'+esc(ev.nom))
|
body.append('style="color:#770083">' + esc(ev.nom))
|
||||||
else:
|
else:
|
||||||
body.append('>'+esc(ev.nom))
|
body.append(">" + esc(ev.nom))
|
||||||
body.append("</a><br/>")
|
body.append("</a><br/>")
|
||||||
return self.day_cell(
|
return self.day_cell(
|
||||||
cssclass,
|
cssclass,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from gestion.models import ErnestoUser
|
||||||
|
|
||||||
from calendrier.models import Event, Participants
|
from calendrier.models import Event, Participants
|
||||||
from gestion.models import ErnestoUser
|
|
||||||
|
|
||||||
|
|
||||||
class ModifEventForm(forms.ModelForm):
|
class ModifEventForm(forms.ModelForm):
|
||||||
|
@ -37,7 +37,13 @@ class EventForm(forms.ModelForm):
|
||||||
class ParticipantsForm(forms.ModelForm):
|
class ParticipantsForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Participants
|
model = Participants
|
||||||
fields = ("reponse", "details", "dont_play_main", "instrument","instrument_autre")
|
fields = (
|
||||||
|
"reponse",
|
||||||
|
"details",
|
||||||
|
"dont_play_main",
|
||||||
|
"instrument",
|
||||||
|
"instrument_autre",
|
||||||
|
)
|
||||||
widgets = {
|
widgets = {
|
||||||
"details": forms.Textarea(attrs={"placeholder": _("50 caractères max")}),
|
"details": forms.Textarea(attrs={"placeholder": _("50 caractères max")}),
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,23 +6,41 @@ from django.db import migrations, models
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('calendrier', '0004_auto_20210606_1640'),
|
("calendrier", "0004_auto_20210606_1640"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name="event",
|
||||||
name='calendrier',
|
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),
|
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(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name="event",
|
||||||
name='desc_users',
|
name="desc_users",
|
||||||
field=models.TextField(blank=True, null=True, verbose_name='Infos (visible seulement des fanfaron·ne·s)'),
|
field=models.TextField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Infos (visible seulement des fanfaron·ne·s)",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='event',
|
model_name="event",
|
||||||
name='desc_users_en',
|
name="desc_users_en",
|
||||||
field=models.TextField(blank=True, null=True, verbose_name='Infos en anglais (visible seulement des fanfaron·ne·s'),
|
field=models.TextField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
verbose_name="Infos en anglais (visible seulement des fanfaron·ne·s",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,18 +6,36 @@ from django.db import migrations, models
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('calendrier', '0005_auto_20210726_0949'),
|
("calendrier", "0005_auto_20210726_0949"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='participants',
|
model_name="participants",
|
||||||
name='instrument_autre',
|
name="instrument_autre",
|
||||||
field=models.CharField(blank=True, max_length=50, null=True),
|
field=models.CharField(blank=True, max_length=50, null=True),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='participants',
|
model_name="participants",
|
||||||
name='instrument',
|
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),
|
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,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
31
calendrier/migrations/0007_auto_20220314_2320.py
Normal file
31
calendrier/migrations/0007_auto_20220314_2320.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# 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"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
17
calendrier/migrations/0008_auto_20220322_1454.py
Normal file
17
calendrier/migrations/0008_auto_20220322_1454.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# 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,9 +2,7 @@ import uuid
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
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 = (
|
ANSWERS = (
|
||||||
("oui", _("Oui")),
|
("oui", _("Oui")),
|
||||||
|
@ -62,7 +60,9 @@ class Participants(models.Model):
|
||||||
reponse = models.CharField(
|
reponse = models.CharField(
|
||||||
_("Réponse"), max_length=20, default="non", choices=ANSWERS
|
_("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)
|
instrument_autre = models.CharField(max_length=50, blank=True, null=True)
|
||||||
dont_play_main = models.CharField(
|
dont_play_main = models.CharField(
|
||||||
_("Je veux jouer d'un instrument different de mon instrument principal:"),
|
_("Je veux jouer d'un instrument different de mon instrument principal:"),
|
||||||
|
@ -72,3 +72,11 @@ class Participants(models.Model):
|
||||||
choices=[("Non", _("Non")), ("Oui", _("Oui"))],
|
choices=[("Non", _("Non")), ("Oui", _("Oui"))],
|
||||||
)
|
)
|
||||||
details = models.CharField(max_length=50, blank=True)
|
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') ]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "gestion/base.html" %}
|
{% extends "gestion/base.html" %}
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
{% load frenchmonth %}
|
{% load frenchmonth %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load translate %}
|
{% load translate %}
|
||||||
|
@ -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>
|
<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>
|
<ul>
|
||||||
{% for a in actu %}
|
{% for a in actu %}
|
||||||
<li>{% autotranslate current_language a.text a.text_en %}</li>
|
<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>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,35 +43,35 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td width="20%" align="left">
|
<td width="20%" align="left">
|
||||||
<<
|
<<
|
||||||
{% ifequal current_language "fr" %}
|
{% if current_language == "fr" %}
|
||||||
<a href="{% url "calendrier:view-month" PreviousYear PreviousMonth %}">{{PreviousMonthName|frenchmonth}} {{PreviousYear}}</a>
|
<a href="{% url "calendrier:view-month" PreviousYear PreviousMonth %}">{{PreviousMonthName|frenchmonth}} {{PreviousYear}}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url "calendrier:view-month" PreviousYear PreviousMonth %}">{{PreviousMonthName}} {{PreviousYear}}</a>
|
<a href="{% url "calendrier:view-month" PreviousYear PreviousMonth %}">{{PreviousMonthName}} {{PreviousYear}}</a>
|
||||||
{% endifequal %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td width="20%" align="center"><a href="{% url "calendrier:home" %}">{% trans "Aujourd'hui" %}</a></td>
|
<td width="20%" align="center"><a href="{% url "calendrier:home" %}">{% trans "Aujourd'hui" %}</a></td>
|
||||||
<td width="20%" align="right">
|
<td width="20%" align="right">
|
||||||
{% ifequal current_language "fr" %}
|
{% if current_language == "fr" %}
|
||||||
<a href="{% url "calendrier:view-month" NextYear NextMonth %}">{{NextMonthName|frenchmonth}} {{NextYear}}</a> >>
|
<a href="{% url "calendrier:view-month" NextYear NextMonth %}">{{NextMonthName|frenchmonth}} {{NextYear}}</a> >>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url "calendrier:view-month" NextYear NextMonth %}">{{NextMonthName}} {{NextYear}}</a> >>
|
<a href="{% url "calendrier:view-month" NextYear NextMonth %}">{{NextMonthName}} {{NextYear}}</a> >>
|
||||||
{% endifequal %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div id="calendar">
|
<div id="calendar">
|
||||||
{% if user.profile.is_chef_event or user.profile.is_chef %}
|
{% if user.profile.is_chef_event or user.profile.is_chef %}
|
||||||
{% ifequal current_language "fr" %}
|
{% if current_language == "fr" %}
|
||||||
{{Calendar_chef|translate}}
|
{{Calendar_chef|translate}}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{Calendar_chef}}
|
{{Calendar_chef}}
|
||||||
{% endifequal %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% ifequal current_language "fr" %}
|
{% if current_language == "fr" %}
|
||||||
{{Calendar|translate}}
|
{{Calendar|translate}}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{Calendar}}
|
{{Calendar}}
|
||||||
{% endifequal %}
|
{% endif %}
|
||||||
{% endif%}
|
{% endif%}
|
||||||
</div>
|
</div>
|
||||||
{% if user.profile.is_chef_event or user.profile.is_chef %}
|
{% if user.profile.is_chef_event or user.profile.is_chef %}
|
||||||
|
|
|
@ -223,6 +223,9 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</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 %}
|
{% endblock %}
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script>
|
<script>
|
||||||
|
@ -258,11 +261,19 @@ singleEvent.createWidget('#single-normal', function() {
|
||||||
console.log('#single-normal widget has been created');
|
console.log('#single-normal widget has been created');
|
||||||
});
|
});
|
||||||
|
|
||||||
{% ifequal current_language "fr" %}
|
{% if current_language == "fr" %}
|
||||||
singleEvent.setOption({ lang: 'fr' });
|
singleEvent.setOption({ lang: 'fr' });
|
||||||
{% else %}
|
{% else %}
|
||||||
singleEvent.setOption({ lang: 'en' });
|
singleEvent.setOption({ lang: 'en' });
|
||||||
{% endifequal %}
|
{% endif %}
|
||||||
</script>
|
</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 %}
|
{% endblock %}
|
||||||
|
|
|
@ -4,7 +4,6 @@ from django.contrib.auth import get_user_model
|
||||||
from django.template.defaultfilters import urlencode
|
from django.template.defaultfilters import urlencode
|
||||||
from django.test import Client, TestCase
|
from django.test import Client, TestCase
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from gestion.models import ErnestoUser
|
from gestion.models import ErnestoUser
|
||||||
|
|
||||||
from ..models import Event
|
from ..models import Event
|
||||||
|
|
|
@ -4,20 +4,20 @@ from calendar import monthrange
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from actu.models import Actu
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.views.generic import DeleteView, TemplateView, UpdateView
|
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.calend import EventCalendar
|
||||||
from calendrier.forms import (ChangeDoodleName, EventForm, ModifEventForm,
|
from calendrier.forms import (ChangeDoodleName, EventForm, ModifEventForm,
|
||||||
ParticipantsForm)
|
ParticipantsForm)
|
||||||
from calendrier.models import Event, Participants
|
from calendrier.models import Event, Participants
|
||||||
from gestion.mixins import ChefRequiredMixin, ChefEventRequiredMixin
|
|
||||||
from gestion.models import Photo
|
|
||||||
|
|
||||||
|
|
||||||
def generer(*args):
|
def generer(*args):
|
||||||
|
@ -76,9 +76,13 @@ class Calendar(LoginRequiredMixin, TemplateView):
|
||||||
lMonth = self.pMonth
|
lMonth = self.pMonth
|
||||||
lCalendarFromMonth = datetime(lYear, lMonth, 1)
|
lCalendarFromMonth = datetime(lYear, lMonth, 1)
|
||||||
lCalendarToMonth = datetime(lYear, lMonth, monthrange(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
|
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(
|
lEvents_chef = Event.objects.filter(
|
||||||
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
|
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
|
||||||
)
|
)
|
||||||
|
@ -170,7 +174,6 @@ class Calendar(LoginRequiredMixin, TemplateView):
|
||||||
|
|
||||||
|
|
||||||
class Home(Calendar):
|
class Home(Calendar):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pYear(self):
|
def pYear(self):
|
||||||
lToday = datetime.now()
|
lToday = datetime.now()
|
||||||
|
@ -209,6 +212,7 @@ class ViewEvent(LoginRequiredMixin, TemplateView):
|
||||||
else:
|
else:
|
||||||
instru = participant.instrument
|
instru = participant.instrument
|
||||||
|
|
||||||
|
instru = "" if instru is None else instru
|
||||||
sure, maybe, namesoui, namespe, namesnon = instrument_count[instru]
|
sure, maybe, namesoui, namespe, namesnon = instrument_count[instru]
|
||||||
|
|
||||||
if participant.reponse == "oui":
|
if participant.reponse == "oui":
|
||||||
|
@ -234,34 +238,61 @@ class ViewEvent(LoginRequiredMixin, TemplateView):
|
||||||
namesnon += [participant.participant.get_doodlename()]
|
namesnon += [participant.participant.get_doodlename()]
|
||||||
instrument_count[instru] = (sure, maybe, namesoui, namespe, namesnon)
|
instrument_count[instru] = (sure, maybe, namesoui, namespe, namesnon)
|
||||||
instrument_count_l = []
|
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:
|
for instrument in instru_order:
|
||||||
if instrument in instrument_count.keys():
|
if instrument in instrument_count.keys():
|
||||||
(sure,maybe,namesoui,namespe,namesnon) =instrument_count[instrument]
|
(sure, maybe, namesoui, namespe, namesnon) = instrument_count[
|
||||||
instrument_count_l.append(( instrument, sure,
|
instrument
|
||||||
|
]
|
||||||
|
instrument_count_l.append(
|
||||||
|
(
|
||||||
|
instrument,
|
||||||
|
sure,
|
||||||
maybe,
|
maybe,
|
||||||
namesoui,
|
namesoui,
|
||||||
namespe,
|
namespe,
|
||||||
namesnon,
|
namesnon,
|
||||||
))
|
)
|
||||||
|
)
|
||||||
for instrument in sorted(instrument_count.keys()):
|
for instrument in sorted(instrument_count.keys()):
|
||||||
if instrument not in instru_order:
|
if instrument not in instru_order:
|
||||||
(sure,maybe,namesoui,namespe,namesnon) =instrument_count[instrument]
|
(sure, maybe, namesoui, namespe, namesnon) = instrument_count[
|
||||||
instrument_count_l.append(( instrument, sure,
|
instrument
|
||||||
|
]
|
||||||
|
instrument_count_l.append(
|
||||||
|
(
|
||||||
|
instrument,
|
||||||
|
sure,
|
||||||
maybe,
|
maybe,
|
||||||
namesoui,
|
namesoui,
|
||||||
namespe,
|
namespe,
|
||||||
namesnon,
|
namesnon,
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
context["event"] = event
|
context["event"] = event
|
||||||
context["instrument_count"] = instrument_count_l
|
context["instrument_count"] = instrument_count_l
|
||||||
context["participants"] = participants
|
context["participants"] = participants.order_by('-creationDate')
|
||||||
context["nboui"] = len(participants.filter(reponse="oui"))
|
context["nboui"] = len(participants.filter(reponse="oui"))
|
||||||
context["nbpe"] = len(participants.filter(reponse="pe"))
|
context["nbpe"] = len(participants.filter(reponse="pe"))
|
||||||
context["nbnon"] = len(participants.filter(reponse="non"))
|
context["nbnon"] = len(participants.filter(reponse="non"))
|
||||||
context["multi_instrumentistes"] = multi_instrumentistes
|
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
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
@ -337,20 +368,22 @@ class ReponseEvent(LoginRequiredMixin, TemplateView):
|
||||||
context["form"] = self.form_class()
|
context["form"] = self.form_class()
|
||||||
context["ev"] = get_object_or_404(Event, id=self.kwargs["id"])
|
context["ev"] = get_object_or_404(Event, id=self.kwargs["id"])
|
||||||
context["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
|
return context
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
form = self.form_class(request.POST)
|
|
||||||
ev = get_object_or_404(Event, id=self.kwargs["id"])
|
ev = get_object_or_404(Event, id=self.kwargs["id"])
|
||||||
part = request.user.profile
|
part = request.user.profile
|
||||||
if form.is_valid():
|
|
||||||
try:
|
try:
|
||||||
p = Participants.objects.get(event=ev, participant=part)
|
p = Participants.objects.get(event=ev, participant=part)
|
||||||
p.delete()
|
|
||||||
except Participants.DoesNotExist:
|
except Participants.DoesNotExist:
|
||||||
pass
|
p = None
|
||||||
|
form = self.form_class(request.POST, instance=p)
|
||||||
|
if form.is_valid():
|
||||||
obj = form.save(commit=False)
|
obj = form.save(commit=False)
|
||||||
|
# Si la participation existe déjà, ces 2 ligne sont redondantes
|
||||||
obj.event = ev
|
obj.event = ev
|
||||||
obj.participant = part
|
obj.participant = part
|
||||||
obj.save()
|
obj.save()
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
# Generated by Django 2.2.17 on 2021-06-08 10:29
|
# Generated by Django 2.2.17 on 2021-06-08 10:29
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
import gestion.models
|
import gestion.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('gestion', '0005_auto_20210427_1834'),
|
("gestion", "0005_auto_20210427_1834"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='photo',
|
model_name="photo",
|
||||||
name='image',
|
name="image",
|
||||||
field=models.ImageField(default=None, upload_to='trombonoscope/deco', validators=[gestion.models.Photo.validate_image]),
|
field=models.ImageField(
|
||||||
|
default=None,
|
||||||
|
upload_to="trombonoscope/deco",
|
||||||
|
validators=[gestion.models.Photo.validate_image],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -6,13 +6,15 @@ from django.db import migrations, models
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('gestion', '0006_auto_20210608_1029'),
|
("gestion", "0006_auto_20210608_1029"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='ernestouser',
|
model_name="ernestouser",
|
||||||
name='is_chef_event',
|
name="is_chef_event",
|
||||||
field=models.BooleanField(default=False, verbose_name='Respo événement Fanfare'),
|
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):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('gestion', '0007_ernestouser_is_chef_event'),
|
("gestion", "0007_ernestouser_is_chef_event"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='ernestouser',
|
model_name="ernestouser",
|
||||||
name='is_chef_com',
|
name="is_chef_com",
|
||||||
field=models.BooleanField(default=False, verbose_name='Respo com'),
|
field=models.BooleanField(default=False, verbose_name="Respo com"),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='ernestouser',
|
model_name="ernestouser",
|
||||||
name='is_chef_instru',
|
name="is_chef_instru",
|
||||||
field=models.BooleanField(default=False, verbose_name='Respo instruments'),
|
field=models.BooleanField(default=False, verbose_name="Respo instruments"),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='ernestouser',
|
model_name="ernestouser",
|
||||||
name='is_chef_event',
|
name="is_chef_event",
|
||||||
field=models.BooleanField(default=False, verbose_name='Respo événements'),
|
field=models.BooleanField(default=False, verbose_name="Respo événements"),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
18
gestion/migrations/0009_ernestouser_is_chef_mu.py
Normal file
18
gestion/migrations/0009_ernestouser_is_chef_mu.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# 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,32 +6,75 @@ class ChefRequiredMixin(UserPassesTestMixin):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
return (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
return (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
||||||
|
|
||||||
|
|
||||||
class ChefEventRequiredMixin(UserPassesTestMixin):
|
class ChefEventRequiredMixin(UserPassesTestMixin):
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
is_chef = (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
is_chef = (
|
||||||
is_chef_event = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_event
|
(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
|
return is_chef or is_chef_event
|
||||||
|
|
||||||
|
|
||||||
class ChefInstruRequiredMixin(UserPassesTestMixin):
|
class ChefInstruRequiredMixin(UserPassesTestMixin):
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
is_chef = (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
is_chef = (
|
||||||
is_chef_instru = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_instru
|
(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
|
return is_chef or is_chef_instru
|
||||||
|
|
||||||
|
|
||||||
class ChefComRequiredMixin(UserPassesTestMixin):
|
class ChefComRequiredMixin(UserPassesTestMixin):
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
is_chef = (user is not None) and hasattr(user, "profile") and user.profile.is_chef
|
is_chef = (
|
||||||
is_chef_com = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_com
|
(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
|
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):
|
class AllChefRequiredMixin(UserPassesTestMixin):
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
user = self.request.user
|
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_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_com = (
|
||||||
is_chef_event = (user is not None) and hasattr(user, "profile") and user.profile.is_chef_event
|
(user is not None) and hasattr(user, "profile") and user.profile.is_chef_com
|
||||||
return is_chef or is_chef_com or is_chef_event or is_su
|
)
|
||||||
|
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
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from colorful.fields import RGBColorField
|
from colorful.fields import RGBColorField
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
import os
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
INSTRU_CHOICES = [
|
INSTRU_CHOICES = [
|
||||||
("Clarinette", _("Clarinette")),
|
("Clarinette", _("Clarinette")),
|
||||||
|
@ -21,7 +22,9 @@ INSTRU_CHOICES = [
|
||||||
("Trompette", _("Trompette")),
|
("Trompette", _("Trompette")),
|
||||||
("Autre", _("Autre")),
|
("Autre", _("Autre")),
|
||||||
("ne sais pas", _("Je ne sais pas encore")),
|
("ne sais pas", _("Je ne sais pas encore")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Photo(models.Model):
|
class Photo(models.Model):
|
||||||
PHOTO_PLACEMENT = (
|
PHOTO_PLACEMENT = (
|
||||||
("home_join", _("Rejoignez nous")),
|
("home_join", _("Rejoignez nous")),
|
||||||
|
@ -84,6 +87,7 @@ class ErnestoUser(models.Model):
|
||||||
is_chef_event = models.BooleanField(_("Respo événements"), default=False)
|
is_chef_event = models.BooleanField(_("Respo événements"), default=False)
|
||||||
is_chef_com = models.BooleanField(_("Respo com"), default=False)
|
is_chef_com = models.BooleanField(_("Respo com"), default=False)
|
||||||
is_chef_instru = models.BooleanField(_("Respo instruments"), default=False)
|
is_chef_instru = models.BooleanField(_("Respo instruments"), default=False)
|
||||||
|
is_chef_mu = models.BooleanField(_("Respo musique"), default=False)
|
||||||
phone = models.CharField(
|
phone = models.CharField(
|
||||||
_("Téléphone"),
|
_("Téléphone"),
|
||||||
max_length=20,
|
max_length=20,
|
||||||
|
@ -91,7 +95,6 @@ class ErnestoUser(models.Model):
|
||||||
help_text=_("seulement visible par les chef·fe·s"),
|
help_text=_("seulement visible par les chef·fe·s"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
COLORS_CHOICES = [
|
COLORS_CHOICES = [
|
||||||
("#e4522f#ffffff", _("Orange et Blanc")),
|
("#e4522f#ffffff", _("Orange et Blanc")),
|
||||||
("#ffffff#000000", _("Blanc et Noir")),
|
("#ffffff#000000", _("Blanc et Noir")),
|
||||||
|
|
|
@ -3704,10 +3704,11 @@ div.spoiler
|
||||||
hsl(220, 100%, 50%),
|
hsl(220, 100%, 50%),
|
||||||
hsl(230, 100%, 50%),
|
hsl(230, 100%, 50%),
|
||||||
hsl(240, 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;
|
color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select[multiple] {
|
||||||
|
height: 15em;
|
||||||
|
}
|
||||||
|
|
BIN
gestion/static/images/cvec.png
Normal file
BIN
gestion/static/images/cvec.png
Normal file
Binary file not shown.
After 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>
|
<a class="dropdown-item" href="https://heyzine.com/flip-book/b2cf4809b7.html" target="_blank">{% trans "Year Book 2021" %}</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{% if user.is_superuser or user.profile.is_chef or user.profile.is_chef_event or user.profile.is_chef_com %}
|
{% 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 %}
|
||||||
<li class="nav-item dropdown">
|
<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">
|
<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>
|
<b>{% trans 'Le pouvoir des cheff·e·s'%}</b>
|
||||||
|
@ -77,18 +77,18 @@
|
||||||
<a class="dropdown-item" href="/admin/">{% trans "Administration" %}</a>
|
<a class="dropdown-item" href="/admin/">{% trans "Administration" %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.profile.is_chef %}
|
{% if user.profile.is_chef %}
|
||||||
<a class="dropdown-item" href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a>
|
|
||||||
<a class="dropdown-item" href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a>
|
<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>
|
{% endif %}
|
||||||
<a class="dropdown-item" href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a>
|
{% if user.profile.is_chef or user.profile.is_chef_event %}
|
||||||
|
|
||||||
{% elif user.profile.is_chef_event %}
|
|
||||||
<a class="dropdown-item" href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a>
|
<a class="dropdown-item" href="{% url 'calendrier:create_event' %}">{% trans "Ajouter un événement" %}</a>
|
||||||
|
{% endif %}
|
||||||
{% elif user.profile.is_chef_com %}
|
{% if user.profile.is_chef or 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_photo' %}">{% trans "Modifier les photos" %}</a>
|
||||||
<a class="dropdown-item" href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a>
|
<a class="dropdown-item" href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a>
|
||||||
{% endif %}
|
{% 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>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -124,11 +124,11 @@
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
{% ifequal current_language "fr" %}
|
{% if current_language == "fr" %}
|
||||||
<a class="nav-link" href="{% changelang "en" %}" ><img src="{% static 'images\en_flag.jpg' %}" width="60" height="40" style="vertical-align: middle"></a>
|
<a class="nav-link" href="{% changelang "en" %}" ><img src="{% static 'images\en_flag.jpg' %}" width="60" height="40" style="vertical-align: middle"></a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="nav-link" href="{% changelang "fr" %}" ><img src="{% static 'images\fr_flag.jpg' %}" width="60" height="40" style="vertical-align: middle"></a>
|
<a class="nav-link" href="{% changelang "fr" %}" ><img src="{% static 'images\fr_flag.jpg' %}" width="60" height="40" style="vertical-align: middle"></a>
|
||||||
{% endifequal %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -145,6 +145,10 @@
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<footer id="footer" style="background-color:rgb(228, 82, 47);">
|
<footer id="footer" style="background-color:rgb(228, 82, 47);">
|
||||||
<div class="copyright">
|
<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">
|
<ul class="icons">
|
||||||
<li><a target="_blank" href="https://www.facebook.com/ernestophone"
|
<li><a target="_blank" href="https://www.facebook.com/ernestophone"
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
{% if user.profile.is_chef or user.is_superuser %}
|
{% if user.profile.is_chef or user.is_superuser %}
|
||||||
<li> <a href="/admin/">{% trans "Administration" %}</a></li>
|
<li> <a href="/admin/">{% trans "Administration" %}</a></li>
|
||||||
|
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.profile.is_chef %}
|
{% if user.profile.is_chef %}
|
||||||
<li><a href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a></li>
|
<li><a href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a></li>
|
||||||
|
@ -24,6 +25,9 @@
|
||||||
<li><a href="{% url 'liste_photo' %}">{% trans "Modifier les photos" %}</a></li>
|
<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>
|
<li><a href="{% url 'liste_video' %}">{% trans "Modifier les vidéos" %}</a></li>
|
||||||
{% endif %}
|
{% 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>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
|
||||||
|
@ -11,12 +12,12 @@ from django.urls import reverse_lazy
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import (CreateView, DeleteView, ListView,
|
from django.views.generic import (CreateView, DeleteView, ListView,
|
||||||
TemplateView, UpdateView)
|
TemplateView, UpdateView)
|
||||||
import os
|
|
||||||
|
|
||||||
from calendrier.forms import ChangeDoodleName
|
from calendrier.forms import ChangeDoodleName
|
||||||
from gestion.forms import (ChangeFormUser, ChangeMembreForm,
|
from gestion.forms import (ChangeFormUser, ChangeMembreForm,
|
||||||
InscriptionMembreForm, RegistrationFormUser)
|
InscriptionMembreForm, RegistrationFormUser)
|
||||||
from gestion.mixins import ChefRequiredMixin, AllChefRequiredMixin, ChefComRequiredMixin
|
from gestion.mixins import (AllChefRequiredMixin, ChefComRequiredMixin,
|
||||||
|
ChefRequiredMixin)
|
||||||
from gestion.models import ErnestoUser, Photo, VideoGallery
|
from gestion.models import ErnestoUser, Photo, VideoGallery
|
||||||
from partitions.models import Category
|
from partitions.models import Category
|
||||||
|
|
||||||
|
@ -79,6 +80,7 @@ class Profil(LoginRequiredMixin, TemplateView):
|
||||||
class Chef(AllChefRequiredMixin, TemplateView):
|
class Chef(AllChefRequiredMixin, TemplateView):
|
||||||
template_name = "gestion/chef.html"
|
template_name = "gestion/chef.html"
|
||||||
|
|
||||||
|
|
||||||
class YearBook2021(TemplateView):
|
class YearBook2021(TemplateView):
|
||||||
template_name = "gestion/yearbook2021.html"
|
template_name = "gestion/yearbook2021.html"
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
<div class="7u 12u$(small)">
|
<div class="7u 12u$(small)">
|
||||||
<p>{% trans "Propriétaire : "%} {% if instru.owner %}{{instru.owner}} {% else %}-{% endif %}<br>
|
<p>{% trans "Propriétaire : "%} {% if instru.owner %}{{instru.owner}} {% else %}-{% endif %}<br>
|
||||||
{% trans "Statut : "%} {{instru.statut}} <br>
|
{% trans "Statut : "%} {{instru.statut}} <br>
|
||||||
{% ifequal instru.statut 'Prêté' %}
|
{% if instru.statut == 'Prêté' %}
|
||||||
{% trans "Utilisateur : "%} {% if instru.user %}{{instru.user}} {% else %}-{% endif %}<br>
|
{% trans "Utilisateur : "%} {% if instru.user %}{{instru.user}} {% else %}-{% endif %}<br>
|
||||||
{% endifequal %}
|
{% endif %}
|
||||||
{% trans "Marque : "%} {% if instru.marque %}{{instru.marque}} {% else %}-{% endif %} <br>
|
{% trans "Marque : "%} {% if instru.marque %}{{instru.marque}} {% else %}-{% endif %} <br>
|
||||||
{% trans "Modele : "%} {% if instru.model %}{{instru.model}} {% else %}-{% endif %}<br>
|
{% trans "Modele : "%} {% if instru.model %}{{instru.model}} {% else %}-{% endif %}<br>
|
||||||
{% trans "Numéro de série : "%} {% if instru.serial %}{{instru.serial}}{% else %}-{% endif %} <br>
|
{% trans "Numéro de série : "%} {% if instru.serial %}{{instru.serial}}{% else %}-{% endif %} <br>
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
|
|
||||||
<td> {{ rep.date }} </td>
|
<td> {{ rep.date }} </td>
|
||||||
<td> {% ifequal current_language "fr" %}
|
<td> {% if current_language == "fr" %}
|
||||||
{{ rep.description }}
|
{{ rep.description }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if instru.description_en %}
|
{% if instru.description_en %}
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ rep.description }}
|
{{ rep.description }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endifequal %} </td>
|
{% endif %} </td>
|
||||||
<td> {{ rep.prix }} </td>
|
<td> {{ rep.prix }} </td>
|
||||||
<td> {{ rep.lieux }} </td>
|
<td> {{ rep.lieux }} </td>
|
||||||
{%if user.profile.is_chef or user.profile.is_chef_instru %}
|
{%if user.profile.is_chef or user.profile.is_chef_instru %}
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.utils.safestring import mark_safe
|
||||||
from django.views.generic import (CreateView, DeleteView, TemplateView,
|
from django.views.generic import (CreateView, DeleteView, TemplateView,
|
||||||
UpdateView)
|
UpdateView)
|
||||||
|
|
||||||
from gestion.mixins import ChefRequiredMixin, ChefInstruRequiredMixin
|
from gestion.mixins import ChefInstruRequiredMixin, ChefRequiredMixin
|
||||||
from gestion.models import Photo
|
from gestion.models import Photo
|
||||||
from instruments.forms import ChefEditInstrumentForm, ChefReparationForm
|
from instruments.forms import ChefEditInstrumentForm, ChefReparationForm
|
||||||
from instruments.models import Instrument, Reparation
|
from instruments.models import Instrument, Reparation
|
||||||
|
@ -28,7 +28,17 @@ class ListeInstru(LoginRequiredMixin, TemplateView):
|
||||||
|
|
||||||
class CreateInstru(ChefInstruRequiredMixin, CreateView):
|
class CreateInstru(ChefInstruRequiredMixin, CreateView):
|
||||||
model = Instrument
|
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"
|
template_name = "instruments/create_instru.html"
|
||||||
success_url = reverse_lazy("instruments:liste")
|
success_url = reverse_lazy("instruments:liste")
|
||||||
|
|
||||||
|
@ -95,11 +105,12 @@ class FicheInstru(LoginRequiredMixin, TemplateView):
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
instru = get_object_or_404(self.model, id=self.kwargs["pk"])
|
instru = get_object_or_404(self.model, id=self.kwargs["pk"])
|
||||||
form = ChefEditInstrumentForm(request.POST, instance=instru)
|
form = ChefEditInstrumentForm(request.POST, instance=instru)
|
||||||
if request.user.profile.is_chef:
|
if request.user.profile.is_chef or request.user.profile.is_chef_instru:
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
context = self.get_context_data()
|
context = self.get_context_data()
|
||||||
context["form"] = form
|
context["form"] = form
|
||||||
|
print(instru.user)
|
||||||
return render(request, self.template_name, context)
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Ernestophone.settings.local")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Ernestophone.settings")
|
||||||
|
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
|
80
npins/default.nix
Normal file
80
npins/default.nix
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
# Generated by npins. Do not modify; will be overwritten regularly
|
||||||
|
let
|
||||||
|
data = builtins.fromJSON (builtins.readFile ./sources.json);
|
||||||
|
version = data.version;
|
||||||
|
|
||||||
|
mkSource =
|
||||||
|
spec:
|
||||||
|
assert spec ? type;
|
||||||
|
let
|
||||||
|
path =
|
||||||
|
if spec.type == "Git" then
|
||||||
|
mkGitSource spec
|
||||||
|
else if spec.type == "GitRelease" then
|
||||||
|
mkGitSource spec
|
||||||
|
else if spec.type == "PyPi" then
|
||||||
|
mkPyPiSource spec
|
||||||
|
else if spec.type == "Channel" then
|
||||||
|
mkChannelSource spec
|
||||||
|
else
|
||||||
|
builtins.throw "Unknown source type ${spec.type}";
|
||||||
|
in
|
||||||
|
spec // { outPath = path; };
|
||||||
|
|
||||||
|
mkGitSource =
|
||||||
|
{
|
||||||
|
repository,
|
||||||
|
revision,
|
||||||
|
url ? null,
|
||||||
|
hash,
|
||||||
|
branch ? null,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
assert repository ? type;
|
||||||
|
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
|
||||||
|
# In the latter case, there we will always be an url to the tarball
|
||||||
|
if url != null then
|
||||||
|
(builtins.fetchTarball {
|
||||||
|
inherit url;
|
||||||
|
sha256 = hash; # FIXME: check nix version & use SRI hashes
|
||||||
|
})
|
||||||
|
else
|
||||||
|
assert repository.type == "Git";
|
||||||
|
let
|
||||||
|
urlToName =
|
||||||
|
url: rev:
|
||||||
|
let
|
||||||
|
matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
|
||||||
|
|
||||||
|
short = builtins.substring 0 7 rev;
|
||||||
|
|
||||||
|
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
|
||||||
|
in
|
||||||
|
"${if matched == null then "source" else builtins.head matched}${appendShort}";
|
||||||
|
name = urlToName repository.url revision;
|
||||||
|
in
|
||||||
|
builtins.fetchGit {
|
||||||
|
url = repository.url;
|
||||||
|
rev = revision;
|
||||||
|
inherit name;
|
||||||
|
# hash = hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkPyPiSource =
|
||||||
|
{ url, hash, ... }:
|
||||||
|
builtins.fetchurl {
|
||||||
|
inherit url;
|
||||||
|
sha256 = hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkChannelSource =
|
||||||
|
{ url, hash, ... }:
|
||||||
|
builtins.fetchTarball {
|
||||||
|
inherit url;
|
||||||
|
sha256 = hash;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
if version == 3 then
|
||||||
|
builtins.mapAttrs (_: mkSource) data.pins
|
||||||
|
else
|
||||||
|
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
|
22
npins/sources.json
Normal file
22
npins/sources.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"pins": {
|
||||||
|
"nix-pkgs": {
|
||||||
|
"type": "Git",
|
||||||
|
"repository": {
|
||||||
|
"type": "Git",
|
||||||
|
"url": "https://git.hubrecht.ovh/hubrecht/nix-pkgs.git"
|
||||||
|
},
|
||||||
|
"branch": "main",
|
||||||
|
"revision": "cc01e1c2a6ecb1e38fde35ee54995a6a639fb057",
|
||||||
|
"url": null,
|
||||||
|
"hash": "17a9vlwrk9365ccyl7a5xspqsn9wizcpwdpvr3qdimvq4fpwhjal"
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"type": "Channel",
|
||||||
|
"name": "nixpkgs-unstable",
|
||||||
|
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.05pre723402.4989a246d7a3/nixexprs.tar.xz",
|
||||||
|
"hash": "0hjng6rhkjiql1dqbanjm6jl6npik29q2lmba032j897fhyzin91"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": 3
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ from django.urls import reverse_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
|
||||||
|
|
||||||
from gestion.mixins import ChefRequiredMixin, ChefEventRequiredMixin
|
from gestion.mixins import ChefEventRequiredMixin, ChefRequiredMixin
|
||||||
from pads.models import Pad
|
from pads.models import Pad
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import Category, PartitionSet
|
from .models import Category, Partition, PartitionSet, SetList
|
||||||
|
|
||||||
|
|
||||||
|
class PartitionAdmin(admin.ModelAdmin):
|
||||||
|
list_filter = ("morceau",)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Category)
|
admin.site.register(Category)
|
||||||
admin.site.register(PartitionSet)
|
admin.site.register(PartitionSet)
|
||||||
|
admin.site.register(SetList)
|
||||||
|
admin.site.register(Partition, PartitionAdmin)
|
||||||
|
|
44
partitions/migrations/0005_setlist.py
Normal file
44
partitions/migrations/0005_setlist.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# 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)",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
22
partitions/migrations/0006_auto_20220118_1525.py
Normal file
22
partitions/migrations/0006_auto_20220118_1525.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# 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",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
22
partitions/migrations/0007_auto_20220118_1542.py
Normal file
22
partitions/migrations/0007_auto_20220118_1542.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# 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,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib import admin
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.functions import Lower
|
from django.db.models.functions import Lower
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -33,8 +34,8 @@ class Partition(models.Model):
|
||||||
super(Partition, self).delete(*args, **kwargs)
|
super(Partition, self).delete(*args, **kwargs)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Morceau")
|
verbose_name = _("Partition")
|
||||||
verbose_name_plural = _("Morceaux")
|
verbose_name_plural = _("Partitions")
|
||||||
ordering = (Lower("nom"),)
|
ordering = (Lower("nom"),)
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,4 +70,43 @@ class PartitionSet(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Morceau")
|
verbose_name = _("Morceau")
|
||||||
verbose_name_plural = _("Morceaux")
|
verbose_name_plural = _("Morceaux")
|
||||||
ordering = (Lower("nom"),)
|
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)
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<a href="{% url "partitions:listepart" partition.nom partition.auteur %}"
|
<a href="{% url "partitions:listepart" partition.nom partition.auteur %}"
|
||||||
class="fichier">{{ partition.nom }} - {{ partition.auteur }}</a>
|
class="fichier">{{ partition.nom }} - {{ partition.auteur }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.profile.is_chef %}
|
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||||
<a href="{% url "partitions:conf_delete_morc" partition.nom partition.auteur %}"
|
<a href="{% url "partitions:conf_delete_morc" partition.nom partition.auteur %}"
|
||||||
class="supprimer">Supprimer</a>
|
class="supprimer">Supprimer</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="info_part">
|
<div class="info_part">
|
||||||
{% if user.profile.is_chef %}
|
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||||
<form action="{% url "partitions:listepart" nom auteur %}" id="chef-edit-form" method="post">
|
<form action="{% url "partitions:listepart" nom auteur %}" id="chef-edit-form" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
<a href="{% url "partitions:download" nom auteur p.id %}" class="telecharger">Télécharger</a>
|
<a href="{% url "partitions:download" nom auteur p.id %}" class="telecharger">Télécharger</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if user.profile.is_chef %}
|
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||||
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="supprimer">Supprimer</a>
|
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="supprimer">Supprimer</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -28,15 +28,17 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for p in part %}
|
{% for p in part %}
|
||||||
{% if user.is_authenticated and ".mscz" in p.part.url %}
|
{% if user.is_authenticated and ".mscz" in p.part.url %}
|
||||||
|
<tr>
|
||||||
<td><p class="fichier">{{ p.nom }}</p></td>
|
<td><p class="fichier">{{ p.nom }}</p></td>
|
||||||
|
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% 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>
|
<td> <a href="{% url "partitions:download" nom auteur p.id %}" class="button icon fa-download">{% trans "Télécharger" %}</a></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.profile.is_chef %} <td>
|
{% if user.profile.is_chef or user.profile.is_chef_mu %} <td>
|
||||||
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="button icon fa-deleate">{% trans "Supprimer" %}</a></td>
|
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="button icon fa-deleate">{% trans "Supprimer" %}</a></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for p in part %}
|
{% for p in part %}
|
||||||
|
@ -54,7 +56,7 @@
|
||||||
{% if user.is_authenticated %}
|
{% 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>
|
<td> <a href="{% url "partitions:download" nom auteur p.id %}" class="button icon fa-download">{% trans "Télécharger" %}</a></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.profile.is_chef %} <td>
|
{% if user.profile.is_chef or user.profile.is_chef_mu %} <td>
|
||||||
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="button icon fa-deleate">{% trans "Supprimer" %}</a></td>
|
<a href="{% url "partitions:conf_delete" nom auteur p.pk %}" class="button icon fa-deleate">{% trans "Supprimer" %}</a></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -65,7 +67,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% if user.profile.is_chef %}
|
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||||
<p><a href="{% url "partitions:upload" p.nom p.auteur %}" class='button'>{% trans "Ajouter un média" %}</a></p>
|
<p><a href="{% url "partitions:upload" p.nom p.auteur %}" class='button'>{% trans "Ajouter un média" %}</a></p>
|
||||||
|
|
||||||
{% if infos or infos_en %}
|
{% if infos or infos_en %}
|
||||||
|
@ -86,7 +88,7 @@
|
||||||
<p></p>
|
<p></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="6u 12u$(small)">
|
<div class="6u 12u$(small)">
|
||||||
{% if user.profile.is_chef %}
|
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||||
<form action="{% url "partitions:listepart" nom auteur %}" id="chef-edit-form" method="post">
|
<form action="{% url "partitions:listepart" nom auteur %}" id="chef-edit-form" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
|
|
|
@ -7,6 +7,20 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<section class="wrapper style1">
|
<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">
|
<div class="inner">
|
||||||
|
|
||||||
<span class="image fit">
|
<span class="image fit">
|
||||||
|
@ -23,7 +37,7 @@
|
||||||
<div class="icon fa-copyright" style="color:#000000"> Lucas Gierzack</div></div>
|
<div class="icon fa-copyright" style="color:#000000"> Lucas Gierzack</div></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
{% if user.profile.is_chef %}
|
{% if user.profile.is_chef or user.profile.is_chef_mu %}
|
||||||
<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>
|
<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 %}
|
{% elif user.is_authenticated %}
|
||||||
<a href="{% url "partitions:download_musecores" %}" class="button alt big">{% trans "Télécharger tous les musecores actifs" %}</a>
|
<a href="{% url "partitions:download_musecores" %}" class="button alt big">{% trans "Télécharger tous les musecores actifs" %}</a>
|
||||||
|
@ -66,7 +80,7 @@
|
||||||
<td> <u><a href="{% url "partitions:listepart" partition.nom partition.auteur %}"
|
<td> <u><a href="{% url "partitions:listepart" partition.nom partition.auteur %}"
|
||||||
class="fichier">{{ partition.nom }}</a> </td>
|
class="fichier">{{ partition.nom }}</a> </td>
|
||||||
<td> {{ partition.auteur }} </a></u> </td>
|
<td> {{ partition.auteur }} </a></u> </td>
|
||||||
{% if user.profile.is_chef %}<td>
|
{% if user.profile.is_chef or user.profile.is_chef_mu %}<td>
|
||||||
|
|
||||||
<a href="{% url "partitions:conf_delete_morc" partition.nom partition.auteur %}"
|
<a href="{% url "partitions:conf_delete_morc" partition.nom partition.auteur %}"
|
||||||
class="button small icon fa-trash">{% trans "Supprimer" %}</a></td>
|
class="button small icon fa-trash">{% trans "Supprimer" %}</a></td>
|
||||||
|
|
21
partitions/templates/partitions/setlist_confirm_delete.html
Normal file
21
partitions/templates/partitions/setlist_confirm_delete.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{% 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 %}
|
18
partitions/templates/partitions/setlist_form.html
Normal file
18
partitions/templates/partitions/setlist_form.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{% 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 %}
|
31
partitions/templates/partitions/setlist_list.html
Normal file
31
partitions/templates/partitions/setlist_list.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{% 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,6 +6,14 @@ app_name = "partitions"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", views.Repertoire.as_view(), name="liste"),
|
path("", views.Repertoire.as_view(), name="liste"),
|
||||||
path("download", views.download_musecores, name="download_musecores"),
|
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>/upload", views.Upload.as_view(), name="upload"),
|
||||||
path("<str:nom>/<str:auteur>", views.Morceau.as_view(), name="listepart"),
|
path("<str:nom>/<str:auteur>", views.Morceau.as_view(), name="listepart"),
|
||||||
path("<str:nom>/<str:auteur>/see/<int:partition_id>", views.see, name="see"),
|
path("<str:nom>/<str:auteur>/see/<int:partition_id>", views.see, name="see"),
|
||||||
|
|
|
@ -7,15 +7,17 @@ from django.core.files import File
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import HttpResponse, get_object_or_404, redirect, render
|
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.safestring import mark_safe
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import (CreateView, DeleteView, ListView,
|
||||||
|
TemplateView, UpdateView)
|
||||||
|
|
||||||
from gestion.mixins import ChefRequiredMixin
|
from gestion.mixins import ChefMuRequiredMixin
|
||||||
from gestion.models import Photo
|
from gestion.models import Photo
|
||||||
from partitions.forms import UploadFileForm, UploadMorceauForm
|
from partitions.forms import UploadFileForm, UploadMorceauForm
|
||||||
from partitions.models import Category, Partition, PartitionSet
|
from partitions.models import Category, Partition, PartitionSet, SetList
|
||||||
|
|
||||||
from .forms import ChefEditMorceauForm
|
from .forms import ChefEditMorceauForm
|
||||||
|
|
||||||
|
@ -69,11 +71,21 @@ def download_musecores(request):
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
from datetime import date, timedelta
|
||||||
|
|
||||||
|
|
||||||
class Repertoire(TemplateView):
|
class Repertoire(TemplateView):
|
||||||
template_name = "partitions/repertoire.html"
|
template_name = "partitions/repertoire.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**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(
|
context["categories"] = Category.objects.prefetch_related(
|
||||||
"partitionset_set"
|
"partitionset_set"
|
||||||
).order_by("order")
|
).order_by("order")
|
||||||
|
@ -94,7 +106,6 @@ class Morceau(LoginRequiredMixin, TemplateView):
|
||||||
form = self.form_class(instance=p)
|
form = self.form_class(instance=p)
|
||||||
infos = mark_safe(p.infos)
|
infos = mark_safe(p.infos)
|
||||||
infos_en = mark_safe(p.infos_en)
|
infos_en = mark_safe(p.infos_en)
|
||||||
|
|
||||||
context["p"] = p
|
context["p"] = p
|
||||||
context["infos"] = infos
|
context["infos"] = infos
|
||||||
context["infos_en"] = infos_en
|
context["infos_en"] = infos_en
|
||||||
|
@ -117,7 +128,7 @@ class Morceau(LoginRequiredMixin, TemplateView):
|
||||||
return render(request, self.template_name, context)
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
class Upload(ChefRequiredMixin, TemplateView):
|
class Upload(ChefMuRequiredMixin, TemplateView):
|
||||||
form_class = UploadFileForm
|
form_class = UploadFileForm
|
||||||
template_name = "partitions/upload.html"
|
template_name = "partitions/upload.html"
|
||||||
|
|
||||||
|
@ -197,7 +208,7 @@ def see(request, nom, auteur, partition_id):
|
||||||
return redirect("login")
|
return redirect("login")
|
||||||
|
|
||||||
|
|
||||||
class DeletePart(ChefRequiredMixin, TemplateView):
|
class DeletePart(ChefMuRequiredMixin, TemplateView):
|
||||||
model = PartitionSet
|
model = PartitionSet
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
@ -214,7 +225,7 @@ class DeletePart(ChefRequiredMixin, TemplateView):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CreateMorc(ChefRequiredMixin, TemplateView):
|
class CreateMorc(ChefMuRequiredMixin, TemplateView):
|
||||||
form_class = UploadMorceauForm
|
form_class = UploadMorceauForm
|
||||||
template_name = "partitions/new.html"
|
template_name = "partitions/new.html"
|
||||||
|
|
||||||
|
@ -259,7 +270,7 @@ class CreateMorc(ChefRequiredMixin, TemplateView):
|
||||||
return render(request, self.template_name, context)
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
class ConfDelete(ChefRequiredMixin, TemplateView):
|
class ConfDelete(ChefMuRequiredMixin, TemplateView):
|
||||||
template_name = "partitions/conf_delete.html"
|
template_name = "partitions/conf_delete.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -270,7 +281,7 @@ class ConfDelete(ChefRequiredMixin, TemplateView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class DeleteMorc(ChefRequiredMixin, TemplateView):
|
class DeleteMorc(ChefMuRequiredMixin, TemplateView):
|
||||||
model = PartitionSet
|
model = PartitionSet
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
@ -284,7 +295,7 @@ class DeleteMorc(ChefRequiredMixin, TemplateView):
|
||||||
return redirect("partitions:liste")
|
return redirect("partitions:liste")
|
||||||
|
|
||||||
|
|
||||||
class ConfDeleteMorc(ChefRequiredMixin, TemplateView):
|
class ConfDeleteMorc(ChefMuRequiredMixin, TemplateView):
|
||||||
template_name = "partitions/conf_delete_morc.html"
|
template_name = "partitions/conf_delete_morc.html"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -313,3 +324,27 @@ def download(request, nom, auteur, partition_id):
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
return redirect("login")
|
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")
|
||||||
|
|
0
propositions/admin.py
Normal file
0
propositions/admin.py
Normal file
38
propositions/migrations/0001_initial.py
Normal file
38
propositions/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# -*- 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)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
18
propositions/migrations/0002_nom_verbose_name.py
Normal file
18
propositions/migrations/0002_nom_verbose_name.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,75 @@
|
||||||
|
# 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"),
|
||||||
|
]
|
43
propositions/migrations/0004_prop_renaming_and_cleaning.py
Normal file
43
propositions/migrations/0004_prop_renaming_and_cleaning.py
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
24
propositions/migrations/0005_remove_nb_yes_no_fields.py
Normal file
24
propositions/migrations/0005_remove_nb_yes_no_fields.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# 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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
53
propositions/migrations/0006_proposition_profile_to_user.py
Normal file
53
propositions/migrations/0006_proposition_profile_to_user.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# 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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
19
propositions/migrations/0007_auto_20220322_1455.py
Normal file
19
propositions/migrations/0007_auto_20220322_1455.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
19
propositions/migrations/0008_auto_20220914_1244.py
Normal file
19
propositions/migrations/0008_auto_20220914_1244.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
19
propositions/migrations/0009_auto_20240615_1303.py
Normal file
19
propositions/migrations/0009_auto_20240615_1303.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
0
propositions/migrations/__init__.py
Normal file
0
propositions/migrations/__init__.py
Normal file
34
propositions/models.py
Normal file
34
propositions/models.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
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"
|
14
propositions/templates/propositions/create.html
Normal file
14
propositions/templates/propositions/create.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{% 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 %}
|
10
propositions/templates/propositions/delete.html
Normal file
10
propositions/templates/propositions/delete.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% 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 %}
|
44
propositions/templates/propositions/liste.html
Normal file
44
propositions/templates/propositions/liste.html
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{% 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 %}
|
165
propositions/tests.py
Normal file
165
propositions/tests.py
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
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]
|
||||||
|
)
|
13
propositions/urls.py
Normal file
13
propositions/urls.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
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"),
|
||||||
|
]
|
8
propositions/utils.py
Normal file
8
propositions/utils.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import string
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def generer(*args):
|
||||||
|
caracteres = string.ascii_letters + string.digits
|
||||||
|
aleatoire = [random.choice(caracteres) for _ in range(6)]
|
||||||
|
return ''.join(aleatoire)
|
63
propositions/views.py
Normal file
63
propositions/views.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
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,4 +0,0 @@
|
||||||
-r requirements.txt
|
|
||||||
|
|
||||||
django-debug-toolbar
|
|
||||||
ipython
|
|
|
@ -1,8 +0,0 @@
|
||||||
Django==2.2.*
|
|
||||||
|
|
||||||
# Pour la prod
|
|
||||||
#psycopg2
|
|
||||||
gunicorn
|
|
||||||
django-colorful
|
|
||||||
Pillow
|
|
||||||
django-avatar==5.0.*
|
|
46
shell.nix
Normal file
46
shell.nix
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
sources ? import ./npins,
|
||||||
|
pkgs ? import sources.nixpkgs {
|
||||||
|
overlays = [
|
||||||
|
(import "${sources.nix-pkgs}/overlay.nix").default
|
||||||
|
];
|
||||||
|
},
|
||||||
|
dev ? true,
|
||||||
|
}:
|
||||||
|
pkgs.mkShell {
|
||||||
|
packages = [
|
||||||
|
(pkgs.python3.withPackages (
|
||||||
|
ps:
|
||||||
|
[
|
||||||
|
ps.django
|
||||||
|
ps.django-avatar
|
||||||
|
ps.django-colorful
|
||||||
|
ps.gunicorn
|
||||||
|
ps.pillow
|
||||||
|
ps.loadcredential
|
||||||
|
]
|
||||||
|
++ (
|
||||||
|
if dev then
|
||||||
|
[
|
||||||
|
ps.ipython
|
||||||
|
ps.django-debug-toolbar
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[ ]
|
||||||
|
)
|
||||||
|
))
|
||||||
|
];
|
||||||
|
env = {
|
||||||
|
DJANGO_SETTINGS_MODULE = "Ernestophone.settings";
|
||||||
|
|
||||||
|
CREDENTIALS_DIRECTORY = builtins.toString ./.credentials;
|
||||||
|
|
||||||
|
ERNESTOPHONE_DEBUG = builtins.toJSON true;
|
||||||
|
ERNESTOPHONE_STATIC_ROOT = builtins.toString ./.static;
|
||||||
|
};
|
||||||
|
shellHook = ''
|
||||||
|
if [ ! -d .static ]; then
|
||||||
|
mkdir .static
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
}
|
|
@ -12,7 +12,7 @@
|
||||||
<p>{% trans "Avatar courant: " %}</p>
|
<p>{% trans "Avatar courant: " %}</p>
|
||||||
{% avatar user %}
|
{% avatar user %}
|
||||||
|
|
||||||
<form enctype="multipart/form-data" method="POST" action="{% url 'avatar_add' %}">
|
<form enctype="multipart/form-data" method="POST" action="{% url 'avatar:add' %}">
|
||||||
{{ upload_avatar_form.as_p }}
|
{{ upload_avatar_form.as_p }}
|
||||||
<p>{% csrf_token %}<input type="submit" value="{% trans "Ajouter une nouvelle image" %}" /></p>
|
<p>{% csrf_token %}<input type="submit" value="{% trans "Ajouter une nouvelle image" %}" /></p>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<p>{% trans "Tu n'as pas encore ajouté d'avatar. Le logo Ernestophone sera utilisé par defaut." %}</p>
|
<p>{% trans "Tu n'as pas encore ajouté d'avatar. Le logo Ernestophone sera utilisé par defaut." %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form enctype="multipart/form-data" method="POST" action="{% url 'avatar_add' %}">
|
<form enctype="multipart/form-data" method="POST" action="{% url 'avatar:add' %}">
|
||||||
{{ upload_avatar_form.as_p }}
|
{{ upload_avatar_form.as_p }}
|
||||||
<p>{% csrf_token %}<input type="submit" value="{% trans "Modifier mon avatar" %}" /></p>
|
<p>{% csrf_token %}<input type="submit" value="{% trans "Modifier mon avatar" %}" /></p>
|
||||||
</form>
|
</form>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
<a href="{% url "trombonoscope:change" %}" class="button alt">{% trans "Retour au profil"%}</a>
|
<a href="{% url "trombonoscope:change" %}" class="button alt">{% trans "Retour au profil"%}</a>
|
||||||
{% if avatars %}
|
{% if avatars %}
|
||||||
<a class="button alt" href="{% url 'avatar_delete' %}">{% trans "Supprimer l'avatar "%}</a>
|
<a class="button alt" href="{% url 'avatar:delete' %}">{% trans "Supprimer l'avatar "%}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div></div></div></section></div>
|
</div></div></div></section></div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -26,9 +26,9 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a class="button alt" href="{% url 'avatar_change' %}">{% trans "Changer l'avatar "%}</a>
|
<a class="button alt" href="{% url 'avatar:change' %}">{% trans "Changer l'avatar "%}</a>
|
||||||
{% if request.user|has_avatar %}
|
{% if request.user|has_avatar %}
|
||||||
<a class="button alt" href="{% url 'avatar_delete' %}">{% trans "Supprimer l'avatar "%}</a>
|
<a class="button alt" href="{% url 'avatar:delete' %}">{% trans "Supprimer l'avatar "%}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,12 @@
|
||||||
<div class="6u 12u$(small)">
|
<div class="6u 12u$(small)">
|
||||||
<h2>{% trans "Suppression de l'avatar" %} :</h2>
|
<h2>{% trans "Suppression de l'avatar" %} :</h2>
|
||||||
{% if not avatars %}
|
{% if not avatars %}
|
||||||
{% url 'avatar_change' as avatar_change_url %}
|
{% url 'avatar:change' as avatar_change_url %}
|
||||||
<p>{% trans "Vous n'avez pas d'avatar à supprimer."%}</p>
|
<p>{% trans "Vous n'avez pas d'avatar à supprimer."%}</p>
|
||||||
<a href="{{ avatar_change_url }}" class="button">{% trans "Télécharger un avatar" %}</a> <a href="{% url "trombonoscope:change" %}" class="button alt">{% trans "Retour au profil"%}</a>
|
<a href="{{ avatar_change_url }}" class="button">{% trans "Télécharger un avatar" %}</a> <a href="{% url "trombonoscope:change" %}" class="button alt">{% trans "Retour au profil"%}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{% trans "Séléctione l'avatar pour le supprimer" %}</p>
|
<p>{% trans "Séléctione l'avatar pour le supprimer" %}</p>
|
||||||
<form method="POST" action="{% url 'avatar_delete' %}">
|
<form method="POST" action="{% url 'avatar:delete' %}">
|
||||||
|
|
||||||
|
|
||||||
{% for field in delete_avatar_form %}
|
{% for field in delete_avatar_form %}
|
||||||
|
|
Loading…
Add table
Reference in a new issue