corrections + class views

This commit is contained in:
Lucie Galland 2021-04-29 00:27:33 +02:00
parent 406f92098f
commit 6ba168d286
81 changed files with 2756 additions and 2736 deletions

View file

@ -1,4 +1,5 @@
import os
from django.utils.translation import gettext_lazy as _
try:
@ -31,64 +32,60 @@ DBPASSWD = import_secret("DBPASSWD")
ACCOUNT_CREATION_PASS = import_secret("ACCOUNT_CREATION_PASS")
BASE_DIR = os.path.join(
os.path.dirname(__file__), "..", ".."
)
BASE_DIR = os.path.join(os.path.dirname(__file__), "..", "..")
INSTALLED_APPS = [
'trombonoscope',
'actu',
'colorful',
'pads',
'calendrier',
'gestion.apps.GestionConfig',
'partitions.apps.PartitionsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'avatar',
'instruments',
"trombonoscope",
"actu",
"colorful",
"pads",
"calendrier",
"gestion.apps.GestionConfig",
"partitions.apps.PartitionsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"avatar",
"instruments",
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.locale.LocaleMiddleware',
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.middleware.locale.LocaleMiddleware",
]
ROOT_URLCONF = "Ernestophone.urls"
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'libraries':{
'changelang': 'gestion.templatetags.changelang',
'modulo': 'gestion.templatetags.modulo',
'autotranslate': 'gestion.templatetags.autotranslate',
'halflength': 'gestion.templatetags.halflength',
}
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
"libraries": {
"changelang": "gestion.templatetags.changelang",
"modulo": "gestion.templatetags.modulo",
"autotranslate": "gestion.templatetags.autotranslate",
"halflength": "gestion.templatetags.halflength",
},
},
}
}]
]
WSGI_APPLICATION = "Ernestophone.wsgi.application"
@ -104,51 +101,51 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# I18n
# I18n
LANGUAGE_CODE = 'fr'
LANGUAGE_CODE = "fr"
LANGUAGES = (
('fr', _('Français')),
('en', _('English')),
("fr", _("Français")),
("en", _("English")),
)
TIME_ZONE = 'UTC'
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
LOCALE_PATHS = ( os.path.join(BASE_DIR, 'locale'), )
LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),)
AUTH_PROFILE_MODEL = 'gestion.ErnestoUser'
AUTH_PROFILE_MODEL = "gestion.ErnestoUser"
LOGIN_URL = "/login"
AVATAR_CLEANUP_DELETED = True
AVATAR_AUTO_GENERATE_SIZES = (250,)
AVATAR_CHANGE_TEMPLATE = "trombonoscope/change_avatar.html"
AVATAR_MAX_AVATARS_PER_USER=1
AVATAR_EXPOSE_USERNAMES=False
AVATAR_STORAGE_DIR="trombonoscope"
AVATAR_ADD_TEMPLATE="trombonoscope/add_avatar.html"
AVATAR_DELETE_TEMPLATE="trombonoscope/delete_avatar.html"
AVATAR_DEFAULT_URL="Ernesto"
AVATAR_PROVIDERS=(
'avatar.providers.PrimaryAvatarProvider',
'avatar.providers.DefaultAvatarProvider',
)
AVATAR_THUMB_FORMAT = 'JPEG'
AVATAR_MAX_AVATARS_PER_USER = 1
AVATAR_EXPOSE_USERNAMES = False
AVATAR_STORAGE_DIR = "trombonoscope"
AVATAR_ADD_TEMPLATE = "trombonoscope/add_avatar.html"
AVATAR_DELETE_TEMPLATE = "trombonoscope/delete_avatar.html"
AVATAR_DEFAULT_URL = "Ernesto"
AVATAR_PROVIDERS = (
"avatar.providers.PrimaryAvatarProvider",
"avatar.providers.DefaultAvatarProvider",
)
AVATAR_THUMB_FORMAT = "JPEG"

View file

@ -1,19 +1,14 @@
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
)
MIDDLEWARE = ["debug_toolbar.middleware.DebugToolbarMiddleware"] + MIDDLEWARE
STATIC_URL = "/static/"
STATIC_ROOT = "static"

View file

@ -3,7 +3,6 @@ import os
from .common import * # noqa
from .common import BASE_DIR
DEBUG = False
ALLOWED_HOSTS = [
@ -12,11 +11,7 @@ ALLOWED_HOSTS = [
]
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(
BASE_DIR, "..", "..", "public", "ernesto", "static"
)
STATIC_ROOT = os.path.join(BASE_DIR, "..", "..", "public", "ernesto", "static")
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(
BASE_DIR, "..", "media"
)
MEDIA_ROOT = os.path.join(BASE_DIR, "..", "media")

View file

@ -13,37 +13,39 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from gestion import views as gestion_views
from django.contrib.auth import views as auth_views
import django.contrib.auth.urls as urls
from django.conf.urls.static import static
from django.conf import settings
from django.conf.urls.i18n import i18n_patterns
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.auth import views as auth_views
from django.urls import include, path
from gestion import views as gestion_views
urlpatterns = []
urlpatterns += i18n_patterns(
path('', gestion_views.home, name="home"),
path("registration", gestion_views.inscription_membre, name="registration"),
path("change", gestion_views.change_membre, name="change_membre"),
path("password", gestion_views.change_password, name="change_password"),
path("thanks", gestion_views.thanks, name="thanks"),
path("changename", gestion_views.changename, name="change-doodle-name"),
path("logout", auth_views.LogoutView.as_view(next_page="home"), name="logout"),
path("", gestion_views.Home.as_view(), name="home"),
path("registration", gestion_views.Inscription.as_view(),
name="registration"),
path("change", gestion_views.ChangeMembre.as_view(), name="change_membre"),
path("password", gestion_views.ChangePassword.as_view(),
name="change_password"),
path("thanks", gestion_views.Thanks.as_view(), name="thanks"),
path("changename", gestion_views.ChangeName.as_view(), name="change-doodle-name"),
path("logout", auth_views.LogoutView.as_view(next_page="home"),
name="logout"),
path("login", gestion_views.MyLoginView.as_view(), name="login"),
path("agenda/", include("calendrier.urls", namespace="calendrier")),
path("partitions/", include("partitions.urls")),
path("instruments/", include("instruments.urls")),
path("pads/", include("pads.urls")),
path(
"login",
gestion_views.MyLoginView.as_view(),
name="login"
"admin/",
admin.site.urls,
),
path('agenda/', include('calendrier.urls',namespace='calendrier')),
path('partitions/', include('partitions.urls')),
path('instruments/', include('instruments.urls')),
path('pads/', include('pads.urls')),
path('admin/', admin.site.urls,),
path('trombonoscope/',include('trombonoscope.urls')),
path("actu/",include('actu.urls')),
path('avatar/', include('avatar.urls')),
prefix_default_language=False )
path("trombonoscope/", include("trombonoscope.urls")),
path("actu/", include("actu.urls")),
path("avatar/", include("avatar.urls")),
prefix_default_language=False,
)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

@ -1,4 +1,3 @@
"""
WSGI config for Ernestophone project.
@ -10,10 +9,8 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
import os
os.environ.setdefault(
"DJANGO_SETTINGS_MODULE",
"Ernestophone.settings.prod"
)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Ernestophone.settings.prod")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

View file

@ -1,3 +1 @@
from django.contrib import admin
# Register your models here.

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class ActuConfig(AppConfig):
name = 'actu'
name = "actu"

View file

@ -7,22 +7,34 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='Actu',
name="Actu",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(null=True, verbose_name='Info')),
('text_en', models.TextField(blank=True, null=True, verbose_name='Info en anglais')),
('order', models.IntegerField(verbose_name='ordre')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("text", models.TextField(null=True, verbose_name="Info")),
(
"text_en",
models.TextField(
blank=True, null=True, verbose_name="Info en anglais"
),
),
("order", models.IntegerField(verbose_name="ordre")),
],
options={
'ordering': ('order',),
'verbose_name_plural': 'Actualités',
'verbose_name': 'Actualité',
"ordering": ("order",),
"verbose_name_plural": "Actualités",
"verbose_name": "Actualité",
},
),
]

View file

@ -1,14 +1,17 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
class Actu(models.Model):
text = models.TextField(_("Info"), null=True, blank=False)
text_en = models.TextField(("Info en anglais"), null=True, blank=True)
order = models.IntegerField(verbose_name=_("ordre"))
def __str__(self):
return self.text
class Meta:
verbose_name = _("Actualité")
verbose_name_plural = _("Actualités")
ordering = ('order',)
ordering = ("order",)

View file

@ -2,11 +2,10 @@ from django.urls import path
from actu import views
app_name = "actu"
urlpatterns = [
path("", views.ActuList.as_view(), name="liste"),
path("ajouter", views.ActuCreate.as_view(), name="add_actu"),
path("edition/<int:pk>", views.ActuUpdate.as_view(), name="edit_actu"),
path("supprimer/<int:pk>", views.ActuDelete.as_view(), name="delete_actu")
path("supprimer/<int:pk>", views.ActuDelete.as_view(), name="delete_actu"),
]

View file

@ -1,9 +1,9 @@
from django.shortcuts import render
from gestion.mixins import ChefRequiredMixin
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from django.urls import reverse_lazy
from actu.models import Actu
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from actu.models import Actu
from gestion.mixins import ChefRequiredMixin
class ActuList(ChefRequiredMixin, ListView):
@ -14,7 +14,7 @@ class ActuList(ChefRequiredMixin, ListView):
class ActuCreate(ChefRequiredMixin, CreateView):
model = Actu
fields = ["text","order","text_en"]
fields = ["text", "order", "text_en"]
template_name = "actu/create_actu.html"
success_url = reverse_lazy("actu:liste")
@ -26,7 +26,7 @@ class ActuCreate(ChefRequiredMixin, CreateView):
class ActuUpdate(ChefRequiredMixin, UpdateView):
model = Actu
fields = ["text","order","text_en"]
fields = ["text", "order", "text_en"]
template_name = "actu/update_actu.html"
success_url = reverse_lazy("actu:liste")

View file

@ -1,6 +1,5 @@
from django.contrib import admin
from .models import Event
admin.site.register(Event)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class CalendrierConfig(AppConfig):
name = 'calendrier'
name = "calendrier"

View file

@ -1,44 +1,44 @@
from django.utils.html import conditional_escape as esc
from itertools import groupby
from calendar import HTMLCalendar
from django.utils.translation import gettext_lazy as _
from datetime import date
from itertools import groupby
from django.utils.html import conditional_escape as esc
from django.utils.translation import gettext_lazy as _
class EventCalendar(HTMLCalendar):
def __init__(self, pEvents):
super(EventCalendar, self).__init__()
self.events = self.group_by_day(pEvents.order_by('date'))
self.events = self.group_by_day(pEvents.order_by("date"))
def formatday(self, day, weekday):
if day != 0:
cssclass = self.cssclasses[weekday]
if date.today() == date(self.year, self.month, day):
cssclass += ' today'
cssclass += " today"
if day in self.events:
cssclass += ' filled'
cssclass += " filled"
body = []
for ev in self.events[day]:
body.append(_('<a href="/agenda/') + '%s">' % ev.id)
body.append(esc(ev.nom))
body.append('</a><br/>')
return self.day_cell(cssclass,
'<div class="dayNumber">%d</div> %s'
% (day, ''.join(body)))
return self.day_cell(cssclass,
'<div class="dayNumber">%d</div>' % day)
return self.day_cell('noday', '&nbsp;')
body.append("</a><br/>")
return self.day_cell(
cssclass,
'<div class="dayNumber">%d</div> %s' % (day, "".join(body)),
)
return self.day_cell(cssclass, '<div class="dayNumber">%d</div>' % day)
return self.day_cell("noday", "&nbsp;")
def formatmonth(self, year, month):
self.year, self.month = year, month
return super(EventCalendar, self).formatmonth(year, month)
def group_by_day(self, pEvents):
def field(ev): return(ev.date.day)
return dict(
[(dat, list(items)) for dat, items in groupby(pEvents, field)]
)
def field(ev):
return ev.date.day
return dict([(dat, list(items)) for dat, items in groupby(pEvents, field)])
def day_cell(self, cssclass, body):
return '<td class="%s">%s</td>' % (cssclass, body)

View file

@ -1,61 +1,59 @@
from django import forms
from django.utils.translation import gettext_lazy as _
from calendrier.models import Event, Participants
from gestion.models import ErnestoUser
from django.utils.translation import gettext_lazy as _
class ModifEventForm(forms.ModelForm):
class Meta:
model = Event
exclude = ['slug']
exclude = ["slug"]
widgets = {
'description': forms.Textarea(attrs={
"placeholder": _("facultatif, balises html supportées")}),
'date': forms.TextInput(attrs={"placeholder": 'jj/mm/aaaa'}),
'debut': forms.TextInput(attrs={"placeholder": 'hh:mm'}),
'fin': forms.TextInput(attrs={"placeholder": _('hh:mm facultatif')})
"description": forms.Textarea(
attrs={"placeholder": _("facultatif, balises html supportées")}
),
"date": forms.TextInput(attrs={"placeholder": "jj/mm/aaaa"}),
"debut": forms.TextInput(attrs={"placeholder": "hh:mm"}),
"fin": forms.TextInput(attrs={"placeholder": _("hh:mm facultatif")}),
}
class EventForm(forms.ModelForm):
class Meta:
model = Event
exclude = ['slug']
exclude = ["slug"]
widgets = {
'nomcourt': forms.TextInput(
attrs={"placeholder": _('9 caractères max')}),
'description': forms.Textarea(
attrs={"placeholder": _("facultatif, balises html supportées")}),
'date': forms.TextInput(attrs={"placeholder": 'jj/mm/aaaa'}),
'debut': forms.TextInput(attrs={"placeholder": 'hh:mm'}),
'fin': forms.TextInput(attrs={"placeholder": _('hh:mm facultatif')}),
"nomcourt": forms.TextInput(attrs={"placeholder": _("9 caractères max")}),
"description": forms.Textarea(
attrs={"placeholder": _("facultatif, balises html supportées")}
),
"date": forms.TextInput(attrs={"placeholder": "jj/mm/aaaa"}),
"debut": forms.TextInput(attrs={"placeholder": "hh:mm"}),
"fin": forms.TextInput(attrs={"placeholder": _("hh:mm facultatif")}),
}
class ParticipantsForm(forms.ModelForm):
class Meta:
model = Participants
fields = ('reponse', 'details')
fields = ("reponse", "details")
widgets = {
'details': forms.Textarea(
attrs={"placeholder": _("50 caractères max")}),
"details": forms.Textarea(attrs={"placeholder": _("50 caractères max")}),
}
class ChangeDoodleName(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(ChangeDoodleName, self).__init__(*args, **kwargs)
self.fields['doodlename'].initial = self.instance.profile.get_doodlename()
self.fields["doodlename"].initial = self.instance.profile.get_doodlename()
def save(self, *args, **kwargs):
super(ChangeDoodleName, self).save(*args, **kwargs)
self.instance.profile.doodlename = self.cleaned_data['doodlename']
self.instance.profile.doodlename = self.cleaned_data["doodlename"]
self.instance.profile.save()
self.instance.save()
class Meta:
model = ErnestoUser
fields = ('doodlename',)
model = ErnestoUser
fields = ("doodlename",)

View file

@ -7,37 +7,82 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0001_initial'),
("gestion", "0001_initial"),
]
operations = [
migrations.CreateModel(
name='Event',
name="Event",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('nom', models.CharField(max_length=100)),
('nomcourt', models.CharField(max_length=9, verbose_name='Nom court')),
('date', models.DateField()),
('debut', models.TimeField()),
('fin', models.TimeField(blank=True, null=True)),
('slug', models.CharField(max_length=7, editable=False, unique=True)),
('lieu', models.CharField(max_length=200)),
('description', models.TextField(blank=True)),
('desc_users', models.TextField(blank=True, verbose_name='Infos (visible seulement des fanfaron-ne-s)', null=True)),
('calendrier', models.BooleanField(verbose_name='Afficher dans le calendrier pour tous', default=False)),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
("nom", models.CharField(max_length=100)),
("nomcourt", models.CharField(max_length=9, verbose_name="Nom court")),
("date", models.DateField()),
("debut", models.TimeField()),
("fin", models.TimeField(blank=True, null=True)),
("slug", models.CharField(max_length=7, editable=False, unique=True)),
("lieu", models.CharField(max_length=200)),
("description", models.TextField(blank=True)),
(
"desc_users",
models.TextField(
blank=True,
verbose_name="Infos (visible seulement des fanfaron-ne-s)",
null=True,
),
),
(
"calendrier",
models.BooleanField(
verbose_name="Afficher dans le calendrier pour tous",
default=False,
),
),
],
options={
'verbose_name': 'Événement',
"verbose_name": "Événement",
},
),
migrations.CreateModel(
name='Participants',
name="Participants",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('reponse', models.CharField(max_length=20, choices=[('oui', 'Oui'), ('non', 'Non'), ('pe', 'Peut-être')], default='non', verbose_name='Réponse')),
('details', models.CharField(blank=True, max_length=50)),
('event', models.ForeignKey(to='calendrier.Event', on_delete=models.CASCADE)),
('participant', models.ForeignKey(to='gestion.ErnestoUser', on_delete=models.CASCADE)),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
(
"reponse",
models.CharField(
max_length=20,
choices=[("oui", "Oui"), ("non", "Non"), ("pe", "Peut-être")],
default="non",
verbose_name="Réponse",
),
),
("details", models.CharField(blank=True, max_length=50)),
(
"event",
models.ForeignKey(to="calendrier.Event", on_delete=models.CASCADE),
),
(
"participant",
models.ForeignKey(
to="gestion.ErnestoUser", on_delete=models.CASCADE
),
),
],
),
]

View file

@ -1,43 +1,63 @@
# Generated by Django 2.2.14 on 2020-07-14 15:59
from django.db import migrations, models
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('calendrier', '0001_initial'),
("calendrier", "0001_initial"),
]
operations = [
migrations.AlterModelOptions(
name='event',
options={'verbose_name': 'Evenement'},
name="event",
options={"verbose_name": "Evenement"},
),
migrations.AddField(
model_name='event',
name='desc_users_en',
field=models.TextField(blank=True, null=True, verbose_name='Infos en anglais (visible seulement des fanfaron-ne-s)'),
model_name="event",
name="desc_users_en",
field=models.TextField(
blank=True,
null=True,
verbose_name="Infos en anglais (visible seulement des fanfaron-ne-s)",
),
),
migrations.AddField(
model_name='event',
name='description_en',
model_name="event",
name="description_en",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='event',
name='calendrier',
field=models.CharField(choices=[('F', 'Visible seulement par les fanfarons'), ('T', 'Afficher dans le calendrier pour tous'), ('H', 'Hall of fame')], default='F', max_length=1),
model_name="event",
name="calendrier",
field=models.CharField(
choices=[
("F", "Visible seulement par les fanfarons"),
("T", "Afficher dans le calendrier pour tous"),
("H", "Hall of fame"),
],
default="F",
max_length=1,
),
),
migrations.AlterField(
model_name='event',
name='slug',
field=models.CharField(default=uuid.uuid1, editable=False, max_length=7, unique=True),
model_name="event",
name="slug",
field=models.CharField(
default=uuid.uuid1, editable=False, max_length=7, unique=True
),
),
migrations.AlterField(
model_name='participants',
name='reponse',
field=models.CharField(choices=[('oui', 'Oui'), ('non', 'Non'), ('pe', 'Peut-etre')], default='non', max_length=20, verbose_name='Réponse'),
model_name="participants",
name="reponse",
field=models.CharField(
choices=[("oui", "Oui"), ("non", "Non"), ("pe", "Peut-etre")],
default="non",
max_length=20,
verbose_name="Réponse",
),
),
]

View file

@ -1,53 +1,62 @@
from django.db import models
import uuid
from gestion.models import ErnestoUser
from django.db import models
from django.utils.translation import gettext_lazy as _
from colorful.fields import RGBColorField
from gestion.models import ErnestoUser
ANSWERS = (
('oui', _('Oui')),
('non', _('Non')),
('pe', _('Peut-etre')),
)
("oui", _("Oui")),
("non", _("Non")),
("pe", _("Peut-etre")),
)
class Event(models.Model):
nom = models.CharField(max_length=100)
nomcourt = models.CharField(max_length=9, verbose_name=_("Nom court"))
date = models.DateField()
debut = models.TimeField()
fin = models.TimeField(blank=True, null=True)
slug = models.CharField(max_length=7, editable=False, unique=True, default=uuid.uuid1)
slug = models.CharField(
max_length=7, editable=False, unique=True, default=uuid.uuid1
)
lieu = models.CharField(max_length=200)
description = models.TextField(blank=True)
description_en = models.TextField(blank=True)
desc_users = models.TextField(
blank=True,
verbose_name=_("Infos (visible seulement des fanfaron-ne-s)"),
null=True)
blank=True,
verbose_name=_("Infos (visible seulement des fanfaron-ne-s)"),
null=True,
)
desc_users_en = models.TextField(
blank=True,
verbose_name=_("Infos en anglais (visible seulement des fanfaron-ne-s)"),
null=True)
blank=True,
verbose_name=_("Infos en anglais (visible seulement des fanfaron-ne-s"),
null=True,
)
CALENDRIER_CHOICES = [
('F', _('Visible seulement par les fanfarons')),
('T', _('Afficher dans le calendrier pour tous')),
('H', _('Hall of fame')),
("F", _("Visible seulement par les fanfarons")),
("T", _("Afficher dans le calendrier pour tous")),
("H", _("Hall of fame")),
]
calendrier = models.CharField(
max_length=1,
choices=CALENDRIER_CHOICES,
default='F',
default="F",
)
def __str__(self):
return self.nom
class Meta:
verbose_name = _("Evenement")
class Participants(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
participant = models.ForeignKey(ErnestoUser, on_delete=models.CASCADE)
reponse = models.CharField(_("Réponse"), max_length=20, default="non",
choices=ANSWERS)
reponse = models.CharField(
_("Réponse"), max_length=20, default="non", choices=ANSWERS
)
details = models.CharField(max_length=50, blank=True)

View file

@ -73,6 +73,24 @@
<div class="1u 12u$(small)"><p></p></div>
<div class="5u 12u$(small)">
<span class="image fit">
{% if photo %}
<img src="{{photo.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo.url %}
<a href="{{photo.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo.color}}"> {% if photo.auteur %}{{photo.auteur}}{%endif%}</a>
{% elif photo.auteur %}
<div class="icon fa-copyright" style="color: {{photo.color}}" > {{photo.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/home.png' %}"/>
<div style="position:absolute;z-index:1;right:0;bottom:0">
<div class="icon fa-copyright"> lor_tie</div>
</div>
{% endif %}
</span>
{% if events_a_venir_not_answered %}
<div class="box" style="background-color:#e4522f">
<h1> {% blocktrans count counter=events_a_venir_not_answered|length %}Doodle à remplir !!!! :{% plural %}Doodles à remplir !!!! :{% endblocktrans %} </h1>
@ -183,23 +201,6 @@
</div>
</div>
{% endif %}
<span class="image fit">
{% if photo %}
<img src="{{photo.image.url}}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
{% if photo.url %}
<a href="{{photo.url}}" target="_blank" class="icon fa-copyright" style="color: {{photo.color}}"> {% if photo.auteur %}{{photo.auteur}}{%endif%}</a>
{% elif photo.auteur %}
<div class="icon fa-copyright" style="color: {{photo.color}}" > {{photo.auteur}}</div>
{% endif %}
</div>
{% else %}
<img src="{% static 'images/home.png' %}"/>
<div style="position:absolute;z-index:1;right:0;bottom:0">
<div class="icon fa-copyright"> lor_tie</div>
</div>
{% endif %}
</span>
</div>
</div>

View file

@ -20,7 +20,7 @@ def translate(tex):
tex = tex.replace("December", "Décembre", 1)
tex = tex.replace("Mon", "Lun", 1)
tex = tex.replace("Tue", "Mar", 1)
tex = tex.replace('Wed', "Mer", 1)
tex = tex.replace("Wed", "Mer", 1)
tex = tex.replace("Thu", "Jeu", 1)
tex = tex.replace("Fri", "Ven", 1)
tex = tex.replace("Sat", "Sam", 1)

View file

@ -6,6 +6,7 @@ from django.test import Client, TestCase
from django.utils import timezone
from gestion.models import ErnestoUser
from ..models import Event
User = get_user_model()
@ -28,11 +29,7 @@ class TestViews(TestCase):
ernesto = new_user("ernesto", ernesto=True)
ernesto_c = Client()
ernesto_c.force_login(ernesto)
self.client_matrix = [
(chef, chef_c),
(ernesto, ernesto_c),
(None, Client())
]
self.client_matrix = [(chef, chef_c), (ernesto, ernesto_c), (None, Client())]
# A private and a public event
now = timezone.now()
later = now + timedelta(seconds=3600)
@ -44,7 +41,7 @@ class TestViews(TestCase):
fin=later.time(),
slug="privevt",
lieu="somewhere",
calendrier=False
calendrier=False,
)
self.pub_event = Event.objects.create(
nom="public event",
@ -54,7 +51,7 @@ class TestViews(TestCase):
fin=later.time(),
slug="pubevt",
lieu="somewhere",
calendrier=True
calendrier=True,
)
# Everyone can see theses pages
@ -88,13 +85,16 @@ class TestViews(TestCase):
chef, _ = self.client_matrix[0]
codereps = ["oui", "non", "pe"]
for coderep in codereps:
url = "/calendar/rep/{}/{}/{}".format(chef.profile.slug, self.priv_event.slug, coderep)
url = "/calendar/rep/{}/{}/{}".format(
chef.profile.slug, self.priv_event.slug, coderep
)
self._everyone_can_get(url, redirect_url="/calendar/")
# Only ernesto members can get theses pages
def _get_restricted_page(self, url, chef_only=False, redirect_url=None):
"""Shorthand for testing wether a page in only accessible by ernesto members"""
def user_allowed(user):
if user is None:
return False

View file

@ -1,17 +1,19 @@
from django.urls import path
from . import views
from .views import EventUpdate, EventDelete
from .views import EventDelete, EventUpdate
app_name = 'calendrier'
app_name = "calendrier"
urlpatterns = [
path('', views.liste, name='liste'),
path("calendar", views.home, name="home"),
path("new", views.create_event, name="create_event"),
path("", views.Agenda.as_view(), name="liste"),
path("calendar", views.Home.as_view(), name="home"),
path("new", views.CreateEvent.as_view(), name="create_event"),
path("edition/<int:pk>", EventUpdate.as_view(), name="edit_event"),
path("supprimer/<int:pk>", EventDelete.as_view(), name="delete_event"),
path("<int:id>/changename", views.changename, name="change-doodle-name"),
path("<int:id>/reponse", views.reponse, name="reponse"),
path("<int:pYear>/<int:pMonth>", views.calendar, name="view-month"),
path("<int:id>", views.view_event, name="view-event"),
path("<int:id>/changename", views.ChangeName.as_view(),
name="change-doodle-name"),
path("<int:id>/reponse", views.ReponseEvent.as_view(), name="reponse"),
path("<int:pYear>/<int:pMonth>", views.Calendar.as_view(),
name="view-month"),
path("<int:id>", views.ViewEvent.as_view(), name="view-event"),
]

View file

@ -1,217 +1,312 @@
import random
import string
from calendar import monthrange
from collections import defaultdict
from datetime import date, datetime
import string
import random
from django.db.models import Q
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.sites.shortcuts import get_current_site
from django.db.models import Count
from django.utils.safestring import mark_safe
from django.views.generic import UpdateView, DeleteView
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.core.mail import send_mail
from django.http import Http404
from django.utils.safestring import mark_safe
from django.views.generic import DeleteView, UpdateView
from gestion.models import ErnestoUser
from actu.models import Actu
from calendrier.calend import EventCalendar
from calendar import monthrange
from calendrier.forms import ModifEventForm, EventForm, ParticipantsForm, ChangeDoodleName
from calendrier.forms import (ChangeDoodleName, EventForm, ModifEventForm,
ParticipantsForm)
from calendrier.models import Event, Participants
from gestion.models import Photo
from partitions.decorators import chef_required
from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from gestion.mixins import ChefRequiredMixin
def generer(*args):
caracteres = string.ascii_letters + string.digits
aleatoire = [random.choice(caracteres) for _ in range(6)]
return ''.join(aleatoire)
def liste(request):
if request.user.is_authenticated :
return redirect('calendrier:home')
lToday = datetime.today()
photo = Photo.objects.filter(cat='liste').order_by('?').first()
events_a_venir = Event.objects.filter(date__gte = lToday).exclude(calendrier__iexact = 'F').order_by("-date")
events_passe = Event.objects.filter(date__lt = lToday).filter(calendrier__iexact = 'H').order_by("-date")
return render(request, 'calendrier/agenda.html', {"events_a_venir": events_a_venir,"events_passe":events_passe,"photo":photo})
return "".join(aleatoire)
def named_month(pMonthNumber):
return date(1900, pMonthNumber, 1).strftime('%B')
return date(1900, pMonthNumber, 1).strftime("%B")
@login_required
def home(request):
class Agenda(TemplateView):
template_name = "calendrier/agenda.html"
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
return redirect('calendrier:home')
return super(Agenda, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
lToday = datetime.today()
context['photo'] = Photo.objects.filter(
cat="liste").order_by("?").first()
context['events_a_venir'] = (
Event.objects.filter(date__gte=lToday)
.exclude(calendrier__iexact="F")
.order_by("-date")
)
context['events_passe'] = (
Event.objects.filter(date__lt=lToday)
.filter(calendrier__iexact="H")
.order_by("-date")
)
return context
class Calendar(LoginRequiredMixin, TemplateView):
template_name = "calendrier/home.html"
@property
def pYear(self):
return self.kwargs['pYear']
@property
def pMonth(self):
return self.kwargs['pMonth']
def get_context_data(self, **kwargs):
context = super(Calendar, self).get_context_data(**kwargs)
actu = Actu.objects.all()
photo = Photo.objects.filter(cat="home").order_by("?").first()
lToday = datetime.now()
lYear = int(self.pYear)
lMonth = int(self.pMonth)
lCalendarFromMonth = datetime(lYear, lMonth, 1)
lCalendarToMonth = datetime(lYear, lMonth,
monthrange(lYear, lMonth)[1])
lEvents = Event.objects.filter(
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
)
lCalendar = EventCalendar(lEvents).formatmonth(lYear, lMonth)
lPreviousYear = lYear
lPreviousMonth = lMonth - 1
if lPreviousMonth == 0:
lPreviousMonth = 12
lPreviousYear -= 1
lNextYear = lYear
lNextMonth = lMonth + 1
if lNextMonth == 13:
lNextMonth = 1
lNextYear = lYear + 1
lYearAfterThis = lYear + 1
lYearBeforeThis = lYear - 1
try:
events_a_venir_not_answered = Event.objects.filter(
date__gte=lToday).exclude(
participants__participant=self.request.user.profile
)
events_a_venir_answered_yes = Event.objects.filter(
date__gte=lToday).filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="oui")
)
events_a_venir_answered_no = Event.objects.filter(
date__gte=lToday).filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="non")
)
events_a_venir_answered_pe = Event.objects.filter(
date__gte=lToday).filter(
Q(participants__participant=self.request.user.profile)
& Q(participants__reponse="pe")
)
except Event.DoesNotExist:
events_a_venir_not_answered = Event.objects.filter(
date__gte=lToday).exclude(
participants__participant__user__username=self.request.user
)
events_a_venir_answered_yes = Event.objects.filter(
date__gte=lToday).filter(
Q(participants__participant__user__username=self.request.user)
& Q(participants__reponse="oui")
)
events_a_venir_answered_no = Event.objects.filter(
date__gte=lToday).filter(
Q(participants__participant__user__username=self.request.user)
& Q(participants__reponse="non")
)
events_a_venir_answered_pe = Event.objects.filter(
date__gte=lToday).filter(
Q(participants__participant__user__username=self.request.user)
& Q(participants__reponse="pe")
)
context["Calendar"] = mark_safe(lCalendar)
context["Month"] = lMonth
context["MonthName"] = named_month(lMonth)
context["Year"] = lYear
context["PreviousMonth"] = lPreviousMonth
context["PreviousMonthName"] = named_month(lPreviousMonth)
context["PreviousYear"] = lPreviousYear
context["NextMonth"] = lNextMonth
context["NextMonthName"] = named_month(lNextMonth)
context["NextYear"] = lNextYear
context["YearBeforeThis"] = lYearBeforeThis
context["YearAfterThis"] = lYearAfterThis
context["events_a_venir_answered_yes"] = events_a_venir_answered_yes
context["events_a_venir_answered_no"] = events_a_venir_answered_no
context["events_a_venir_answered_pe"] = events_a_venir_answered_pe
context["events_a_venir_not_answered"] = events_a_venir_not_answered
context["actu"] = actu
context["photo"] = photo
return context
class Home(Calendar):
lToday = datetime.now()
return calendar(request, lToday.year, lToday.month)
@login_required
def calendar(request, pYear, pMonth):
actu = Actu.objects.all()
photo = Photo.objects.filter(cat='home').order_by('?').first()
lToday = datetime.now()
lYear = int(pYear)
lMonth = int(pMonth)
lCalendarFromMonth = datetime(lYear, lMonth, 1)
lCalendarToMonth = datetime(lYear, lMonth, monthrange(lYear, lMonth)[1])
lEvents = Event.objects.filter(
date__gte=lCalendarFromMonth, date__lte=lCalendarToMonth
)
if request.user.is_authenticated:
lEvents = Event.objects.filter(date__gte=lCalendarFromMonth,
date__lte=lCalendarToMonth)
lCalendar = EventCalendar(lEvents).formatmonth(lYear, lMonth)
lPreviousYear = lYear
lPreviousMonth = lMonth - 1
if lPreviousMonth == 0:
lPreviousMonth = 12
lPreviousYear -= 1
lNextYear = lYear
lNextMonth = lMonth + 1
if lNextMonth == 13:
lNextMonth = 1
lNextYear = lYear + 1
lYearAfterThis = lYear + 1
lYearBeforeThis = lYear - 1
try:
events_a_venir_not_answered = Event.objects.filter(date__gte = lToday).exclude(participants__participant=request.user.profile)
events_a_venir_answered = Event.objects.filter(date__gte = lToday).filter(participants__participant=request.user.profile)
events_a_venir_answered_yes = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant=request.user.profile )& Q(participants__reponse= 'oui'))
events_a_venir_answered_no = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant=request.user.profile) & Q(participants__reponse= 'non'))
events_a_venir_answered_pe = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant=request.user.profile)& Q(participants__reponse= 'pe'))
except:
events_a_venir_not_answered = Event.objects.filter(date__gte = lToday).exclude(participants__participant__user__username=request.user)
events_a_venir_answered = Event.objects.filter(date__gte = lToday).filter(participants__participant__user__username=request.user)
events_a_venir_answered_yes = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant__user__username=request.user )& Q(participants__reponse= 'oui'))
events_a_venir_answered_no = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant__user__username=request.user) & Q(participants__reponse= 'non'))
events_a_venir_answered_pe = Event.objects.filter(date__gte = lToday).filter(Q(participants__participant__user__username=request.user)& Q(participants__reponse= 'pe'))
return render(request, 'calendrier/home.html', {
'Calendar': mark_safe(lCalendar),
'Month': lMonth,
'MonthName': named_month(lMonth),
'Year': lYear,
'PreviousMonth': lPreviousMonth,
'PreviousMonthName': named_month(lPreviousMonth),
'PreviousYear': lPreviousYear,
'NextMonth': lNextMonth,
'NextMonthName': named_month(lNextMonth),
'NextYear': lNextYear,
'YearBeforeThis': lYearBeforeThis,
'YearAfterThis': lYearAfterThis,
"events_a_venir_answered_yes": events_a_venir_answered_yes,
"events_a_venir_answered_no": events_a_venir_answered_no,
"events_a_venir_answered_pe": events_a_venir_answered_pe,
"events_a_venir_not_answered": events_a_venir_not_answered,
"actu" : actu,
"photo" : photo,
})
@property
def pYear(self):
return self.lToday.year
@login_required
def view_event(request, id):
event = get_object_or_404(Event, id=id)
participants = event.participants_set.all()
multi_instrumentistes = event.participants_set.filter(Q(participant__multi_instrumentiste = 'Oui')& ~Q(reponse = 'non'))
# Restricted event, only erneso users can see it
if not request.user.is_authenticated and not event.calendrier:
return redirect(reverse('calendrier:home'))
# Count the number of occurences of each instrument
instrument_count = defaultdict(lambda: (0, 0,[],[],[]))
for participant in participants:
instrument = participant.participant.instru
if (instrument == "Autre"):
instrument = participant.participant.instru_autre
sure, maybe, namesoui, namespe, namesnon = instrument_count[instrument]
if participant.reponse == "oui":
namesoui += [participant.participant.get_doodlename()]
instrument_count[instrument] = (sure + 1, maybe,namesoui,namespe,namesnon)
elif participant.reponse == "pe":
namespe += [participant.participant.get_doodlename()]
instrument_count[instrument] = (sure, maybe + 1,namesoui,namespe,namesnon)
else:
namesnon += [participant.participant.get_doodlename()]
instrument_count[instrument] = (sure, maybe,namesoui,namespe,namesnon)
instrument_count = [
(instrument, sure, maybe,namesoui, namespe ,namesnon)
for instrument, (sure, maybe,namesoui,namespe,namesnon) in instrument_count.items()
]
context = {
"event": event,
"instrument_count": instrument_count,
"participants": participants,
"nboui": len(participants.filter(reponse="oui")),
"nbpe": len(participants.filter(reponse="pe")),
"nbnon": len(participants.filter(reponse="non")),
"multi_instrumentistes":multi_instrumentistes,
}
return render(request, 'calendrier/view_event.html', context=context)
@property
def pMonth(self):
return self.lToday.month
class ViewEvent(LoginRequiredMixin, TemplateView):
template_name = "calendrier/view_event.html"
def get_context_data(self, **kwargs):
context = super(ViewEvent, self).get_context_data(**kwargs)
event = get_object_or_404(Event, id=self.kwargs['id'])
participants = event.participants_set.all()
multi_instrumentistes = event.participants_set.filter(
Q(participant__multi_instrumentiste="Oui") & ~Q(reponse="non")
)
# Restricted event, only erneso users can see it
if not self.request.user.is_authenticated and not event.calendrier:
return redirect(reverse("calendrier:home"))
# Count the number of occurences of each instrument
instrument_count = defaultdict(lambda: (0, 0, [], [], []))
for participant in participants:
instru = participant.participant.instru
if instru == "Autre":
instru = participant.participant.instru_autre
sure, maybe, namesoui, namespe, namesnon = instrument_count[instru]
if participant.reponse == "oui":
namesoui += [participant.participant.get_doodlename()]
instrument_count[instru] = (
sure + 1,
maybe,
namesoui,
namespe,
namesnon,
)
elif participant.reponse == "pe":
namespe += [participant.participant.get_doodlename()]
instrument_count[instru] = (
sure,
maybe + 1,
namesoui,
namespe,
namesnon,
)
else:
namesnon += [participant.participant.get_doodlename()]
instrument_count[instru] = (sure, maybe, namesoui,
namespe, namesnon)
instrument_count = [
(instrument, sure, maybe, namesoui, namespe, namesnon)
for instrument, (
sure,
maybe,
namesoui,
namespe,
namesnon,
) in instrument_count.items()
]
context["event"] = event
context["instrument_count"] = instrument_count
context["participants"] = participants
context["nboui"] = len(participants.filter(reponse="oui"))
context["nbpe"] = len(participants.filter(reponse="pe"))
context["nbnon"] = len(participants.filter(reponse="non"))
context["multi_instrumentistes"] = multi_instrumentistes
return context
class ChangeName(LoginRequiredMixin, TemplateView):
form_class = ChangeDoodleName
template_name = "calendrier/changename.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.form_class(instance=self.request.user)
context["id"] = self.kwargs['id']
return context
@login_required
def changename(request,id):
if request.method == 'POST':
def post(self, request, *args, **kwargs):
success = False
requbis = request.POST.copy()
form = ChangeDoodleName(requbis, instance=request.user)
form = self.form_class(requbis, instance=request.user)
if form.is_valid():
form.save()
success = True
return redirect('calendrier:view-event',id=id)
else:
form = ChangeDoodleName(instance=request.user)
return render(request, 'calendrier/changename.html',locals())
return redirect("calendrier:view-event", id=self.kwargs['id'])
else:
context = self.get_context_data()
context['success'] = success
return render(request, self.template_name, context)
@chef_required
def create_event(request):
if request.method == "POST":
form = EventForm(request.POST)
class CreateEvent(LoginRequiredMixin, TemplateView):
form_class = EventForm
template_name = "calendrier/create.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.form_class()
return context
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
temp = True
while temp:
code = generer()
try:
Event.objects.get(slug=code)
except:
except Event.DoesNotExist:
temp = False
nom = form.cleaned_data["nom"]
date = form.cleaned_data["date"]
date = date.strftime('%d/%m/%Y')
debut = form.cleaned_data["debut"]
date = date.strftime("%d/%m/%Y")
obj = form.save(commit=False)
obj.slug = code
obj.save()
id = obj.id
envoi = True
return redirect('calendrier:view-event',id=id)
else:
form = EventForm()
return render(request, "calendrier/create.html", locals())
return redirect("calendrier:view-event", id=id)
else:
context = self.get_context_data()
return render(request, self.template_name, context)
class ReponseEvent(LoginRequiredMixin, TemplateView):
form_class = ParticipantsForm
template_name = "calendrier/reponse.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.form_class()
context['ev'] = get_object_or_404(Event, id=self.kwargs['id'])
context['id'] = self.kwargs['id']
return context
@login_required
def reponse(request, id):
part = request.user.profile
ev = get_object_or_404(Event, id=id)
if request.method == "POST":
form = ParticipantsForm(request.POST)
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
ev = get_object_or_404(Event, id=self.kwargs['id'])
part = request.user.profile
if form.is_valid():
try:
p = Participants.objects.get(event=ev, participant=part)
@ -222,43 +317,33 @@ def reponse(request, id):
obj.event = ev
obj.participant = part
obj.save()
envoi = True
return redirect('calendrier:view-event',id=id)
else:
form = ParticipantsForm()
return render(request, "calendrier/reponse.html", locals())
return redirect("calendrier:view-event", id=self.kwargs['id'])
else:
context = self.get_context_data()
return render(request, self.template_name, context)
class EventUpdate(UpdateView):
class EventUpdate(ChefRequiredMixin, UpdateView):
model = Event
template_name = "calendrier/update.html"
form_class = ModifEventForm
def get_context_data(self, **kwargs):
ctx = super(EventUpdate, self).get_context_data(**kwargs)
ctx['id'] = self.get_object().id
ctx["id"] = self.get_object().id
return ctx
def get_success_url(self):
return reverse('calendrier:view-event', kwargs={'id' : self.get_object().id})
@method_decorator(chef_required)
def dispatch(self, *args, **kwargs):
return super(EventUpdate, self).dispatch(*args, **kwargs)
return reverse("calendrier:view-event",
kwargs={"id": self.get_object().id})
class EventDelete(DeleteView):
class EventDelete(ChefRequiredMixin, DeleteView):
model = Event
template_name = "calendrier/delete.html"
success_url = reverse_lazy("calendrier:home")
def get_context_data(self, **kwargs):
ctx = super(EventDelete, self).get_context_data(**kwargs)
ctx['id'] = self.get_object().id
ctx["id"] = self.get_object().id
return ctx
@method_decorator(chef_required)
def dispatch(self, *args, **kwargs):
return super(EventDelete,self).dispatch(*args, **kwargs)

View file

@ -6,12 +6,11 @@ les permissions.
"""
from django.contrib import admin
from django.contrib.auth.models import User, Group, Permission
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import Group, Permission, User
from gestion.models import ErnestoUser, VideoGallery, Photo
from actu.models import Actu
from gestion.models import ErnestoUser, Photo, VideoGallery
class UserProfileInline(admin.StackedInline):
@ -112,6 +111,7 @@ class UserProfileAdmin(UserAdmin):
user.groups.add(chef_group)
user.save()
admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin)
admin.site.register(VideoGallery)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class GestionConfig(AppConfig):
name = 'gestion'
name = "gestion"

View file

@ -1,47 +1,71 @@
from django import forms
from gestion.models import ErnestoUser
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.tokens import default_token_generator
from django.utils.translation import gettext_lazy as _
from gestion.models import ErnestoUser
class RegistrationFormUser(UserCreationForm):
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'password1',
'password2', 'email',)
fields = (
"username",
"first_name",
"last_name",
"password1",
"password2",
"email",
)
class ChangeFormUser(UserChangeForm):
password = None
class Meta:
model = User
fields = ('first_name', 'last_name', 'email',)
fields = (
"first_name",
"last_name",
"email",
)
class ChangeMembreForm(forms.ModelForm):
def clean(self):
cleaned_data = super(ChangeMembreForm, self).clean()
instru=cleaned_data.get("instru")
instru = cleaned_data.get("instru")
instru_autre = cleaned_data.get("instru_autre")
if (instru == "Autre") and not (instru_autre):
raise forms.ValidationError(_("Préçisez quel autre instrument"))
multi_instru=cleaned_data.get("multi_instrumentiste")
multi_instru = cleaned_data.get("multi_instrumentiste")
instru_bonus = cleaned_data.get("instru_bonus")
if (multi_instru == "Oui") and not (instru_bonus):
raise forms.ValidationError(_("Préçisez quel·s instrument·s supplémentaire·s vous pouvez jouer"))
raise forms.ValidationError(
_("Préçisez quel·s instrument·s supplémentaire·s vous pouvez jouer")
)
return cleaned_data
class Meta:
model = ErnestoUser
fields = ("phone", "instru","instru_autre","multi_instrumentiste","instru_bonus")
fields = (
"phone",
"instru",
"instru_autre",
"multi_instrumentiste",
"instru_bonus",
)
class InscriptionMembreForm(ChangeMembreForm):
validation = forms.CharField(max_length=100, widget=forms.PasswordInput)
class Meta:
model = ErnestoUser
fields = ("phone", "instru","instru_autre",'multi_instrumentiste',
'instru_bonus' )
fields = (
"phone",
"instru",
"instru_autre",
"multi_instrumentiste",
"instru_bonus",
)

View file

@ -1,5 +1,5 @@
from django.db import migrations, models
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
@ -10,28 +10,64 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
name='ErnestoUser',
name="ErnestoUser",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('is_ernesto', models.BooleanField(verbose_name="Membre de l'Ernestophone", default=True)),
('is_chef', models.BooleanField(verbose_name='Chef Fanfare', default=False)),
('phone', models.CharField(blank=True, max_length=20, verbose_name='Téléphone')),
('instru', models.CharField(blank=True, max_length=40, verbose_name='Instrument joué')),
('slug', models.CharField(max_length=7, editable=False, unique=True)),
('doodlename', models.CharField(blank=True, max_length=30, verbose_name='Nom pour le doodle')),
('mails', models.BooleanField(verbose_name='Recevoir les mails', default=True)),
(
'user',
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
(
"is_ernesto",
models.BooleanField(
verbose_name="Membre de l'Ernestophone", default=True
),
),
(
"is_chef",
models.BooleanField(verbose_name="Chef Fanfare", default=False),
),
(
"phone",
models.CharField(
blank=True, max_length=20, verbose_name="Téléphone"
),
),
(
"instru",
models.CharField(
blank=True, max_length=40, verbose_name="Instrument joué"
),
),
("slug", models.CharField(max_length=7, editable=False, unique=True)),
(
"doodlename",
models.CharField(
blank=True, max_length=30, verbose_name="Nom pour le doodle"
),
),
(
"mails",
models.BooleanField(
verbose_name="Recevoir les mails", default=True
),
),
(
"user",
models.OneToOneField(
to=settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='profile'
)
related_name="profile",
),
),
],
options={
'verbose_name': 'Profil Ernestophoniste',
'verbose_name_plural': 'Profil Ernestophoniste',
"verbose_name": "Profil Ernestophoniste",
"verbose_name_plural": "Profil Ernestophoniste",
},
),
]

View file

@ -7,80 +7,157 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0001_initial'),
("gestion", "0001_initial"),
]
operations = [
migrations.CreateModel(
name='VideoGallery',
name="VideoGallery",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=127)),
('order', models.IntegerField(verbose_name='ordre')),
('url', models.URLField()),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=127)),
("order", models.IntegerField(verbose_name="ordre")),
("url", models.URLField()),
],
options={
'verbose_name_plural': 'Videos',
'verbose_name': 'Video',
"verbose_name_plural": "Videos",
"verbose_name": "Video",
},
),
migrations.RemoveField(
model_name='ernestouser',
name='mails',
model_name="ernestouser",
name="mails",
),
migrations.AddField(
model_name='ernestouser',
name='instru_autre',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Lequel ?'),
model_name="ernestouser",
name="instru_autre",
field=models.CharField(
blank=True, max_length=100, null=True, verbose_name="Lequel ?"
),
),
migrations.AddField(
model_name='ernestouser',
name='instru_bonus',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Le·s·quel·s ?'),
model_name="ernestouser",
name="instru_bonus",
field=models.CharField(
blank=True, max_length=100, null=True, verbose_name="Le·s·quel·s ?"
),
),
migrations.AddField(
model_name='ernestouser',
name='instru_trombonoscope',
field=models.CharField(blank=True, max_length=30, verbose_name='Instrument affiché sur le trombonoscope'),
model_name="ernestouser",
name="instru_trombonoscope",
field=models.CharField(
blank=True,
max_length=30,
verbose_name="Instrument affiché sur le trombonoscope",
),
),
migrations.AddField(
model_name='ernestouser',
name='multi_instrumentiste',
field=models.CharField(choices=[('Non', 'Non'), ('Oui', 'Oui')], default='Non', help_text='Seulement si tu connais les partitions par coeur', max_length=3, verbose_name="Je suis capable de jouer d'un autre instrument en manche :"),
model_name="ernestouser",
name="multi_instrumentiste",
field=models.CharField(
choices=[("Non", "Non"), ("Oui", "Oui")],
default="Non",
help_text="Seulement si tu connais les partitions par coeur",
max_length=3,
verbose_name="Je suis capable de jouer d'un autre instrument en manche :",
),
),
migrations.AddField(
model_name='ernestouser',
name='nom_trombonoscope',
field=models.CharField(blank=True, max_length=30, verbose_name='Nom affiché sur le trombonoscope'),
model_name="ernestouser",
name="nom_trombonoscope",
field=models.CharField(
blank=True,
max_length=30,
verbose_name="Nom affiché sur le trombonoscope",
),
),
migrations.AddField(
model_name='ernestouser',
name='trombonoscope',
field=models.CharField(choices=[('non', 'Non'), ('o_a', 'Oui en tant que fanfaron actuel'), ('o_v', 'Oui en tant que vie·ille·ux')], default='non', max_length=3, null=True, verbose_name='Je souhaite apparaitre dans le trombonoscope :'),
model_name="ernestouser",
name="trombonoscope",
field=models.CharField(
choices=[
("non", "Non"),
("o_a", "Oui en tant que fanfaron actuel"),
("o_v", "Oui en tant que vie·ille·ux"),
],
default="non",
max_length=3,
null=True,
verbose_name="Je souhaite apparaitre dans le trombonoscope :",
),
),
migrations.AddField(
model_name='ernestouser',
name='trombonoscope_colors',
field=models.CharField(choices=[('#e4522f#ffffff', 'Orange et Blanc'), ('#ffffff#000000', 'Blanc et Noir'), ('#A8107C#000000', 'Rose et Noir'), ('#10A4A8#ffffff', 'Bleu et Blanc'), ('#26A810#000000', 'Vert et Noir'), ('#A81026#ffffff', 'Rouge et Blanc'), ('#E3E54C#000000', 'Jaune et Noir'), ('autre', 'Autre')], default='OrangeBlanc', max_length=40, verbose_name='Couleur du profil'),
model_name="ernestouser",
name="trombonoscope_colors",
field=models.CharField(
choices=[
("#e4522f#ffffff", "Orange et Blanc"),
("#ffffff#000000", "Blanc et Noir"),
("#A8107C#000000", "Rose et Noir"),
("#10A4A8#ffffff", "Bleu et Blanc"),
("#26A810#000000", "Vert et Noir"),
("#A81026#ffffff", "Rouge et Blanc"),
("#E3E54C#000000", "Jaune et Noir"),
("autre", "Autre"),
],
default="OrangeBlanc",
max_length=40,
verbose_name="Couleur du profil",
),
),
migrations.AddField(
model_name='ernestouser',
name='trombonoscope_fond',
field=colorful.fields.RGBColorField(default='#e4522f', verbose_name='Couleur de fond du profil'),
model_name="ernestouser",
name="trombonoscope_fond",
field=colorful.fields.RGBColorField(
default="#e4522f", verbose_name="Couleur de fond du profil"
),
),
migrations.AddField(
model_name='ernestouser',
name='trombonoscope_texte',
field=colorful.fields.RGBColorField(default='#ffffff', verbose_name='Couleur du texte du profil'),
model_name="ernestouser",
name="trombonoscope_texte",
field=colorful.fields.RGBColorField(
default="#ffffff", verbose_name="Couleur du texte du profil"
),
),
migrations.AlterField(
model_name='ernestouser',
name='instru',
field=models.CharField(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')], default='ne sais pas', max_length=40, verbose_name='Instrument joué'),
model_name="ernestouser",
name="instru",
field=models.CharField(
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"),
],
default="ne sais pas",
max_length=40,
verbose_name="Instrument joué",
),
),
migrations.AlterField(
model_name='ernestouser',
name='phone',
field=models.CharField(blank=True, help_text='seulement visible par les chef·fe·s', max_length=20, verbose_name='Téléphone'),
model_name="ernestouser",
name="phone",
field=models.CharField(
blank=True,
help_text="seulement visible par les chef·fe·s",
max_length=20,
verbose_name="Téléphone",
),
),
]

View file

@ -2,30 +2,84 @@
import colorful.fields
from django.db import migrations, models
import gestion.models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0002_auto_20200908_2222'),
("gestion", "0002_auto_20200908_2222"),
]
operations = [
migrations.CreateModel(
name='Photo',
name="Photo",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=127)),
('cat', models.CharField(choices=[('home_join', 'Rejoignez nous'), ('home_contact', 'Nous Contacter'), ('home_rep', "Répertoire de l'acceuil"), ('login', 'Connexion'), ('change_membre', 'Modification du profil'), ('inscription_membre', 'Inscription'), ('home', 'Calendrier connecté'), ('liste', 'Agenda public'), ('part', 'Répertoire'), ('n', "N'apparait pas")], default='n', max_length=127)),
('auteur', models.CharField(blank=True, max_length=127, null=True, verbose_name="Auteur de l'image")),
('url', models.URLField(blank=True, null=True, verbose_name="Lien vers le site de l'auteur")),
('color', colorful.fields.RGBColorField(default='#ffffff', verbose_name="Couleur du nom de l'auteur")),
('image', models.ImageField(default=None, upload_to='deco', validators=[gestion.models.Photo.validate_image])),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=127)),
(
"cat",
models.CharField(
choices=[
("home_join", "Rejoignez nous"),
("home_contact", "Nous Contacter"),
("home_rep", "Répertoire de l'acceuil"),
("login", "Connexion"),
("change_membre", "Modification du profil"),
("inscription_membre", "Inscription"),
("home", "Calendrier connecté"),
("liste", "Agenda public"),
("part", "Répertoire"),
("n", "N'apparait pas"),
],
default="n",
max_length=127,
),
),
(
"auteur",
models.CharField(
blank=True,
max_length=127,
null=True,
verbose_name="Auteur de l'image",
),
),
(
"url",
models.URLField(
blank=True,
null=True,
verbose_name="Lien vers le site de l'auteur",
),
),
(
"color",
colorful.fields.RGBColorField(
default="#ffffff", verbose_name="Couleur du nom de l'auteur"
),
),
(
"image",
models.ImageField(
default=None,
upload_to="deco",
validators=[gestion.models.Photo.validate_image],
),
),
],
options={
'verbose_name': 'Photo',
'verbose_name_plural': 'Photos',
"verbose_name": "Photo",
"verbose_name_plural": "Photos",
},
),
]

View file

@ -6,13 +6,29 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0003_photo'),
("gestion", "0003_photo"),
]
operations = [
migrations.AlterField(
model_name='photo',
name='cat',
field=models.CharField(choices=[('home_join', 'Rejoignez nous'), ('home_contact', 'Nous Contacter'), ('home_rep', "Répertoire de l'acceuil"), ('login', 'Connexion'), ('change_membre', 'Modification du profil'), ('inscription_membre', 'Inscription'), ('home', 'Calendrier connecté'), ('liste', 'Agenda public'), ('part', 'Répertoire'), ('instru', 'Instruments'), ('n', "N'apparait pas")], default='n', max_length=127),
model_name="photo",
name="cat",
field=models.CharField(
choices=[
("home_join", "Rejoignez nous"),
("home_contact", "Nous Contacter"),
("home_rep", "Répertoire de l'acceuil"),
("login", "Connexion"),
("change_membre", "Modification du profil"),
("inscription_membre", "Inscription"),
("home", "Calendrier connecté"),
("liste", "Agenda public"),
("part", "Répertoire"),
("instru", "Instruments"),
("n", "N'apparait pas"),
],
default="n",
max_length=127,
),
),
]

View file

@ -1,38 +1,48 @@
# -*- coding: utf-8 -*-
from django.db import models
from colorful.fields import RGBColorField
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
class Photo(models.Model):
PHOTO_PLACEMENT = (
('home_join', _("Rejoignez nous")),
('home_contact', _("Nous Contacter")),
('home_rep', _("Répertoire de l'acceuil")),
('login', _('Connexion')),
('change_membre', _('Modification du profil')),
('inscription_membre', _('Inscription')),
('home', _('Calendrier connecté')),
('liste', _('Agenda public')),
('part', _('Répertoire')),
('instru', _('Instruments')),
('n',_("N'apparait pas"))
)
("home_join", _("Rejoignez nous")),
("home_contact", _("Nous Contacter")),
("home_rep", _("Répertoire de l'acceuil")),
("login", _("Connexion")),
("change_membre", _("Modification du profil")),
("inscription_membre", _("Inscription")),
("home", _("Calendrier connecté")),
("liste", _("Agenda public")),
("part", _("Répertoire")),
("instru", _("Instruments")),
("n", _("N'apparait pas")),
)
def validate_image(fieldfile_obj):
filesize = fieldfile_obj.file.size
megabyte_limit = 1.0
if filesize > megabyte_limit*1024*1024:
raise ValidationError("Max file size is %sMB" % str(megabyte_limit))
mb_limit = 1.0
if filesize > mb_limit * 1024 * 1024:
raise ValidationError("La taille max est %sMB" % str(mb_limit))
name = models.CharField(max_length=127)
cat = models.CharField(max_length = 127,choices = PHOTO_PLACEMENT,default='n')
auteur = models.CharField(max_length=127,verbose_name=_("Auteur de l'image"),null=True,blank=True)
url = models.URLField(verbose_name=_("Lien vers le site de l'auteur"),null=True,blank=True)
color = RGBColorField(_("Couleur du nom de l'auteur"),default='#ffffff')
image = models.ImageField(upload_to='deco',default=None,validators=[validate_image])
cat = models.CharField(max_length=127, choices=PHOTO_PLACEMENT,
default="n")
auteur = models.CharField(
max_length=127, verbose_name=_("Auteur de l'image"), null=True,
blank=True
)
url = models.URLField(
verbose_name=_("Lien vers le site de l'auteur"), null=True, blank=True
)
color = RGBColorField(_("Couleur du nom de l'auteur"), default="#ffffff")
image = models.ImageField(
upload_to="deco", default=None, validators=[validate_image]
)
def __str__(self):
return self.name
@ -42,57 +52,101 @@ class Photo(models.Model):
class ErnestoUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
is_ernesto = models.BooleanField(_("Membre de l'Ernestophone"), default=True)
user = models.OneToOneField(User, on_delete=models.CASCADE,
related_name="profile")
is_ernesto = models.BooleanField(_("Membre de l'Ernestophone"),
default=True)
is_chef = models.BooleanField(_("Chef Fanfare"), default=False)
phone = models.CharField(_("Téléphone"), max_length=20, blank=True ,help_text= _("seulement visible par les chef·fe·s"))
phone = models.CharField(
_("Téléphone"),
max_length=20,
blank=True,
help_text=_("seulement visible par les chef·fe·s"),
)
INSTRU_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')),
("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")),
]
COLORS_CHOICES = [
('#e4522f#ffffff', _('Orange et Blanc')),
('#ffffff#000000', _('Blanc et Noir')),
('#A8107C#000000', _('Rose et Noir')),
('#10A4A8#ffffff', _('Bleu et Blanc')),
('#26A810#000000', _('Vert et Noir')),
('#A81026#ffffff', _('Rouge et Blanc')),
('#E3E54C#000000', _('Jaune et Noir')),
('autre',_('Autre')),
("#e4522f#ffffff", _("Orange et Blanc")),
("#ffffff#000000", _("Blanc et Noir")),
("#A8107C#000000", _("Rose et Noir")),
("#10A4A8#ffffff", _("Bleu et Blanc")),
("#26A810#000000", _("Vert et Noir")),
("#A81026#ffffff", _("Rouge et Blanc")),
("#E3E54C#000000", _("Jaune et Noir")),
("autre", _("Autre")),
]
]
instru = models.CharField(_("Instrument joué"), max_length=40, blank=False,choices=INSTRU_CHOICES,default='ne sais pas')
instru_autre = models.CharField(_("Lequel ?"),null=True,max_length=100,blank=True)
instru = models.CharField(
_("Instrument joué"),
max_length=40,
blank=False,
choices=INSTRU_CHOICES,
default="ne sais pas",
)
instru_autre = models.CharField(
_("Lequel ?"), null=True, max_length=100, blank=True
)
slug = models.CharField(max_length=7, editable=False, unique=True)
doodlename = models.CharField(_("Nom pour le doodle"), max_length=30,
blank=True)
trombonoscope = models.CharField(_('Je souhaite apparaitre dans le trombonoscope :'),max_length=3,blank=False,null=True,choices=[('non',_('Non')),('o_a',_('Oui en tant que fanfaron actuel')),('o_v',_('Oui en tant que vie·ille·ux'))],default='non')
instru_trombonoscope = models.CharField(_("Instrument affiché sur le trombonoscope"), max_length=30,
blank=True)
nom_trombonoscope = models.CharField(_("Nom affiché sur le trombonoscope"), max_length=30,
blank=True)
trombonoscope_colors = models.CharField(_("Couleur du profil"), max_length=40, blank=False,choices=COLORS_CHOICES,default='OrangeBlanc')
trombonoscope_fond = RGBColorField(_("Couleur de fond du profil"),default='#e4522f')
trombonoscope_texte = RGBColorField(_("Couleur du texte du profil"),default='#ffffff')
multi_instrumentiste = models.CharField(_("Je suis capable de jouer d'un autre instrument en manche :"),default='Non',null=False,max_length=3,choices=[('Non',_('Non')),('Oui',_('Oui'))],help_text= _("Seulement si tu connais les partitions par coeur"))
instru_bonus = models.CharField(_("Le·s·quel·s ?"),null=True,max_length=100,blank=True)
trombonoscope = models.CharField(
_("Je souhaite apparaitre dans le trombonoscope:"),
max_length=3,
blank=False,
null=True,
choices=[
("non", _("Non")),
("o_a", _("Oui en tant que fanfaron actuel")),
("o_v", _("Oui en tant que vie·ille·ux")),
],
default="non",
)
instru_trombonoscope = models.CharField(
_("Instrument affiché sur le trombonoscope"), max_length=30, blank=True
)
nom_trombonoscope = models.CharField(
_("Nom affiché sur le trombonoscope"), max_length=30, blank=True
)
trombonoscope_colors = models.CharField(
_("Couleur du profil"),
max_length=40,
blank=False,
choices=COLORS_CHOICES,
default="OrangeBlanc",
)
trombonoscope_fond = RGBColorField(
_("Couleur de fond du profil"), default="#e4522f"
)
trombonoscope_texte = RGBColorField(
_("Couleur du texte du profil"), default="#ffffff"
)
multi_instrumentiste = models.CharField(
_("Je suis capable de jouer d'un autre instrument en manche :"),
default="Non",
null=False,
max_length=3,
choices=[("Non", _("Non")), ("Oui", _("Oui"))],
help_text=_("Seulement si tu connais les partitions par coeur"),
)
instru_bonus = models.CharField(
_("Le·s·quel·s ?"), null=True, max_length=100, blank=True
)
class Meta:
verbose_name = _("Profil Ernestophoniste")

View file

@ -33,13 +33,15 @@
<!-- Nav -->
<nav id="menu">
<ul class="links">
<li><p></p></li>
<li>{% ifequal current_language "fr" %}
<a href="{% changelang "en" %}" >English<span class="image right"><img src="{% static "images/en_flag.jpg" %}"></span></a>
{% else %}
<a href="{% changelang "fr" %}">Français<span class="image right"><img src="{% static "images/fr_flag.jpg" %}"></span></a>
{% endifequal %}</li>
{% if not user.is_authenticated %}
<li><a href="{% url 'home' %}">{% trans "Accueil" %}</a></li>
<li><a href="{% url 'calendrier:liste' %}">{% trans "Agenda" %}</a></li>
{% else %}
@ -47,24 +49,38 @@
{% endif %}
<li><a href="{% url 'partitions:liste' %}">{% trans "Répertoire" %}</a></li>
{% if user.is_authenticated %}
<li><a href="{% url 'trombonoscope:view' %}">{% trans "Trombonoscope" %}</a></li>
<li><a href="{% url 'instruments:liste' %}">{% trans "Instruments" %}</a></li>
<li><a href="https://photos.cof.ens.fr/index.php/Clubs-du-COF/L'Ernestophone" target="_blank">{% trans "Galerie Photo" %}</a></li>
<li><a href="{% url 'instruments:liste' %}">{% trans "Instruments" %}</a></li>
<li><a href="{% url 'pads:list' %}">{% trans "Pads" %}</a></li>
</ul>
<h1>{% trans "Social :" %}</h1>
<ul class ="links">
<li><a href="{% url 'trombonoscope:view' %}">{% trans "Trombonoscope" %}</a></li>
<li><a href="https://photos.cof.ens.fr/index.php/Clubs-du-COF/L'Ernestophone" target="_blank">{% trans "Galerie Photo" %}</a></li>
</ul>
<h1> {% trans "Mon profil :" %}</h1>
<ul class = 'links'>
<li><a href="{% url 'change_membre' %}">{% trans "Modification du profil" %}</a></li>
<li><a href="{% url 'logout' %}">{% trans "Déconnexion" %}</a></li>
</ul>
{% if user.is_superuser or user.profile.is_chef %}
</ul>
<h1>{% trans "Le pouvoir des chef·fe·s :" %}</h1>
<ul class="links">
<li><a href="/admin/">{% trans "Administration" %}</a></li>
{% if user.profile.is_chef %}
<li><a href="{% url 'actu:liste' %}">{% trans "Modifier les actualités" %}</a></li>
{% endif %}
</ul>
{% endif %}
<li><a href="{% url 'change_membre' %}">{% trans "Modification du profil" %}</a></li>
<li><a href="{% url 'logout' %}">{% trans "Déconnexion" %}</a></li>
</ul>
{% else %}
<li><a href="{% url 'login' %}">{% trans "Se connecter" %}</a></li>
<li><a href="{% url 'registration' %}">{% trans "Créer un compte" %}</a></li>
</ul>
{% endif %}
</ul>
</nav>

View file

@ -3,12 +3,13 @@ from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag
def autotranslate(current_language, description, description_en):
if( current_language != "fr" and description_en):
if current_language != "fr" and description_en:
return mark_safe(description_en)
elif(current_language == "fr" and not description):
elif current_language == "fr" and not description:
return mark_safe(description_en)
else:
return mark_safe(description)

View file

@ -12,7 +12,7 @@ def changelang(context, lang=None, *args, **kwargs):
Usage: {% change_lang 'en' %}
"""
path = context['request'].path
path = context["request"].path
url_parts = resolve(path)
url = path

View file

@ -1,8 +1,10 @@
from django.template import Library
from math import ceil
from django.template import Library
register = Library()
@register.filter
def half_length(liste):
try:

View file

@ -1,8 +1,10 @@
from django import template
from datetime import date, timedelta
from django import template
register = template.Library()
@register.filter
def modulo(num, val):
return num % val

View file

@ -1,132 +1,187 @@
from django.shortcuts import render, redirect
from partitions.models import Category
from gestion.forms import ChangeMembreForm, ChangeFormUser,RegistrationFormUser, InscriptionMembreForm
from django.conf import settings
from django.http import HttpResponseRedirect
from gestion.models import ErnestoUser, VideoGallery, Photo
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import PasswordChangeForm
from calendrier.forms import ChangeDoodleName
from partitions.decorators import chef_required
from gestion.mixins import ChefRequiredMixin
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from django.contrib.auth.views import LoginView
from django.urls import reverse_lazy
from django.shortcuts import render_to_response
import string
import random
import string
from django.conf import settings
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.views import LoginView
from django.shortcuts import redirect, render
from calendrier.forms import ChangeDoodleName
from gestion.forms import (ChangeFormUser, ChangeMembreForm,
InscriptionMembreForm, RegistrationFormUser)
from gestion.models import ErnestoUser, Photo, VideoGallery
from partitions.models import Category
from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.translation import gettext_lazy as _
def generer(*args):
caracteres = string.ascii_letters + string.digits
aleatoire = [random.choice(caracteres) for _ in range(6)]
return ''.join(aleatoire)
aleatoire = [random.choice(caracteres) for i in range(6)]
return "".join(aleatoire)
def home(request):
if request.user.is_authenticated :
return redirect('calendrier:home')
categories = Category.objects.filter(name = "Partitions actives").prefetch_related("partitionset_set")
videos = VideoGallery.objects.all()
photo_rep = Photo.objects.filter(cat='home_rep').order_by('?').first()
photo_join = Photo.objects.filter(cat='home_join').order_by('?').first()
photo_contact = Photo.objects.filter(cat='home_contact').order_by('?').first()
return render_to_response( 'gestion/index.html', {"request":request,"categories": categories,'videos':videos,'photo_rep':photo_rep,'photo_join':photo_join,'photo_contact':photo_contact})
class Home(TemplateView):
template_name = "gestion/index.html"
class MyLoginView(LoginView):
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
return redirect('calendrier:home')
return super(Home, self).dispatch(request, *args, **kwargs)
template_name = 'gestion/login.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
photo = Photo.objects.filter(cat='login').order_by('?').first()
context['photo'] = photo
context["categories"] = Category.objects.filter(
name="Partitions actives").prefetch_related(
"partitionset_set"
)
context['videos'] = VideoGallery.objects.all()
context['photo_rep'] = Photo.objects.filter(
cat="home_rep").order_by("?").first()
context['photo_join'] = Photo.objects.filter(
cat="home_join").order_by("?").first()
context['photo_contact'] = Photo.objects.filter(
cat="home_contact").order_by("?").first()
return context
def thanks(request):
class MyLoginView(LoginView):
return render(request, 'gestion/thanks.html', locals())
template_name = "gestion/login.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["photo"] = Photo.objects.filter(
cat="login").order_by("?").first()
return context
@login_required
def changename(request):
if request.method == 'POST':
class Thanks(TemplateView):
template_name = "gestion/thanks.html"
class ChangeName(LoginRequiredMixin, TemplateView):
form_class = ChangeDoodleName
template_name = "gestion/changename.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.form_class(instance=self.request.user)
return context
def post(self, request, *args, **kwargs):
requbis = request.POST.copy()
form = ChangeDoodleName(requbis, instance=request.user)
form = self.form_class(requbis,
instance=request.user)
if form.is_valid():
form.save()
success = True
return redirect('change_membre')
else:
form = ChangeDoodleName(instance=request.user)
return render(request, 'gestion/changename.html', locals())
return redirect("change_membre")
context = self.get_context_data()
context['form'] = form
return render(request, self.template_name, context)
class ChangeMembre(LoginRequiredMixin, TemplateView):
comp_form_class = ChangeMembreForm
user_form_class = ChangeFormUser
template_name = "gestion/change.html"
@login_required
def change_membre(request):
photo = Photo.objects.filter(cat='change_membre').order_by('?').first()
if request.method == 'POST':
comp_form = ChangeMembreForm(request.POST, instance=request.user.profile)
user_form = ChangeFormUser(request.POST, instance=request.user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
comp_form = self.comp_form_class(instance=self.request.user.profile)
user_form = self.user_form_class(instance=self.request.user)
context["comp_form"] = comp_form
context["user_form"] = user_form
context["photo"] = Photo.objects.filter(
cat="change_membre").order_by("?").first()
return context
def post(self, request, *args, **kwargs):
success = False
comp_form = self.comp_form_class(request.POST,
instance=request.user.profile)
user_form = self.user_form_class(request.POST, instance=request.user)
if user_form.is_valid() and comp_form.is_valid():
user_form.save()
comp_form.save()
success = True
return redirect('home')
else:
comp_form = ChangeMembreForm(instance=request.user.profile)
user_form = ChangeFormUser(instance=request.user)
return render(request, 'gestion/change.html', locals())
@login_required
def change_password(request):
if request.method == 'POST':
context = self.get_context_data()
context['success'] = success
context['comp_form'] = comp_form
context['user_form'] = user_form
return render(request, self.template_name, context)
class ChangePassword(LoginRequiredMixin, TemplateView):
form_class = PasswordChangeForm
template_name = "gestion/changepasswd.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = self.form_class(self.request.user)
return context
def post(self, request, *args, **kwargs):
requbis = request.POST.copy()
form = PasswordChangeForm(request.user, data=requbis)
success = False
form = self.form_class(request.user, data=requbis)
if form.is_valid():
request.user.profile.photo.delete()
form.save()
success = True
else:
form = PasswordChangeForm(request.user)
return render(request, 'gestion/changepasswd.html', locals())
context = self.get_context_data()
context['success'] = success
context['form'] = form
return render(request, self.template_name, context)
class Inscription(TemplateView):
user_form_class = RegistrationFormUser
comp_form_class = InscriptionMembreForm
template_name = "gestion/registration.html"
def inscription_membre(request):
photo = Photo.objects.filter(cat='inscription_membre').order_by('?').first()
if request.method == 'POST':
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comp_form'] = self.comp_form_class()
context['user_form'] = self.user_form_class()
context['photo'] = Photo.objects.filter(
cat="inscription_membre").order_by("?").first()
return context
user_form = RegistrationFormUser(request.POST)
comp_form = InscriptionMembreForm(request.POST)
def post(self, request, *args, **kwargs):
user_form = self.user_form_class(request.POST)
comp_form = self.comp_form_class(request.POST)
if user_form.is_valid() and comp_form.is_valid():
pseudo = user_form.cleaned_data['username']
if not (comp_form.cleaned_data['validation']
== settings.ACCOUNT_CREATION_PASS):
error = "Le champ Validation ne correspond pas à celui attendu"
return render(request, "gestion/registration.html", locals())
if not (
comp_form.cleaned_data["validation"] == settings.ACCOUNT_CREATION_PASS
):
error = _("Le champ Validation ne correspond pas à celui attendu")
context = self.get_context_data()
context['user_form'] = user_form
context['comp_form'] = comp_form
context['error'] = error
return render(request, self.template_name, context)
member = user_form.save(commit=False)
temp = True
while temp:
code = generer()
try:
ErnestoUser.objects.get(slug=code)
except:
except ErnestoUser.DoesNotExist:
temp = False
member.save()
(profile, _) = ErnestoUser.objects.get_or_create(user=member,
(profile, k) = ErnestoUser.objects.get_or_create(user=member,
slug=code)
comp_form = InscriptionMembreForm(request.POST, instance=profile)
comp_form = self.comp_form_class(request.POST, instance=profile)
obj = comp_form.save(commit=False)
obj.slug = code
obj.save()
envoi = True
return redirect('thanks')
else:
comp_form = InscriptionMembreForm()
user_form = RegistrationFormUser()
return render(request, 'gestion/registration.html', locals())
return redirect("thanks")
else:
context = self.get_context_data()
context['user_form'] = user_form
context['comp_form'] = comp_form
return render(request, self.template_name, context)

View file

@ -1,8 +1,6 @@
from django.contrib import admin
from .models import Instrument,Reparation
from .models import Instrument, Reparation
admin.site.register(Instrument)
admin.site.register(Reparation)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class InstrumentsConfig(AppConfig):
name = 'instruments'
name = "instruments"

View file

@ -1,11 +0,0 @@
from django.contrib.auth.decorators import user_passes_test
def is_chef(user):
try:
profile = user.profile
return profile.is_chef
except:
return False
chef_required = user_passes_test(lambda u: is_chef(u))

View file

@ -0,0 +1,27 @@
from django import forms
from .models import Instrument, Reparation
class ChefReparationForm(forms.ModelForm):
class Meta:
model = Reparation
fields = ("date", "description", "description_en", "prix", "lieux")
class ChefEditInstrumentForm(forms.ModelForm):
class Meta:
model = Instrument
fields = (
"statut",
"user",
"infos",
"type",
"owner",
"marque",
"model",
"serial",
"annee",
"prix",
"infos_en",
)

View file

@ -1,56 +1,174 @@
# Generated by Django 2.2.17 on 2021-04-01 19:25
from django.db import migrations, models
import django.db.models.deletion
import django.db.models.functions.text
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='Instrument',
name="Instrument",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('model', models.CharField(blank=True, max_length=100, null=True, verbose_name='Modèle')),
('prix', models.CharField(blank=True, default='', max_length=100, verbose_name='Prix')),
('etat', models.CharField(choices=[('Bon état', 'Bon état'), ('Etat moyen', 'Etat moyen'), ('Mauvais état', 'Mauvais état')], default='Bon état', max_length=100)),
('marque', models.CharField(blank=True, max_length=100, null=True, verbose_name='Marque')),
('serial', models.CharField(blank=True, default=' ', max_length=100, null=True, verbose_name='Numéro de série')),
('annee', models.CharField(blank=True, max_length=100, null=True, verbose_name="Année d'achat")),
('owner', models.CharField(default='Fanfare', max_length=100, verbose_name='Propriétaire')),
('user', models.CharField(blank=True, max_length=100, verbose_name='Utilisateur')),
('type', models.CharField(max_length=40, verbose_name='Instrument')),
('statut', models.CharField(choices=[('Disponible', 'Disponible'), ('Prêté', 'Prêté')], default='Disponible', max_length=100)),
('infos', models.TextField(blank=True, default='', verbose_name='Infos utiles')),
('infos_en', models.TextField(blank=True, default='', verbose_name='Infos utiles en anglais')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"model",
models.CharField(
blank=True, max_length=100, null=True, verbose_name="Modèle"
),
),
(
"prix",
models.CharField(
blank=True, default="", max_length=100, verbose_name="Prix"
),
),
(
"etat",
models.CharField(
choices=[
("Bon état", "Bon état"),
("Etat moyen", "Etat moyen"),
("Mauvais état", "Mauvais état"),
],
default="Bon état",
max_length=100,
),
),
(
"marque",
models.CharField(
blank=True, max_length=100, null=True, verbose_name="Marque"
),
),
(
"serial",
models.CharField(
blank=True,
default=" ",
max_length=100,
null=True,
verbose_name="Numéro de série",
),
),
(
"annee",
models.CharField(
blank=True,
max_length=100,
null=True,
verbose_name="Année d'achat",
),
),
(
"owner",
models.CharField(
default="Fanfare", max_length=100, verbose_name="Propriétaire"
),
),
(
"user",
models.CharField(
blank=True, max_length=100, verbose_name="Utilisateur"
),
),
("type", models.CharField(max_length=40, verbose_name="Instrument")),
(
"statut",
models.CharField(
choices=[("Disponible", "Disponible"), ("Prêté", "Prêté")],
default="Disponible",
max_length=100,
),
),
(
"infos",
models.TextField(
blank=True, default="", verbose_name="Infos utiles"
),
),
(
"infos_en",
models.TextField(
blank=True, default="", verbose_name="Infos utiles en anglais"
),
),
],
options={
'verbose_name': 'Instrument',
'verbose_name_plural': 'Instruments',
'ordering': (django.db.models.functions.text.Lower('type'),),
"verbose_name": "Instrument",
"verbose_name_plural": "Instruments",
"ordering": (django.db.models.functions.text.Lower("type"),),
},
),
migrations.CreateModel(
name='Reparation',
name="Reparation",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date', models.DateField(max_length=100, verbose_name='Date')),
('description', models.CharField(blank=True, default=' ', max_length=100, verbose_name='Description')),
('description_en', models.CharField(blank=True, default=' ', max_length=100, verbose_name='Description en anglais')),
('prix', models.CharField(blank=True, default='', max_length=100, verbose_name='Prix')),
('lieux', models.CharField(blank=True, default=' ', max_length=100, verbose_name='Lieux')),
('instru', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='instruments.Instrument', verbose_name='Instrument')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date", models.DateField(max_length=100, verbose_name="Date")),
(
"description",
models.CharField(
blank=True,
default=" ",
max_length=100,
verbose_name="Description",
),
),
(
"description_en",
models.CharField(
blank=True,
default=" ",
max_length=100,
verbose_name="Description en anglais",
),
),
(
"prix",
models.CharField(
blank=True, default="", max_length=100, verbose_name="Prix"
),
),
(
"lieux",
models.CharField(
blank=True, default=" ", max_length=100, verbose_name="Lieux"
),
),
(
"instru",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="instruments.Instrument",
verbose_name="Instrument",
),
),
],
options={
'verbose_name': 'Réparation',
'verbose_name_plural': 'Réparations',
'ordering': ('date',),
"verbose_name": "Réparation",
"verbose_name_plural": "Réparations",
"ordering": ("date",),
},
),
]

View file

@ -1,6 +1,3 @@
import os
from django.conf import settings
from django.db import models
from django.db.models.functions import Lower
from django.utils.translation import gettext_lazy as _
@ -8,37 +5,62 @@ from django.utils.translation import gettext_lazy as _
class Instrument(models.Model):
model = models.CharField(_("Modèle"),max_length=100,null=True,blank=True)
prix = models.CharField(_("Prix"),max_length=100,default='',blank=True)
etat = models.CharField(max_length=100,default='Bon état',choices = [('Bon état',_('Bon état')),('Etat moyen',_('Etat moyen')),('Mauvais état',_('Mauvais état'))])
marque = models.CharField(_("Marque"),max_length=100,null=True,blank=True)
serial = models.CharField(_("Numéro de série"),max_length=100,default=' ',null=True,blank=True)
annee = models.CharField(_("Année d'achat"),max_length=100,null=True,blank=True)
owner = models.CharField(_("Propriétaire"),max_length=100,default='Fanfare')
user = models.CharField(_('Utilisateur'),max_length=100,blank=True)
model = models.CharField(_("Modèle"), max_length=100, null=True, blank=True)
prix = models.CharField(_("Prix"), max_length=100, default="", blank=True)
etat = models.CharField(
max_length=100,
default="Bon état",
choices=[
("Bon état", _("Bon état")),
("Etat moyen", _("Etat moyen")),
("Mauvais état", _("Mauvais état")),
],
)
marque = models.CharField(_("Marque"), max_length=100, null=True, blank=True)
serial = models.CharField(
_("Numéro de série"), max_length=100, default=" ", null=True, blank=True
)
annee = models.CharField(_("Année d'achat"), max_length=100, null=True, blank=True)
owner = models.CharField(_("Propriétaire"), max_length=100, default="Fanfare")
user = models.CharField(_("Utilisateur"), max_length=100, blank=True)
type = models.CharField(_("Instrument"), max_length=40, blank=False)
statut = models.CharField(max_length=100,default='Disponible',choices = [('Disponible',_('Disponible')),('Prêté',_('Prêté'))])
infos = models.TextField(_("Infos utiles"), null=False, blank=True,default="")
infos_en = models.TextField("Infos utiles en anglais", null=False, blank=True,default="")
statut = models.CharField(
max_length=100,
default="Disponible",
choices=[("Disponible", _("Disponible")), ("Prêté", _("Prêté·e"))],
)
infos = models.TextField(_("Infos utiles"), null=False, blank=True, default="")
infos_en = models.TextField(
"Infos utiles en anglais", null=False, blank=True, default=""
)
def __str__(self):
return self.type
class Meta:
verbose_name = _('Instrument')
verbose_name_plural = _('Instruments')
ordering = (Lower('type'),)
verbose_name = _("Instrument")
verbose_name_plural = _("Instruments")
ordering = (Lower("type"),)
class Reparation(models.Model):
date = models.DateField(_("Date"),max_length=100)
instru = models.ForeignKey("Instrument", on_delete=models.CASCADE,verbose_name=_("Instrument"))
description = models.CharField(_("Description"),max_length=100,default=' ',blank=True)
description_en = models.CharField(_("Description en anglais"),max_length=100,default=' ',blank=True)
prix = models.CharField(_("Prix"),max_length=100,default='',blank=True)
lieux = models.CharField(_('Lieux'),max_length=100,default=' ',blank=True)
date = models.DateField(_("Date"), max_length=100)
instru = models.ForeignKey(
"Instrument", on_delete=models.CASCADE, verbose_name=_("Instrument")
)
description = models.CharField(
_("Description"), max_length=100, default=" ", blank=True
)
description_en = models.CharField(
_("Description en anglais"), max_length=100, default=" ", blank=True
)
prix = models.CharField(_("Prix"), max_length=100, default="", blank=True)
lieux = models.CharField(_("Lieux"), max_length=100, default=" ", blank=True)
def __str__(self):
return self.description
class Meta:
verbose_name = _('Réparation')
verbose_name_plural = _('Réparations')
ordering = ('date',)
verbose_name = _("Réparation")
verbose_name_plural = _("Réparations")
ordering = ("date",)

View file

@ -1,8 +1,6 @@
{% extends "gestion/base.html" %}
{% load static %}
{% load i18n %}
{% load autotranslate %}
{% load halflength %}
{% block titre %}{% trans "Instruments" %}{% endblock %}
{% block content %}
<div id="main">
@ -19,9 +17,9 @@
</div>
{% else %}
<img src="{% static 'images/instruments.jpg' %}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
<div class="icon fa-copyright" style="color:#000000"> Lucas Gierzack</div>
<div class="icon fa-copyright" style="color:#000000"> Lucas Gierzack</div></div>
{% endif %}
</div></span>
</span>
{% if user.profile.is_chef %}
<a href="{% url "instruments:ajouter_instru" %}" class="button alt big">{% trans "Ajouter un instrument" %}</a>
{% endif %}
@ -38,9 +36,9 @@
</thead>
<tbody>
{% for instrument in instrus_dispo %}
<a href="{% url "instruments:fiche_instru" instrument.id %}">
<tr>
<td> {{ instrument.type }} </td>
<td> <a href="{% url "instruments:fiche_instru" instrument.id %}">{{ instrument.type }} </a></td>
<td> {{ instrument.owner }} </td>
<td> {{ instrument.etat }} </td>
<td>
@ -76,7 +74,7 @@
{% for instrument in instrus_prete %}
<tr>
<td> {{ instrument.type }} </td>
<td> <a href="{% url "instruments:fiche_instru" instrument.id %}">{{ instrument.type }} </a> </td>
<td> {{ instrument.owner }} </td>
<td> {{ instrument.user }} </td>
<td> {{ instrument.etat}} </td>

View file

@ -9,7 +9,7 @@
<div id="main">
<section class="wrapper style1">
<div class="inner">
<h1>{% blocktrans with type=instru.type etat=instru.etat%} {{type}} en {{etat}} {% endblocktrans%}</h1>
<h3>{% blocktrans with type=instru.type etat=instru.etat statut=instru.statut%} {{type}} en {{etat}} : {{statut}} {% endblocktrans%}</h3>
<div class="row">
<div class="7u 12u$(small)">
@ -22,11 +22,11 @@
{% trans "Modele : "%} {{instru.model}} <br>
{% trans "Numéro de série : "%} {{instru.serial}} <br>
{% trans "Prix : "%} {{instru.prix}} <br>
{% blocktrans with annee=instru.annee %} Acheté.e en {{annee}} {% endblocktrans%}
{% blocktrans with annee=instru.annee %} Acheté·e en {{annee}} {% endblocktrans%}
</p>
{% if infos or infos_en %}
<h3>{% trans "Infos utiles :" %}</h3>
<h1>{% trans "Infos utiles :" %}</h1>
<div class="box">{% autotranslate current_language infos infos_en %}</div>
@ -95,16 +95,6 @@
{{ form.as_p }}
<input type="submit" value="Enregister" />
</form>
{% else %}
{% if instru.infos %}
<div>
<h4>Infos utiles</h4>
<p>{{ infos }}</p>
</div>
{% endif %}
</div>
</div>
{% endif %}

View file

@ -4,6 +4,7 @@ from django.template.defaultfilters import urlencode
from django.test import Client, TestCase
from gestion.models import ErnestoUser
from ..models import Category, Partition, PartitionSet
User = get_user_model()
@ -11,12 +12,7 @@ User = get_user_model()
def new_user(username, ernesto=False, chef=False):
u = User.objects.create_user(username=username)
ErnestoUser.objects.create(
user=u,
slug=username,
is_chef=chef,
is_ernesto=ernesto
)
ErnestoUser.objects.create(user=u, slug=username, is_chef=chef, is_ernesto=ernesto)
return u
@ -32,16 +28,10 @@ class TestViews(TestCase):
ernesto = new_user("ernesto", ernesto=True)
ernesto_c = Client()
ernesto_c.force_login(ernesto)
self.client_matrix = [
(chef, chef_c),
(ernesto, ernesto_c),
(None, Client())
]
self.client_matrix = [(chef, chef_c), (ernesto, ernesto_c), (None, Client())]
# A Partition set with 1 partition
self.pset = PartitionSet.objects.create(
category=Category.objects.first(),
nom="My PSet",
auteur="PSet author"
category=Category.objects.first(), nom="My PSet", auteur="PSet author"
)
file = File(open("partitions/tests/test_file.txt"), "test file")
Partition.objects.create(nom="part1", part=file, morceau=self.pset)
@ -90,9 +80,7 @@ class TestViews(TestCase):
def test_download(self):
"""Only ernesto members can download partitions"""
part = self.pset.partition_set.first()
url = "/partitions/{}/{}/{}".format(
self.pset.nom, self.pset.auteur, part.id
)
url = "/partitions/{}/{}/{}".format(self.pset.nom, self.pset.auteur, part.id)
self._get_restricted_page(url)
def test_new(self):

View file

@ -2,13 +2,15 @@ from django.urls import path
from . import views
app_name = 'instruments'
app_name = "instruments"
urlpatterns = [
path('', views.liste, name='liste'),
path("delete/<int:pk>", views.InstruDelete.as_view(), name="delete_instru"),
path("delete_reparation/<int:pk>", views.delete_rep, name="delete_rep"),
path("new", views.InstruCreate.as_view(), name="ajouter_instru"),
path("new_rep/<int:pk>", views.create_rep, name="ajouter_rep"),
path("update_rep/<int:pk>", views.RepUpdate.as_view(), name="update_rep"),
path("fiche/<int:pk>",views.fiche_instru,name="fiche_instru"),
path("", views.ListeInstru.as_view(), name="liste"),
path("delete/<int:pk>", views.DeleteInstru.as_view(),
name="delete_instru"),
path("delete_reparation/<int:pk>", views.DeleteRep.as_view(),
name="delete_rep"),
path("new", views.CreateInstru.as_view(), name="ajouter_instru"),
path("new_rep/<int:pk>", views.CreateRep.as_view(), name="ajouter_rep"),
path("update_rep/<int:pk>", views.UpdateRep.as_view(), name="update_rep"),
path("fiche/<int:pk>", views.FicheInstru.as_view(), name="fiche_instru"),
]

View file

@ -1,104 +1,125 @@
from django.shortcuts import render, HttpResponse, get_object_or_404, redirect, reverse
from instruments.models import Instrument,Reparation
from gestion.models import Photo
from django.contrib.auth.decorators import login_required
from django.forms.models import modelform_factory
from django.utils.safestring import mark_safe
from django.utils.text import slugify
from django.core.files import File
from django.utils.encoding import smart_str
from django.http import Http404
from instruments.decorators import chef_required
from django.conf import settings
from django.db.models import Q
import os
import zipfile
import io
from gestion.mixins import ChefRequiredMixin
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.http import HttpResponseRedirect
@login_required
def liste(request):
photo = Photo.objects.filter(cat='instru').order_by('?').first()
instrus_dispo = Instrument.objects.all().order_by('type').filter(statut='Disponible')
instrus_prete = Instrument.objects.all().order_by('type').filter(statut='Prêté')
return render(request, 'instruments/instru_liste.html', {"instrus_dispo":instrus_dispo,"instrus_prete":instrus_prete,"photo":photo})
from django.utils.safestring import mark_safe
from django.views.generic import CreateView, DeleteView, UpdateView
from django.views.generic import TemplateView
from gestion.mixins import ChefRequiredMixin
from django.contrib.auth.mixins import LoginRequiredMixin
from gestion.models import Photo
from instruments.forms import ChefEditInstrumentForm, ChefReparationForm
from instruments.models import Instrument, Reparation
class InstruCreate(ChefRequiredMixin, CreateView):
class ListeInstru(LoginRequiredMixin, TemplateView):
template_name = "instruments/instru_liste.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['photo'] = Photo.objects.filter(
cat="instru").order_by("?").first()
context['instrus_dispo'] = Instrument.objects.all().order_by(
"type").filter(statut="Disponible")
context['instrus_prete'] = Instrument.objects.all().order_by(
"type").filter(statut="Prêté")
return context
class CreateInstru(ChefRequiredMixin, CreateView):
model = Instrument
fields = ["owner",'etat','type','marque','model','serial','annee','prix']
fields = ["owner", "etat", "type", "marque",
"model", "serial", "annee", "prix"]
template_name = "instruments/create_instru.html"
success_url = reverse_lazy("instruments:liste")
@chef_required
def create_rep(request, pk):
ChefEditForm = modelform_factory(Reparation,
fields=("date","description","description_en","prix",'lieux'))
if request.method == "POST":
form = ChefEditForm(request.POST)
class CreateRep(ChefRequiredMixin, TemplateView):
form_class = ChefReparationForm
template_name = "instruments/create_rep.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = self.form_class()
context["pk"] = self.kwargs['pk']
return context
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
rep = Reparation()
rep.date = form.cleaned_data['date']
rep.description = form.cleaned_data['description']
rep.description_en = form.cleaned_data['description_en']
rep.prix = form.cleaned_data['prix']
rep.lieux = form.cleaned_data['lieux']
rep.id_instru = get_object_or_404(Instrument, id=pk)
rep.date = form.cleaned_data["date"]
rep.description = form.cleaned_data["description"]
rep.description_en = form.cleaned_data["description_en"]
rep.prix = form.cleaned_data["prix"]
rep.lieux = form.cleaned_data["lieux"]
rep.instru = get_object_or_404(Instrument, id=self.kwargs['pk'])
rep.save()
return redirect( 'instruments:fiche_instru', pk=pk)
else:
form = ChefEditForm(request.POST)
return render(request, 'instruments/create_rep.html', locals())
return redirect("instruments:fiche_instru", pk=self.kwargs['pk'])
else:
context = self.get_context_data()
context['form'] = form
return render(request, self.template_name, context)
@chef_required
def delete_rep(request,pk):
rep = get_object_or_404(Reparation, id=pk)
id_instru = rep.instru.id
rep.delete()
suppression = _("Réparation supprimée")
return redirect('instruments:fiche_instru',pk=id_instru)
@login_required
def fiche_instru(request, pk):
instru = get_object_or_404(Instrument, id=pk)
reparations= Reparation.objects.filter(instru = pk).order_by('-date')
ChefEditForm = modelform_factory(Instrument,
fields=("statut","user","infos","type","owner","marque","model","serial","annee","prix","infos_en"))
if request.method == "POST" and request.user.profile.is_chef:
form = ChefEditForm(request.POST, instance=instru)
if form.is_valid():
form.save()
form = ChefEditForm(instance=instru)
infos = mark_safe(instru.infos)
infos_en = mark_safe(instru.infos_en)
return render(request, 'instruments/update_instru.html', locals())
class RepUpdate(ChefRequiredMixin, UpdateView):
class DeleteRep(ChefRequiredMixin, TemplateView):
model = Reparation
fields = ["date","description","description_en","prix",'lieux']
template_name = "instruments/delete_instru.html"
def get(self, request, *args, **kwargs):
rep = get_object_or_404(self.model, id=self.kwargs['pk'])
id_instru = rep.instru.id
rep.delete()
return redirect("instruments:fiche_instru", pk=id_instru)
class FicheInstru(LoginRequiredMixin, TemplateView):
template_name = "instruments/update_instru.html"
model = Instrument
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
instru = get_object_or_404(self.model, id=self.kwargs['pk'])
reparations = Reparation.objects.filter(
instru=self.kwargs['pk']).order_by("-date")
form = ChefEditInstrumentForm(instance=instru)
infos = mark_safe(instru.infos)
infos_en = mark_safe(instru.infos_en)
context["reparations"] = reparations
context["instru"] = instru
context["form"] = form
context["infos"] = infos
context["infos_en"] = infos_en
return context
def post(self, request, *args, **kwargs):
instru = get_object_or_404(self.model, id=self.kwargs['pk'])
form = ChefEditInstrumentForm(request.POST, instance=instru)
if request.user.profile.is_chef:
if form.is_valid():
form.save()
context = self.get_context_data()
context['form'] = form
return render(request, self.template_name, context)
class UpdateRep(ChefRequiredMixin, UpdateView):
model = Reparation
fields = ["date", "description", "description_en", "prix", "lieux"]
template_name = "instruments/update_rep.html"
def get_success_url(self):
# if you are passing 'pk' from 'urls' to 'DeleteView' for company
# capture that 'pk' as companyid and pass it to 'reverse_lazy()' function
id_instru=get_object_or_404(Reparation, id=self.kwargs['pk']).instru.id
return reverse_lazy('instruments:fiche_instru', kwargs={'pk': id_instru})
id_instru = get_object_or_404(Reparation,
id=self.kwargs["pk"]).instru.id
return reverse_lazy("instruments:fiche_instru",
kwargs={"pk": id_instru})
class InstruDelete(ChefRequiredMixin, DeleteView):
class DeleteInstru(ChefRequiredMixin, DeleteView):
model = Instrument
template_name = "instruments/delete_instru.html"
success_url = reverse_lazy("instruments:liste")

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,7 @@ import os
import sys
if __name__ == "__main__":
os.environ.setdefault(
"DJANGO_SETTINGS_MODULE",
"Ernestophone.settings.local"
)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Ernestophone.settings.local")
from django.core.management import execute_from_command_line

View file

@ -1,3 +1 @@
from django.contrib import admin
# Register your models here.

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class PadsConfig(AppConfig):
name = 'pads'
name = "pads"

View file

@ -1,8 +1,12 @@
from django import forms
from pads.models import Pad
class PadForm(forms.ModelForm):
class Meta:
model = Pad
fields = ('nom', 'url',)
fields = (
"nom",
"url",
)

View file

@ -6,20 +6,27 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='Pad',
name="Pad",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('nom', models.CharField(max_length=100)),
('url', models.URLField()),
('date', models.DateField(verbose_name='Créé le')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
("nom", models.CharField(max_length=100)),
("url", models.URLField()),
("date", models.DateField(verbose_name="Créé le")),
],
options={
'verbose_name': 'Pad',
"verbose_name": "Pad",
},
),
]

View file

@ -6,13 +6,13 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pads', '0001_initial'),
("pads", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name='pad',
name='date',
field=models.DateField(verbose_name='Cree le'),
model_name="pad",
name="date",
field=models.DateField(verbose_name="Cree le"),
),
]

View file

@ -11,4 +11,6 @@ class Pad(models.Model):
class Meta:
verbose_name = "Pad"
# Create your models here.

View file

@ -2,7 +2,6 @@ from django.urls import path
from pads import views
app_name = "pads"
urlpatterns = [
path("", views.PadList.as_view(), name="list"),

View file

@ -3,6 +3,7 @@ from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
from django.utils import timezone
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from gestion.mixins import ChefRequiredMixin
from pads.models import Pad

View file

@ -1,7 +1,6 @@
from django.contrib import admin
from .models import Category,PartitionSet
from .models import Category, PartitionSet
admin.site.register(Category)
admin.site.register(PartitionSet)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class PartitionsConfig(AppConfig):
name = 'partitions'
name = "partitions"

View file

@ -1,11 +0,0 @@
from django.contrib.auth.decorators import user_passes_test
def is_chef(user):
try:
profile = user.profile
return profile.is_chef
except:
return False
chef_required = user_passes_test(lambda u: is_chef(u))

View file

@ -1,5 +1,7 @@
from django import forms
from .models import PartitionSet
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
@ -9,3 +11,9 @@ class UploadFileForm(forms.Form):
class UploadMorceauForm(forms.Form):
titre = forms.CharField(max_length=100)
auteur = forms.CharField(max_length=100)
class ChefEditMorceauForm(forms.ModelForm):
class Meta:
model = PartitionSet
fields = ("category", "download_unlogged", "infos", "url", "infos_en")

View file

@ -6,31 +6,66 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='Partition',
name="Partition",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('nom', models.CharField(max_length=100)),
('part', models.FileField(upload_to='partitions/')),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
("nom", models.CharField(max_length=100)),
("part", models.FileField(upload_to="partitions/")),
],
),
migrations.CreateModel(
name='PartitionSet',
name="PartitionSet",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
('nom', models.CharField(max_length=100)),
('auteur', models.CharField(max_length=100)),
('category', models.CharField(max_length=8, choices=[('active', 'Actif'), ('incoming', 'À venir'), ('old', 'Archive'), ('optional', 'Optionnel')], default='incoming', verbose_name='Types de partitions')),
('infos', models.TextField(blank=True, verbose_name='Infos utiles', null=True)),
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
verbose_name="ID",
serialize=False,
),
),
("nom", models.CharField(max_length=100)),
("auteur", models.CharField(max_length=100)),
(
"category",
models.CharField(
max_length=8,
choices=[
("active", "Actif"),
("incoming", "À venir"),
("old", "Archive"),
("optional", "Optionnel"),
],
default="incoming",
verbose_name="Types de partitions",
),
),
(
"infos",
models.TextField(
blank=True, verbose_name="Infos utiles", null=True
),
),
],
),
migrations.AddField(
model_name='partition',
name='morceau',
field=models.ForeignKey(to='partitions.PartitionSet', on_delete=models.CASCADE),
model_name="partition",
name="morceau",
field=models.ForeignKey(
to="partitions.PartitionSet", on_delete=models.CASCADE
),
),
]

View file

@ -1,19 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
from django.db import migrations, models
def create_categories(apps, schema_editor):
# Insert the previously hardcoded categories in the database
Category = apps.get_model("partitions", "Category")
Category.objects.bulk_create([
Category(name="Partitions actives", order=1),
Category(name="Partitions optionnelles", order=2),
Category(name="Partitions à venir", order=3),
Category(name="Archives", order=4)
])
Category.objects.bulk_create(
[
Category(name="Partitions actives", order=1),
Category(name="Partitions optionnelles", order=2),
Category(name="Partitions à venir", order=3),
Category(name="Archives", order=4),
]
)
def set_new_categories(apps, schema_editor):
@ -24,7 +26,7 @@ def set_new_categories(apps, schema_editor):
"active": assoc_list[0],
"incoming": assoc_list[2],
"old": assoc_list[3],
"optional": assoc_list[1]
"optional": assoc_list[1],
}
for par_set in PartitionSet.objects.all():
par_set.category = mapping[par_set.category_old]
@ -39,7 +41,7 @@ def reset_old_categories(apps, schema_editor):
assoc_list[0][1]: "active",
assoc_list[2][1]: "incoming",
assoc_list[3][1]: "old",
assoc_list[1][1]: "optional"
assoc_list[1][1]: "optional",
}
for par_set in PartitionSet.objects.all():
par_set.category_old = mapping[par_set.category]
@ -49,29 +51,39 @@ def reset_old_categories(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
('partitions', '0001_initial'),
("partitions", "0001_initial"),
]
operations = [
migrations.CreateModel(
name='Category',
name="Category",
fields=[
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
('name', models.CharField(max_length=127)),
('order', models.IntegerField(verbose_name='order')),
(
"id",
models.AutoField(
verbose_name="ID",
primary_key=True,
serialize=False,
auto_created=True,
),
),
("name", models.CharField(max_length=127)),
("order", models.IntegerField(verbose_name="order")),
],
options={'verbose_name': 'catégorie', 'verbose_name_plural': 'catégories'},
options={"verbose_name": "catégorie", "verbose_name_plural": "catégories"},
),
migrations.RunPython(create_categories, migrations.RunPython.noop),
migrations.RenameField(model_name="partitionset", old_name="category", new_name="category_old"),
migrations.RenameField(
model_name="partitionset", old_name="category", new_name="category_old"
),
migrations.AddField(
model_name='partitionset',
name='category',
model_name="partitionset",
name="category",
field=models.ForeignKey(
verbose_name='Type de partition',
to='partitions.Category',
verbose_name="Type de partition",
to="partitions.Category",
on_delete=django.db.models.deletion.PROTECT,
default=1 # Dummy, will be set by the RunPython operation
default=1, # Dummy, will be set by the RunPython operation
),
preserve_default=False,
),

View file

@ -1,47 +1,78 @@
# Generated by Django 2.2.14 on 2020-07-16 17:49
from django.db import migrations, models
import django.db.models.expressions
import django.db.models.functions.text
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('partitions', '0002_category'),
("partitions", "0002_category"),
]
operations = [
migrations.AlterModelOptions(
name='category',
options={'ordering': ('order',), 'verbose_name': 'Categorie', 'verbose_name_plural': 'Categories'},
name="category",
options={
"ordering": ("order",),
"verbose_name": "Categorie",
"verbose_name_plural": "Categories",
},
),
migrations.AlterModelOptions(
name='partition',
options={'ordering': (django.db.models.expressions.CombinedExpression(django.db.models.expressions.Value('-'), '+', django.db.models.functions.text.Lower('nom')),), 'verbose_name': 'Morceau', 'verbose_name_plural': 'Morceaux'},
name="partition",
options={
"ordering": (
django.db.models.expressions.CombinedExpression(
django.db.models.expressions.Value("-"),
"+",
django.db.models.functions.text.Lower("nom"),
),
),
"verbose_name": "Morceau",
"verbose_name_plural": "Morceaux",
},
),
migrations.AlterModelOptions(
name='partitionset',
options={'ordering': (django.db.models.expressions.CombinedExpression(django.db.models.expressions.Value('-'), '+', django.db.models.functions.text.Lower('nom')),), 'verbose_name': 'Morceau', 'verbose_name_plural': 'Morceaux'},
name="partitionset",
options={
"ordering": (
django.db.models.expressions.CombinedExpression(
django.db.models.expressions.Value("-"),
"+",
django.db.models.functions.text.Lower("nom"),
),
),
"verbose_name": "Morceau",
"verbose_name_plural": "Morceaux",
},
),
migrations.AddField(
model_name='category',
name='nom_en',
model_name="category",
name="nom_en",
field=models.CharField(blank=True, max_length=100, null=True),
),
migrations.AddField(
model_name='partitionset',
name='infos_en',
field=models.TextField(blank=True, null=True, verbose_name='Infos utiles en anglais'),
model_name="partitionset",
name="infos_en",
field=models.TextField(
blank=True, null=True, verbose_name="Infos utiles en anglais"
),
),
migrations.AddField(
model_name='partitionset',
name='url',
field=models.URLField(blank=True, help_text='Dans Youtube cliquer sur partager puis importer pour récuperer la bonne adresse', null=True, verbose_name="Url d'une video youtube"),
model_name="partitionset",
name="url",
field=models.URLField(
blank=True,
help_text="Dans Youtube cliquer sur partager puis importer pour récuperer la bonne adresse",
null=True,
verbose_name="Url d'une video youtube",
),
),
migrations.AlterField(
model_name='category',
name='order',
field=models.IntegerField(verbose_name='ordre'),
model_name="category",
name="order",
field=models.IntegerField(verbose_name="ordre"),
),
]

View file

@ -1,37 +1,52 @@
# Generated by Django 2.2.17 on 2021-03-31 13:50
from django.db import migrations, models
import django.db.models.functions.text
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('partitions', '0003_auto_20200716_1749'),
("partitions", "0003_auto_20200716_1749"),
]
operations = [
migrations.AlterModelOptions(
name='partition',
options={'ordering': (django.db.models.functions.text.Lower('nom'),), 'verbose_name': 'Morceau', 'verbose_name_plural': 'Morceaux'},
name="partition",
options={
"ordering": (django.db.models.functions.text.Lower("nom"),),
"verbose_name": "Morceau",
"verbose_name_plural": "Morceaux",
},
),
migrations.AlterModelOptions(
name='partitionset',
options={'ordering': (django.db.models.functions.text.Lower('nom'),), 'verbose_name': 'Morceau', 'verbose_name_plural': 'Morceaux'},
name="partitionset",
options={
"ordering": (django.db.models.functions.text.Lower("nom"),),
"verbose_name": "Morceau",
"verbose_name_plural": "Morceaux",
},
),
migrations.AddField(
model_name='partitionset',
name='download_unlogged',
field=models.CharField(choices=[('n', 'Non'), ('o', 'Oui')], default='n', max_length=1, verbose_name='Téléchargeable non connecté ?'),
model_name="partitionset",
name="download_unlogged",
field=models.CharField(
choices=[("n", "Non"), ("o", "Oui")],
default="n",
max_length=1,
verbose_name="Téléchargeable non connecté ?",
),
),
migrations.AlterField(
model_name='partitionset',
name='infos',
field=models.TextField(blank=True, default='', verbose_name='Infos utiles'),
model_name="partitionset",
name="infos",
field=models.TextField(blank=True, default="", verbose_name="Infos utiles"),
),
migrations.AlterField(
model_name='partitionset',
name='infos_en',
field=models.TextField(blank=True, default='', verbose_name='Infos utiles en anglais'),
model_name="partitionset",
name="infos_en",
field=models.TextField(
blank=True, default="", verbose_name="Infos utiles en anglais"
),
),
]

View file

@ -2,29 +2,28 @@ import os
from django.conf import settings
from django.db import models
from colorful.fields import RGBColorField
from django.db.models.functions import Lower
from django.utils.translation import gettext_lazy as _
class Category(models.Model):
name = models.CharField(max_length=127)
order = models.IntegerField(verbose_name=_("ordre"))
nom_en = models.CharField(max_length=100,null=True,blank=True)
nom_en = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return self.name
class Meta:
verbose_name = _("Categorie")
verbose_name_plural = _("Categories")
ordering = ('order',)
ordering = ("order",)
class Partition(models.Model):
nom = models.CharField(max_length=100)
part = models.FileField(upload_to="partitions/")
morceau = models.ForeignKey('PartitionSet', on_delete=models.CASCADE)
morceau = models.ForeignKey("PartitionSet", on_delete=models.CASCADE)
def __str__(self):
return self.nom
@ -34,26 +33,40 @@ class Partition(models.Model):
super(Partition, self).delete(*args, **kwargs)
class Meta:
verbose_name = _('Morceau')
verbose_name_plural = _('Morceaux')
ordering = (Lower('nom'),)
verbose_name = _("Morceau")
verbose_name_plural = _("Morceaux")
ordering = (Lower("nom"),)
class PartitionSet(models.Model):
nom = models.CharField(max_length=100)
auteur = models.CharField(max_length=100)
category = models.ForeignKey(
Category,
on_delete=models.PROTECT,
verbose_name=_("Type de partition")
Category, on_delete=models.PROTECT, verbose_name=_("Type de partition")
)
download_unlogged = models.CharField(_("Téléchargeable non connecté ?"),default='n',choices = [('n',_('Non')),('o',_('Oui'))],max_length=1)
infos = models.TextField(_("Infos utiles"), null=False, blank=True,default="")
infos_en = models.TextField("Infos utiles en anglais", null=False, blank=True,default="")
url = models.URLField(_("Url d'une video youtube"),null=True,blank=True, help_text= _("Dans Youtube cliquer sur partager puis importer pour récuperer la bonne adresse"))
download_unlogged = models.CharField(
_("Téléchargeable non connecté ?"),
default="n",
choices=[("n", _("Non")), ("o", _("Oui"))],
max_length=1,
)
infos = models.TextField(_("Infos utiles"), null=False, blank=True, default="")
infos_en = models.TextField(
"Infos utiles en anglais", null=False, blank=True, default=""
)
url = models.URLField(
_("Url d'une video youtube"),
null=True,
blank=True,
help_text=_(
"Dans Youtube cliquer sur partager puis importer pour récuperer la bonne adresse"
),
)
def __str__(self):
return("%s - %s [%s]" % (self.nom, self.auteur, self.category))
return "%s - %s [%s]" % (self.nom, self.auteur, self.category)
class Meta:
verbose_name = _('Morceau')
verbose_name_plural = _('Morceaux')
ordering = (Lower('nom'),)
verbose_name = _("Morceau")
verbose_name_plural = _("Morceaux")
ordering = (Lower("nom"),)

View file

@ -7,7 +7,7 @@
<div class="inner">
<h4>{% trans "Confirmation de suppression" %}</h4>
<p>{% trans "Voulez-vous vraiment supprimer cette partition ?" %}"</p>
<p>{% trans "Voulez-vous vraiment supprimer cette partition ?" %}</p>
<p><a href="{% url "partitions:delete" nom auteur id %}" class="button " >{% trans "Oui" %}</a></p>
<p><a href="{% url "partitions:listepart" nom auteur %}" class="button alt" >{% trans "Retour à la liste des partitions" %}</a></p>

View file

@ -74,7 +74,7 @@
<div class="box">{% autotranslate current_language infos infos_en %}</div>
{% endif %}
{% endif %}

View file

@ -20,9 +20,9 @@
</div>
{% else %}
<img src="{% static 'images/all_repertoire.jpg' %}" alt="" /> <div style="position:absolute;z-index:1;right:0;bottom:0">
<div class="icon fa-copyright" style="color:#000000"> Lucas Gierzack</div>
<div class="icon fa-copyright" style="color:#000000"> Lucas Gierzack</div></div>
{% endif %}
</div></span>
</span>
{% if user.profile.is_chef %}
<a href="{% url "partitions:ajouter_morceau" %}" class="button alt big">{% trans "Ajouter un morceau" %}</a> &nbsp <a href="{% url "partitions:download_musecores" %}" class="button alt big">{% trans "Télécharger tous les musecores actifs" %}</a>
{% elif user.is_authenticated %}

View file

@ -4,6 +4,7 @@ from django.template.defaultfilters import urlencode
from django.test import Client, TestCase
from gestion.models import ErnestoUser
from ..models import Category, Partition, PartitionSet
User = get_user_model()
@ -11,12 +12,7 @@ User = get_user_model()
def new_user(username, ernesto=False, chef=False):
u = User.objects.create_user(username=username)
ErnestoUser.objects.create(
user=u,
slug=username,
is_chef=chef,
is_ernesto=ernesto
)
ErnestoUser.objects.create(user=u, slug=username, is_chef=chef, is_ernesto=ernesto)
return u
@ -32,16 +28,10 @@ class TestViews(TestCase):
ernesto = new_user("ernesto", ernesto=True)
ernesto_c = Client()
ernesto_c.force_login(ernesto)
self.client_matrix = [
(chef, chef_c),
(ernesto, ernesto_c),
(None, Client())
]
self.client_matrix = [(chef, chef_c), (ernesto, ernesto_c), (None, Client())]
# A Partition set with 1 partition
self.pset = PartitionSet.objects.create(
category=Category.objects.first(),
nom="My PSet",
auteur="PSet author"
category=Category.objects.first(), nom="My PSet", auteur="PSet author"
)
file = File(open("partitions/tests/test_file.txt"), "test file")
Partition.objects.create(nom="part1", part=file, morceau=self.pset)
@ -90,9 +80,7 @@ class TestViews(TestCase):
def test_download(self):
"""Only ernesto members can download partitions"""
part = self.pset.partition_set.first()
url = "/partitions/{}/{}/{}".format(
self.pset.nom, self.pset.auteur, part.id
)
url = "/partitions/{}/{}/{}".format(self.pset.nom, self.pset.auteur, part.id)
self._get_restricted_page(url)
def test_new(self):

View file

@ -2,17 +2,26 @@ from django.urls import path
from . import views
app_name = 'partitions'
app_name = "partitions"
urlpatterns = [
path('', views.liste, name='liste'),
path('download', views.download_musecores, name='download_musecores'),
path("<str:nom>/<str:auteur>/upload", views.upload, name="upload"),
path("<str:nom>/<str:auteur>", views.listepart, name="listepart"),
path("<str:nom>/<str:auteur>/see/<int:partition_id>", views.see, name="see"),
path("<str:nom>/<str:auteur>/<int:partition_id>", views.download, name="download"),
path("<str:nom>/<str:auteur>/<int:id>/conf", views.conf_delete, name="conf_delete"),
path("<str:nom>/<str:auteur>/<int:id>/delete", views.delete, name="delete"),
path("<str:nom>/<str:auteur>/delete", views.delete_morc, name="delete_morc"),
path("<str:nom>/<str:auteur>/conf", views.conf_delete_morc, name="conf_delete_morc"),
path("new", views.ajouter_morceau, name="ajouter_morceau"),
path("", views.Repertoire.as_view(), name="liste"),
path("download", views.download_musecores, name="download_musecores"),
path("<str:nom>/<str:auteur>/upload", views.Upload.as_view(),
name="upload"),
path("<str:nom>/<str:auteur>", views.Morceau.as_view(), name="listepart"),
path("<str:nom>/<str:auteur>/see/<int:partition_id>", views.see,
name="see"),
path("<str:nom>/<str:auteur>/<int:partition_id>", views.download,
name="download"),
path("<str:nom>/<str:auteur>/<int:id>/conf", views.ConfDelete.as_view(),
name="conf_delete"),
path("<str:nom>/<str:auteur>/<int:id>/delete", views.DeletePart.as_view(),
name="delete"),
path("<str:nom>/<str:auteur>/delete", views.DeleteMorc.as_view(),
name="delete_morc"),
path(
"<str:nom>/<str:auteur>/conf", views.ConfDeleteMorc.as_view(),
name="conf_delete_morc"
),
path("new", views.CreateMorc.as_view(), name="ajouter_morceau"),
]

View file

@ -1,27 +1,34 @@
from django.shortcuts import render, HttpResponse, get_object_or_404, redirect, reverse
from partitions.models import Category, Partition, PartitionSet
from gestion.models import Photo
from django.contrib.auth.decorators import login_required
from partitions.forms import UploadFileForm, UploadMorceauForm
from django.forms.models import modelform_factory
from django.utils.safestring import mark_safe
from django.utils.text import slugify
from django.core.files import File
from django.utils.encoding import smart_str
from django.http import Http404
from partitions.decorators import chef_required
from django.conf import settings
from django.db.models import Q
import io
import os
import zipfile
import io
from django.core.files import File
from django.db.models import Q
from django.http import Http404
from django.shortcuts import HttpResponse, get_object_or_404, redirect, render
from django.utils.safestring import mark_safe
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from gestion.models import Photo
from partitions.forms import UploadFileForm, UploadMorceauForm
from partitions.models import Category, Partition, PartitionSet
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
from .forms import ChefEditMorceauForm
from gestion.mixins import ChefRequiredMixin
def download_musecores(request):
p = Partition.objects.filter(Q(part__contains = ".mscz") & Q(Q(morceau__category__name = "Partitions actives" )|Q(morceau__category__name = "Partitions optionnelles" )))
p = Partition.objects.filter(
Q(part__contains=".mscz")
& Q(
Q(morceau__category__name="Partitions actives")
| Q(morceau__category__name="Partitions optionnelles")
)
)
zip_subdir = "Ernestophone_musescores"
zip_filename = "%s.zip" % zip_subdir
@ -32,14 +39,22 @@ def download_musecores(request):
# The zip compressor
zf = zipfile.ZipFile(s, "w")
for part in p :
for part in p:
fpath = part.part.path
typ=".mscz"
typ = ".mscz"
# Calculate path for file in zip
fdir, fname = os.path.split(fpath)
zip_path = os.path.join(zip_subdir, '%s_%s_%s.%s' % (
slugify(part.morceau.nom), slugify(part.morceau.auteur), slugify(part.nom), typ))
zip_path = os.path.join(
zip_subdir,
"%s_%s_%s.%s"
% (
slugify(part.morceau.nom),
slugify(part.morceau.auteur),
slugify(part.nom),
typ,
),
)
# Add file, at correct path
zf.write(fpath, zip_path)
@ -49,70 +64,117 @@ def download_musecores(request):
# Grab ZIP file from in-memory, make response with correct MIME-type
resp = HttpResponse(s.getvalue())
# ..and correct content-disposition
resp['Content-Disposition'] = 'attachment; filename=%s' % zip_filename
resp["Content-Disposition"] = "attachment; filename=%s" % zip_filename
return resp
def liste(request):
categories = Category.objects.prefetch_related("partitionset_set").order_by("order")
photo = Photo.objects.filter(cat='part').order_by('?').first()
return render(request, 'partitions/repertoire.html', {"categories": categories,"photo":photo})
@login_required
def listepart(request, nom, auteur):
p = get_object_or_404(PartitionSet, nom=nom, auteur=auteur)
part = p.partition_set.all().order_by('nom')
ChefEditForm = modelform_factory(PartitionSet,
fields=("category","download_unlogged", "infos","url","infos_en"))
if request.method == "POST" and request.user.profile.is_chef:
form = ChefEditForm(request.POST, instance=p)
if form.is_valid():
form.save()
form = ChefEditForm(instance=p)
infos = mark_safe(p.infos)
infos_en = mark_safe(p.infos_en)
return render(request, 'partitions/part.html', locals())
class Repertoire(TemplateView):
template_name = "partitions/repertoire.html"
@chef_required
def upload(request, nom, auteur):
if request.method == "POST":
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['categories'] = Category.objects.prefetch_related(
"partitionset_set").order_by("order")
context['photo'] = Photo.objects.filter(
cat="part").order_by("?").first()
return context
class Morceau(LoginRequiredMixin, TemplateView):
template_name = "partitions/part.html"
form_class = ChefEditMorceauForm
def get_context_data(self, **kwargs):
context = super(Morceau, self).get_context_data(**kwargs)
p = get_object_or_404(PartitionSet, nom=self.kwargs['nom'],
auteur=self.kwargs['auteur'])
part = p.partition_set.all().order_by("nom")
form = self.form_class(instance=p)
infos = mark_safe(p.infos)
infos_en = mark_safe(p.infos_en)
context["p"] = p
context["infos"] = infos
context["infos_en"] = infos_en
context["form"] = form
context["part"] = part
context["nom"] = self.kwargs['nom']
context["auteur"] = self.kwargs['auteur']
return context
def post(self, request, *args, **kwargs):
p = get_object_or_404(PartitionSet, nom=self.kwargs['nom'],
auteur=self.kwargs['auteur'])
if request.user.profile.is_chef:
form = self.form_class(request.POST, instance=p)
if form.is_valid():
form.save()
context = self.get_context_data()
return render(request, self.template_name, context)
class Upload(ChefRequiredMixin, TemplateView):
form_class = UploadFileForm
sauvegarde = False
error = False
template_name = "partitions/upload.html"
def get_context_data(self, **kwargs):
context = super(Upload, self).get_context_data(**kwargs)
form = self.form_class()
context["sauvegarde"] = self.sauvegarde
context["nom"] = self.kwargs['nom']
context["auteur"] = self.kwargs['auteur']
context["form"] = form
context["error"] = self.error
return context
def post(self, request, *args, **kwargs):
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
partition = Partition()
partition.part = form.cleaned_data['file']
partition.nom = form.cleaned_data['title']
if '/' in partition.nom:
error = _("Le caractère / n'est pas autorisé dans le nom")
form = UploadFileForm()
return render(request, "partitions/upload.html", locals())
mor = get_object_or_404(PartitionSet, nom=nom, auteur=auteur)
partition.part = form.cleaned_data["file"]
partition.nom = form.cleaned_data["title"]
if "/" in partition.nom:
self.error = _("Le caractère / n'est pas autorisé dans le nom")
context = self.get_context_data()
return render(request, self.template_name, context)
mor = get_object_or_404(PartitionSet, nom=self.kwargs['nom'],
auteur=self.kwargs['auteur'])
partition.morceau = mor
try:
mor.partition_set.get(nom=partition.nom)
error = _("Un morceau du même nom existe déjà")
self.error = _("Un morceau du même nom existe déjà")
except Partition.DoesNotExist:
partition.save()
sauvegarde = True
else:
form = UploadFileForm()
return render(request, 'partitions/upload.html', locals())
self.sauvegarde = True
context = self.get_context_data()
context['form'] = form
return render(request, self.template_name, context)
def see(request, nom, auteur, partition_id):
partition = get_object_or_404(Partition, id=partition_id)
_, extension = os.path.splitext(partition.part.path)
download_unlogged = partition.morceau.download_unlogged
if(download_unlogged == 'o' or request.user.is_authenticated):
if download_unlogged == "o" or request.user.is_authenticated:
if ".pdf" == extension:
with open(partition.part.path, 'rb') as f:
with open(partition.part.path, "rb") as f:
myfile = File(f)
response = HttpResponse(content=myfile.read())
response["Content-Type"] = "application/pdf"
response["Content-Disposition"] = "inline; filename=%s_%s_%s.pdf" % (
slugify(nom), slugify(auteur), slugify(partition.nom))
slugify(nom),
slugify(auteur),
slugify(partition.nom),
)
return response
elif ".mp3" == extension:
with open(partition.part.path, 'rb') as f:
with open(partition.part.path, "rb") as f:
myfile = File(f)
response = HttpResponse()
response.write(myfile.read())
@ -122,38 +184,56 @@ def see(request, nom, auteur, partition_id):
else:
p = get_object_or_404(PartitionSet, nom=nom, auteur=auteur)
part = p.partition_set.all()
return render(request, 'partitions/part.html', locals())
else :
return redirect('login')
return render(
request,
"partitions/part.html",
{"p": p, "part": part, "nom": nom, "auteur": auteur},
)
else:
return redirect("login")
@chef_required
def delete(request, nom, auteur, id):
p = get_object_or_404(PartitionSet, nom=nom, auteur=auteur)
try:
part = p.partition_set.get(id=id)
except Partition.DoesNotExist:
raise Http404
part.delete()
suppression = _("Partition supprimée")
p.refresh_from_db()
part = p.partition_set.all()
return redirect('partitions:listepart',nom=nom,auteur=auteur)
@chef_required
def ajouter_morceau(request):
if request.method == "POST":
form = UploadMorceauForm(request.POST)
class DeletePart(ChefRequiredMixin, TemplateView):
model = PartitionSet
def get(self, request, *args, **kwargs):
p = get_object_or_404(self.model, nom=self.kwargs['nom'],
auteur=self.kwargs['auteur'])
try:
part = p.partition_set.get(id=self.kwargs['id'])
except Partition.DoesNotExist:
raise Http404
part.delete()
return redirect("partitions:listepart", nom=self.kwargs['nom'],
auteur=self.kwargs['auteur'])
class CreateMorc(ChefRequiredMixin, TemplateView):
form_class = UploadMorceauForm
template_name = "partitions/new.html"
def get_context_data(self, **kwargs):
context = super(CreateMorc, self).get_context_data(**kwargs)
context['form'] = self.form_class()
return context
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
sauvegarde = False
error = False
if form.is_valid():
partitionset = PartitionSet()
partitionset.nom = form.cleaned_data['titre']
partitionset.auteur = form.cleaned_data['auteur']
if '/' in partitionset.auteur or '/' in partitionset.nom:
partitionset.nom = form.cleaned_data["titre"]
partitionset.auteur = form.cleaned_data["auteur"]
if "/" in partitionset.auteur or "/" in partitionset.nom:
error = _("Le caractère / n'est pas autorisé")
form = UploadMorceauForm()
return render(request, 'partitions/new.html', locals())
context = self.get_context_data()
context['error'] = error
return render(request, self.template_name, context)
try:
PartitionSet.objects.get(nom=partitionset.nom,
auteur=partitionset.auteur)
PartitionSet.objects.get(
nom=partitionset.nom, auteur=partitionset.auteur
)
error = _("Un morceau du même nom existe déjà")
except PartitionSet.DoesNotExist:
# XXX. Hideous
@ -165,50 +245,64 @@ def ajouter_morceau(request):
partitionset.category = cat
partitionset.save()
sauvegarde = True
return redirect('partitions:liste')
else:
form = UploadMorceauForm()
return render(request, 'partitions/new.html', locals())
return redirect("partitions:liste")
context = self.get_context_data()
context['sauvegarde'] = sauvegarde
context['error'] = error
context['form'] = form
return render(request, self.template_name, context)
class ConfDelete(ChefRequiredMixin, TemplateView):
template_name = "partitions/conf_delete.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['nom'] = self.kwargs.get("nom")
context['auteur'] = self.kwargs.get("auteur")
context['id'] = self.kwargs.get("id")
return context
@chef_required
def conf_delete(request, nom, auteur, id):
part = get_object_or_404(Partition, id=id)
return render(request, 'partitions/conf_delete.html', locals())
class DeleteMorc(ChefRequiredMixin, TemplateView):
model = PartitionSet
@chef_required
def delete_morc(request, nom, auteur):
p = get_object_or_404(PartitionSet, nom=nom, auteur=auteur)
part = p.partition_set.all()
for pa in part:
pa.delete()
p.delete()
partitions = PartitionSet.objects.all()
categories = Category.objects.prefetch_related("partitionset_set")
return redirect('partitions:liste')
def get(self, request, *args, **kwargs):
p = get_object_or_404(self.model, nom=self.kwargs['nom'],
auteur=self.kwargs['auteur'])
part = p.partition_set.all()
for pa in part:
pa.delete()
p.delete()
return redirect("partitions:liste")
@chef_required
def conf_delete_morc(request, nom, auteur):
return render(request, 'partitions/conf_delete_morc.html', locals())
class ConfDeleteMorc(ChefRequiredMixin, TemplateView):
template_name = "partitions/conf_delete_morc.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['nom'] = self.kwargs.get("nom")
context['auteur'] = self.kwargs.get("auteur")
return context
def download(request, nom, auteur, partition_id):
partition = get_object_or_404(Partition, id=partition_id)
download_unlogged = partition.morceau.download_unlogged
if(download_unlogged == 'o' or request.user.is_authenticated):
with open(partition.part.path, 'rb') as f:
if download_unlogged == "o" or request.user.is_authenticated:
with open(partition.part.path, "rb") as f:
myfile = File(f)
response = HttpResponse(content=myfile.read())
typ = os.path.splitext(myfile.name)[1][1:]
response['Content-Type'] = 'application/%s' % (typ, )
response['Content-Disposition'] = 'attachment; filename=%s_%s_%s.%s' % (
slugify(nom), slugify(auteur), slugify(partition.nom), typ)
response["Content-Type"] = "application/%s" % (typ,)
response["Content-Disposition"] = "attachment; filename=%s_%s_%s.%s" % (
slugify(nom),
slugify(auteur),
slugify(partition.nom),
typ,
)
return response
else :
return redirect('login')
else:
return redirect("login")

View file

@ -1,3 +1 @@
from django.contrib import admin
# Register your models here.

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class TrombonoscopeConfig(AppConfig):
name = 'trombonoscope'
name = "trombonoscope"

View file

@ -1,25 +1,26 @@
from django import forms
from gestion.models import ErnestoUser
from django.utils.translation import gettext_lazy as _
class ChangeTrombonoscope(forms.ModelForm):
def save(self, *args, **kwargs):
super(ChangeTrombonoscope, self).save(*args, **kwargs)
trombonoscope = self.cleaned_data["trombonoscope"]
trombonoscope_colors = self.cleaned_data['trombonoscope_colors']
if(trombonoscope_colors != 'autre'):
self.instance.trombonoscope_fond=trombonoscope_colors[:7]
self.instance.trombonoscope_texte=trombonoscope_colors[7:]
self.instance.save( )
trombonoscope_colors = self.cleaned_data["trombonoscope_colors"]
if trombonoscope_colors != "autre":
self.instance.trombonoscope_fond = trombonoscope_colors[:7]
self.instance.trombonoscope_texte = trombonoscope_colors[7:]
self.instance.save()
class Meta:
model = ErnestoUser
fields = ("trombonoscope","nom_trombonoscope","instru_trombonoscope","trombonoscope_colors","trombonoscope_fond","trombonoscope_texte")
fields = (
"trombonoscope",
"nom_trombonoscope",
"instru_trombonoscope",
"trombonoscope_colors",
"trombonoscope_fond",
"trombonoscope_texte",
)

View file

@ -1,3 +1 @@
from django.db import models
# Create your models here.

View file

@ -1,8 +1,10 @@
from django import template
from datetime import date, timedelta
from django import template
register = template.Library()
@register.filter
def modulo(num, val):
return num % val

View file

@ -2,10 +2,8 @@ from django.urls import path
from trombonoscope import views
app_name = "trombonoscope"
urlpatterns = [
path("", views.trombonoscope, name="view"),
path("modif_profil", views.changetrombonoscope, name="change"),
path("", views.Trombonoscope.as_view(), name="view"),
path("modif_profil", views.ChangeTrombonoscope.as_view(), name="change"),
]

View file

@ -1,24 +1,39 @@
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render
from gestion.models import ErnestoUser
from trombonoscope.forms import ChangeTrombonoscope
from django.shortcuts import render, redirect
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
@login_required
def changetrombonoscope(request):
if request.method == 'POST':
requbis = request.POST.copy()
form = ChangeTrombonoscope(request.POST,request.FILES, instance=request.user.profile)
class ChangeTrombonoscope(LoginRequiredMixin, TemplateView):
form_class = ChangeTrombonoscope
template_name = "trombonoscope/changetrombonoscope.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
form = self.form_class(instance=self.request.user.profile)
context['form'] = form
return context
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES,
instance=request.user.profile)
if form.is_valid():
form.save()
success = True
return redirect('trombonoscope:view')
else:
form = ChangeTrombonoscope(instance=request.user.profile)
return render(request, 'trombonoscope/changetrombonoscope.html', locals())
return redirect("trombonoscope:view")
context = self.get_context_data()
context['form'] = form
return render(request, self.template_name, context)
@login_required
def trombonoscope(request):
trombonoscope_actuel = ErnestoUser.objects.filter(trombonoscope = "o_a")
trombonoscope_vieux = ErnestoUser.objects.filter(trombonoscope = "o_v")
return render(request, 'trombonoscope/trombonoscope.html', {'trombonoscope_actuel':trombonoscope_actuel,'trombonoscope_vieux':trombonoscope_vieux})
class Trombonoscope(LoginRequiredMixin, TemplateView):
template_name = "trombonoscope/trombonoscope.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['trombonoscope_vieux'] = ErnestoUser.objects.filter(
trombonoscope="o_v")
context['trombonoscope_actuel'] = ErnestoUser.objects.filter(
trombonoscope="o_a")
return context