From b5a51e1bec92666fa5e9a228b71527f2746a74bc Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Thu, 8 Mar 2018 23:16:03 +0100 Subject: [PATCH 01/10] =?UTF-8?q?Nouvelle=20orientation=20du=20projet,=20r?= =?UTF-8?q?ed=C3=A9finition=20des=20structures=20de=20donn=C3=A9es.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/migrations/0001_initial.py | 7 +- .../migrations/0002_content_school_owner.py | 22 ---- content/models.py | 36 ++++-- settings/migrations/0001_initial.py | 12 +- .../migrations/0002_auto_20180301_1047.py | 28 ----- .../migrations/0003_auto_20180301_1109.py | 23 ---- settings/models.py | 16 ++- settings/views.py | 4 +- site_tps/wsgi.py | 22 ++-- users/admin.py | 44 ------- users/migrations/0001_initial.py | 27 ++-- users/migrations/0002_schoolprofile_admins.py | 20 --- users/migrations/0003_auto_20180301_0933.py | 19 --- users/migrations/0004_auto_20180301_0952.py | 19 --- users/migrations/0005_auto_20180301_1029.py | 19 --- users/migrations/0006_schoolprofile_phone.py | 18 --- users/models.py | 118 +++++++++--------- users/urls.py | 6 - users/views.py | 31 +---- 19 files changed, 141 insertions(+), 350 deletions(-) delete mode 100644 content/migrations/0002_content_school_owner.py delete mode 100644 settings/migrations/0002_auto_20180301_1047.py delete mode 100644 settings/migrations/0003_auto_20180301_1109.py delete mode 100644 users/migrations/0002_schoolprofile_admins.py delete mode 100644 users/migrations/0003_auto_20180301_0933.py delete mode 100644 users/migrations/0004_auto_20180301_0952.py delete mode 100644 users/migrations/0005_auto_20180301_1029.py delete mode 100644 users/migrations/0006_schoolprofile_phone.py diff --git a/content/migrations/0001_initial.py b/content/migrations/0001_initial.py index 004b326..ec520ff 100644 --- a/content/migrations/0001_initial.py +++ b/content/migrations/0001_initial.py @@ -1,5 +1,6 @@ -# Generated by Django 2.0.1 on 2018-02-28 18:43 +# Generated by Django 2.0.1 on 2018-03-08 22:03 +import content.models from django.db import migrations, models import django.db.models.deletion @@ -9,6 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ + ('users', '0001_initial'), ] operations = [ @@ -26,8 +28,9 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=255, verbose_name='Nom du contenu')), - ('file', models.FileField(upload_to='', verbose_name='Fichier')), + ('file', models.FileField(upload_to=content.models.get_upload_to, validators=[content.models.validate_file_extension], verbose_name='Fichier')), ('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='content.Category', verbose_name='Catégorie')), + ('school_owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.School')), ], ), ] diff --git a/content/migrations/0002_content_school_owner.py b/content/migrations/0002_content_school_owner.py deleted file mode 100644 index affdd4d..0000000 --- a/content/migrations/0002_content_school_owner.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 2.0.1 on 2018-02-28 18:43 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('content', '0001_initial'), - ('users', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='content', - name='school_owner', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.SchoolProfile'), - ), - ] diff --git a/content/models.py b/content/models.py index 6c5b204..9597d81 100644 --- a/content/models.py +++ b/content/models.py @@ -1,9 +1,11 @@ -from django.db import models -from django.urls import reverse -from django.contrib.auth.models import Group -from django.conf import settings +import os + +from django.db import models +from django.core.exceptions import ValidationError +from django.urls import reverse + +from users.models import School -from users.models import SchoolProfile class Category(models.Model): """Une catégorie de contenu.""" @@ -19,13 +21,26 @@ class Category(models.Model): verbose_name="Illustration de la catégorie", null=True, ) + def get_absolute_url(self): - return reverse('content:category-list', kwargs={'pk':self.pk}) + return reverse('content:category-list', kwargs={'pk': self.pk}) def __str__(self): return self.name +def get_upload_to(instance, filename): + extension = filename.split('.')[-1] + return "static/media/"+instance.school.name+"/"+instance.category.name+'.'+extension + + +def validate_file_extension(value): + ext = os.path.splitext(value.name)[1] # [0] returns path+filename + valid_extensions = ['mp4', 'avi', 'mov'] + if not ext.lower() in valid_extensions: + raise ValidationError(u'Unsupported file extension.') + + class Content(models.Model): """Un contenu du site (vidéo).""" name = models.CharField( @@ -33,7 +48,7 @@ class Content(models.Model): verbose_name="Nom du contenu" ) school_owner = models.ForeignKey( - SchoolProfile, + School, on_delete=models.CASCADE, ) category = models.ForeignKey( @@ -43,11 +58,10 @@ class Content(models.Model): null=True ) file = models.FileField( - verbose_name="Fichier" + verbose_name="Fichier", + validators=[validate_file_extension], + upload_to=get_upload_to ) def __str__(self): return self.name - - def manager_right(self): - return 'users.manage_' + str(self.school_owner.group.pk) diff --git a/settings/migrations/0001_initial.py b/settings/migrations/0001_initial.py index 035ff9e..7a5978d 100644 --- a/settings/migrations/0001_initial.py +++ b/settings/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.1 on 2018-02-28 18:43 +# Generated by Django 2.0.1 on 2018-03-08 22:03 from django.db import migrations, models @@ -17,6 +17,16 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('allow_upload', models.BooleanField(default=False, verbose_name="Autoriser l'upload de vidéos.")), ('home_message', models.TextField(default='', verbose_name="Message de la page d'accueil")), + ('site_logo', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Logo du site')), + ('event_poster', models.ImageField(blank=True, null=True, upload_to='', verbose_name="Affiche de l'événement")), + ], + ), + migrations.CreateModel( + name='StaticPage', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='Titre de la catégorie')), + ('text', models.TextField(verbose_name='Texte de la catégorie')), ], ), ] diff --git a/settings/migrations/0002_auto_20180301_1047.py b/settings/migrations/0002_auto_20180301_1047.py deleted file mode 100644 index fbfe96d..0000000 --- a/settings/migrations/0002_auto_20180301_1047.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 2.0.1 on 2018-03-01 10:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('settings', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='sitesettings', - name='event_poster', - field=models.ImageField(null=True, upload_to='', verbose_name="Affiche de l'événement"), - ), - migrations.AddField( - model_name='sitesettings', - name='min_number_of_categories', - field=models.PositiveIntegerField(default=0, verbose_name='Nombre minimal de catégories dans laquelle participer'), - ), - migrations.AddField( - model_name='sitesettings', - name='site_logo', - field=models.ImageField(null=True, upload_to='', verbose_name='Logo du site'), - ), - ] diff --git a/settings/migrations/0003_auto_20180301_1109.py b/settings/migrations/0003_auto_20180301_1109.py deleted file mode 100644 index 417d28c..0000000 --- a/settings/migrations/0003_auto_20180301_1109.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 2.0.1 on 2018-03-01 11:09 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('settings', '0002_auto_20180301_1047'), - ] - - operations = [ - migrations.AlterField( - model_name='sitesettings', - name='event_poster', - field=models.ImageField(blank=True, null=True, upload_to='', verbose_name="Affiche de l'événement"), - ), - migrations.AlterField( - model_name='sitesettings', - name='site_logo', - field=models.ImageField(blank=True, null=True, upload_to='', verbose_name='Logo du site'), - ), - ] diff --git a/settings/models.py b/settings/models.py index 6173ce7..2376dfb 100644 --- a/settings/models.py +++ b/settings/models.py @@ -1,7 +1,5 @@ from django.db import models -from .aes_field import AESEncryptedField - class SiteSettings(models.Model): PRETTY_NAME = "Réglages du site" @@ -23,11 +21,17 @@ class SiteSettings(models.Model): null=True, blank=True ) - min_number_of_categories = models.PositiveIntegerField( - verbose_name="Nombre minimal de catégories dans laquelle participer", - default=0, - ) @classmethod def get_settings(cls): return cls.objects.get_or_create()[0] + + +class StaticPage(models.Model): + name = models.CharField( + max_length=255, + verbose_name="Titre de la catégorie", + ) + text = models.TextField( + verbose_name="Texte de la catégorie" + ) diff --git a/settings/views.py b/settings/views.py index bd54782..6fdfd7c 100644 --- a/settings/views.py +++ b/settings/views.py @@ -7,7 +7,7 @@ from django.shortcuts import get_object_or_404, redirect, render from django.contrib import messages from content.models import Category -from users.models import SchoolProfile +from users.models import School from .models import SiteSettings from .forms import SelectUserForm @@ -20,7 +20,7 @@ class SettingsView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView): context = super().get_context_data(**kwargs) context['categories'] = Category.objects.all() context['site_settings'], _ = SiteSettings.objects.get_or_create() - context['schools'] = SchoolProfile.objects.all() + context['schools'] = School.objects.all() context['settings'] = True context['administrators'] = Group.objects.get(name='admins').user_set.all() return context diff --git a/site_tps/wsgi.py b/site_tps/wsgi.py index f3ddb29..90123c0 100644 --- a/site_tps/wsgi.py +++ b/site_tps/wsgi.py @@ -1,16 +1,18 @@ -""" -WSGI config for site_tps project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/ -""" - import os +import sys +VIRTUALENV_LOC = '/var/www/site_tps/env_site' + +# Activation de l'environnement virtuel +activate_env=os.path.join(VIRTUALENV_LOC, 'bin/activate_this.py') +exec(compile(open(activate_env, "rb").read(), activate_env, 'exec'), {'__file__':activate_env}) + +# Ajout du répertoire du site au PATH +sys.path.append('/var/www/site_tps') +sys.path.append('/var/www/site_tps/site_tps') + +# Les trucs par défaut de Django from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site_tps.settings") - application = get_wsgi_application() diff --git a/users/admin.py b/users/admin.py index 465315b..e69de29 100644 --- a/users/admin.py +++ b/users/admin.py @@ -1,44 +0,0 @@ -from django.contrib import admin -from django.contrib.auth.admin import UserAdmin as BaseUserAdmin -from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin -from django.contrib.auth.models import User, Group - -from .models import UserProfile, SchoolProfile - -# Define an inline admin descriptor for Employee model -# which acts a bit like a singleton - - -class UserInline(admin.StackedInline): - model = UserProfile - can_delete = False - verbose_name_plural = 'user profiles' - -# Define a new User admin - - -class UserAdmin(BaseUserAdmin): - inlines = (UserInline, ) - -# Define an inline admin descriptor for Employee model -# which acts a bit like a singleton - - -class SchoolInline(admin.StackedInline): - model = SchoolProfile - can_delete = False - verbose_name_plural = 'schools' - fk_name = 'admins' - -# Define a new User admin - - -class GroupAdmin(BaseGroupAdmin): - inlines = (SchoolInline, ) - - -# Re-register UserAdmin -admin.site.unregister(User) -admin.site.register(User, UserAdmin) -admin.site.unregister(Group) -admin.site.register(Group, GroupAdmin) diff --git a/users/migrations/0001_initial.py b/users/migrations/0001_initial.py index f355ca7..5f9ade5 100644 --- a/users/migrations/0001_initial.py +++ b/users/migrations/0001_initial.py @@ -1,8 +1,10 @@ -# Generated by Django 2.0.1 on 2018-02-28 18:43 +# Generated by Django 2.0.1 on 2018-03-08 22:03 from django.conf import settings +import django.core.validators from django.db import migrations, models import django.db.models.deletion +import users.models class Migration(migrations.Migration): @@ -10,24 +12,25 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('auth', '0009_alter_user_last_name_max_length'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( - name='SchoolProfile', + name='School', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='students', to='auth.Group')), - ], - ), - migrations.CreateModel( - name='UserProfile', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('school', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.SchoolProfile')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('phone', models.CharField(help_text='Visible uniquement des administrateurs', max_length=10, null=True, validators=[django.core.validators.RegexValidator('^[0-9]{10}$', 'Veuillez entrer un numéro à 10 chiffres.')], verbose_name='Numéro de téléphone pour contacter le responsable des productions')), + ('logo', models.ImageField(null=True, upload_to=users.models.get_upload_to, verbose_name="Logo à utiliser pour représenter l'école")), + ('first_name_j1', models.CharField(max_length=255, verbose_name='Prénom juré n°1')), + ('last_name_j1', models.CharField(max_length=255, verbose_name='Nom juré n°1')), + ('phone_j1', models.CharField(help_text='Visible uniquement des administrateurs', max_length=10, null=True, validators=[django.core.validators.RegexValidator('^[0-9]{10}$', 'Veuillez entrer un numéro à 10 chiffres.')], verbose_name='Numéro de téléphone juré n°1')), + ('mail_j1', models.EmailField(max_length=254, verbose_name='Email juré n°1')), + ('first_name_j2', models.CharField(max_length=255, verbose_name='Prénom juré n°2')), + ('last_name_j2', models.CharField(max_length=255, verbose_name='Nom juré n°2')), + ('phone_j2', models.CharField(help_text='Visible uniquement des administrateurs', max_length=10, null=True, validators=[django.core.validators.RegexValidator('^[0-9]{10}$', 'Veuillez entrer un numéro à 10 chiffres.')], verbose_name='Numéro de téléphone juré n°2')), + ('mail_j2', models.EmailField(max_length=254, verbose_name='Email juré n°2')), + ('admin', models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name="Administrateur de l'école")), ], ), ] diff --git a/users/migrations/0002_schoolprofile_admins.py b/users/migrations/0002_schoolprofile_admins.py deleted file mode 100644 index bbd050c..0000000 --- a/users/migrations/0002_schoolprofile_admins.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 2.0.1 on 2018-03-01 07:16 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('auth', '0009_alter_user_last_name_max_length'), - ('users', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='schoolprofile', - name='admins', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='admin_of', to='auth.Group'), - ), - ] diff --git a/users/migrations/0003_auto_20180301_0933.py b/users/migrations/0003_auto_20180301_0933.py deleted file mode 100644 index 3a6468a..0000000 --- a/users/migrations/0003_auto_20180301_0933.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.0.1 on 2018-03-01 09:33 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_schoolprofile_admins'), - ] - - operations = [ - migrations.AlterField( - model_name='schoolprofile', - name='group', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='school', to='auth.Group'), - ), - ] diff --git a/users/migrations/0004_auto_20180301_0952.py b/users/migrations/0004_auto_20180301_0952.py deleted file mode 100644 index 1055782..0000000 --- a/users/migrations/0004_auto_20180301_0952.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.0.1 on 2018-03-01 09:52 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0003_auto_20180301_0933'), - ] - - operations = [ - migrations.AlterField( - model_name='schoolprofile', - name='group', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='school', to='auth.Group'), - ), - ] diff --git a/users/migrations/0005_auto_20180301_1029.py b/users/migrations/0005_auto_20180301_1029.py deleted file mode 100644 index 7b1b802..0000000 --- a/users/migrations/0005_auto_20180301_1029.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 2.0.1 on 2018-03-01 10:29 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0004_auto_20180301_0952'), - ] - - operations = [ - migrations.AlterField( - model_name='userprofile', - name='school', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.SchoolProfile'), - ), - ] diff --git a/users/migrations/0006_schoolprofile_phone.py b/users/migrations/0006_schoolprofile_phone.py deleted file mode 100644 index d9bd723..0000000 --- a/users/migrations/0006_schoolprofile_phone.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.0.1 on 2018-03-01 23:28 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0005_auto_20180301_1029'), - ] - - operations = [ - migrations.AddField( - model_name='schoolprofile', - name='phone', - field=models.CharField(help_text='Visible uniquement des administrateurs', max_length=10, null=True, verbose_name='Numéro de téléphone pour contacter le responsable des productions'), - ), - ] diff --git a/users/models.py b/users/models.py index 577dfb0..16f50dc 100644 --- a/users/models.py +++ b/users/models.py @@ -7,18 +7,17 @@ from django.dispatch import receiver from django.core import validators -class SchoolProfile(models.Model): +def get_upload_to(instance, filename): + return "static/media/"+instance.name+"/"+filename + + +class School(models.Model): """Ajoute un champ pour distinguer les groupes écoles des autres.""" - group = models.OneToOneField( - Group, - on_delete=models.CASCADE, - related_name="school", - ) - admins = models.OneToOneField( - Group, + admin = models.OneToOneField( + User, + verbose_name="Administrateur de l'école", + null=True, on_delete=models.SET_NULL, - related_name="admin_of", - null=True ) phone = models.CharField( max_length=10, @@ -31,6 +30,53 @@ class SchoolProfile(models.Model): "Veuillez entrer un numéro à 10 chiffres."), ] ) + logo = models.ImageField( + upload_to=get_upload_to, + verbose_name="Logo à utiliser pour représenter l'école", + null=True, + blank=False, + ) + first_name_j1 = models.CharField( + max_length=255, + verbose_name="Prénom juré n°1" + ) + last_name_j1 = models.CharField( + max_length=255, + verbose_name="Nom juré n°1" + ) + phone_j1 = models.CharField( + max_length=10, + help_text="Visible uniquement des administrateurs", + verbose_name="Numéro de téléphone juré n°1", + blank=False, + null=True, + validators=[ + validators.RegexValidator('^[0-9]{10}$', + "Veuillez entrer un numéro à 10 chiffres."), + ] + ) + mail_j1 = models.EmailField(verbose_name="Email juré n°1") + first_name_j2 = models.CharField( + max_length=255, + verbose_name="Prénom juré n°2" + ) + last_name_j2 = models.CharField( + max_length=255, + verbose_name="Nom juré n°2" + ) + phone_j2 = models.CharField( + max_length=10, + help_text="Visible uniquement des administrateurs", + verbose_name="Numéro de téléphone juré n°2", + blank=False, + null=True, + validators=[ + validators.RegexValidator('^[0-9]{10}$', + "Veuillez entrer un numéro à 10 chiffres."), + ] + ) + mail_j2 = models.EmailField(verbose_name="Email juré n°2") + def __str__(self): return self.group.name @@ -41,55 +87,3 @@ class SchoolProfile(models.Model): def number_of_categories(self): return self.content_set.values('category').distinct().count() - def save(self, *args, **kwargs): - viewing_right, _ = Permission.objects.get_or_create( - codename='view_' + str(self.group.pk), - name='Peut voir ' + str(self.group.pk), - content_type=ContentType.objects.get_for_model(SchoolProfile) - ) - if viewing_right not in self.group.permissions.all(): - self.group.permissions.add(viewing_right) - self.group.save() - admins,_ = Group.objects.get_or_create(name='admins') - admins.permissions.add(viewing_right) - super().save(*args, **kwargs) - - -@receiver(post_save, sender=SchoolProfile) -def update_permissions_school(sender, instance, **kwargs): - instance.admins,admin_created = Group.objects.get_or_create(name=str(instance.group.pk)+'_admins') - admin_right,_ = Permission.objects.get_or_create( - codename='manage_' + str(instance.group.pk), - name="Administrateur de l'école " + str(instance.group.pk), - content_type=ContentType.objects.get_for_model(SchoolProfile) - ) - admins,_ = Group.objects.get_or_create(name='admins') - admins.permissions.add(admin_right) - if admin_created: - instance.save(update_fields=['admins']) - instance.admins.permissions.add(admin_right) - instance.admins.save() - - -class UserProfile(models.Model): - """Profil d'un utilisateur""" - school = models.ForeignKey(SchoolProfile, on_delete=models.SET_NULL, null=True) - user = models.OneToOneField(User, on_delete=models.CASCADE) - - -@receiver(post_save, sender=UserProfile) -def update_groups(sender, instance, **kwargs): - instance.user.groups.add(instance.school.group) - - -@receiver(post_save, sender=User) -def update_permission_user(sender, instance, **kwargs): - perm,_ = Permission.objects.get_or_create( - codename='manage_'+str(instance.pk), - name='Peut administrer ' + instance.username, - content_type=ContentType.objects.get_for_model(User) - ) - instance.user_permissions.add(perm) - admins,_ = Group.objects.get_or_create(name='admins') - admins.permissions.add(perm) - diff --git a/users/urls.py b/users/urls.py index d52bfa3..79a06a2 100644 --- a/users/urls.py +++ b/users/urls.py @@ -1,7 +1,6 @@ from django.urls import path from .views import ( CreateUser, - CreateUserProfile, CreateSchool, EditSchoolName, EditSchoolPhone, @@ -37,11 +36,6 @@ urlpatterns = [ PasswordChange.as_view(), name='change-password' ), - path( - 'user//set_school', - CreateUserProfile.as_view(), - name='create-userprofile' - ), path( 'user/', Profile.as_view(), diff --git a/users/views.py b/users/views.py index a939e8f..145b406 100644 --- a/users/views.py +++ b/users/views.py @@ -8,7 +8,7 @@ from django.contrib import messages from django.urls import reverse, reverse_lazy from django.shortcuts import get_object_or_404, redirect -from .models import UserProfile, SchoolProfile +from .models import School from content.models import Content @@ -64,27 +64,9 @@ class Profile(LoginRequiredMixin, UpdateView): ) -class CreateUserProfile(CreateView): - model = UserProfile - fields = ['school'] - template_name = 'edit.html' - - success_url = reverse_lazy('home') - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['title'] = "Choix de l'école" - context['validate'] = "Choisir" - return context - - def form_valid(self, form): - form.instance.user = get_object_or_404(User, pk=self.kwargs['pk']) - return super(CreateUserProfile, self).form_valid(form) - - class CreateSchool(LoginRequiredMixin, PermissionRequiredMixin, CreateView): permission_required = 'users.add_schoolprofile' - model = Group + model = School fields = ['name'] template_name = 'edit.html' success_url = reverse_lazy('settings:index') @@ -97,17 +79,16 @@ class CreateSchool(LoginRequiredMixin, PermissionRequiredMixin, CreateView): def form_valid(self, form): response = super(CreateSchool, self).form_valid(form) - profile = SchoolProfile() + profile = School() profile.group = form.instance profile.save() return response class EditSchoolName(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): - model = Group + model = School fields = ['name'] template_name = 'edit.html' - queryset = Group.objects.filter(school__isnull=False) def get_success_url(self): return reverse('users:edit-school-phone', kwargs={'pk':self.object.school.pk}) @@ -128,7 +109,7 @@ class EditSchoolName(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): class EditSchoolPhone(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): - model = SchoolProfile + model = School fields = ['phone'] template_name = 'edit.html' @@ -148,13 +129,11 @@ class EditSchoolPhone(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): class DeleteSchool(LoginRequiredMixin, PermissionRequiredMixin, DeleteView): model = Group permission_required = 'users.delete_schoolprofile' - queryset = Group.objects.filter(school__isnull=False) class School(LoginRequiredMixin, PermissionRequiredMixin, DetailView): model = Group template_name = "users/school.html" - queryset = Group.objects.filter(school__isnull=False) def get_context_data(self, **kwargs): context = super().get_context_data() From 0303710d2609f1d06ff3d344a6768f61b77a73f2 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Fri, 9 Mar 2018 00:53:38 +0100 Subject: [PATCH 02/10] nouvelles vues pour users --- users/forms.py | 56 +++++ users/models.py | 4 + users/templates/users/school.html | 45 +--- users/urls.py | 80 +++---- users/views.py | 332 ++++++++++++++---------------- 5 files changed, 246 insertions(+), 271 deletions(-) create mode 100644 users/forms.py diff --git a/users/forms.py b/users/forms.py new file mode 100644 index 0000000..8d42501 --- /dev/null +++ b/users/forms.py @@ -0,0 +1,56 @@ +from django import forms +from django.contrib.auth.models import User + +from .models import School + + +class CreateSchool(forms.ModelForm): + class Meta: + model = User + fields = '__all__' + + +class CreateUser(forms.ModelForm): + class Meta: + model = User + fields = '__all__' + + +class EditPhone(forms.ModelForm): + class Meta: + model = School + fields = ['phone'] + + +class EditLogo(forms.ModelForm): + class Meta: + model = School + fields = ['logo'] + + +class EditMail(forms.ModelForm): + class Meta: + model = User + fields = ['email'] + + +class EditJury1(forms.ModelForm): + class Meta: + model = School + fields = [ + 'first_name_j1', + 'last_name_j1', + 'phone_j1', + 'mail_j1' + ] + + +class EditJury2(forms.ModelForm): + class Meta: + model = School + fields = [ + 'first_name_j2', + 'last_name_j2', + 'phone_j2', + 'mail_j2' + ] diff --git a/users/models.py b/users/models.py index 16f50dc..253225c 100644 --- a/users/models.py +++ b/users/models.py @@ -36,6 +36,10 @@ class School(models.Model): null=True, blank=False, ) + validated = models.BooleanField( + verbose_name="Inscription validé.", + default=False + ) first_name_j1 = models.CharField( max_length=255, verbose_name="Prénom juré n°1" diff --git a/users/templates/users/school.html b/users/templates/users/school.html index e76fd7f..1a3de49 100644 --- a/users/templates/users/school.html +++ b/users/templates/users/school.html @@ -2,50 +2,17 @@ {% load bootstrap4 %} {% block content %} -

{{object.name}}

+

{{school.name}}

{% if manager_right in perms %} Numéro de téléphone : -{% if object.school.phone %}{{object.school.phone}} - - - Éditer - +{% if school.phone %}{{school.phone}} {%else%} Non indiqué{%endif%}
{%endif%} -{% if manager_right in perms %} -

Membres

- - - - - - - - - {% for member in members %} - - - - - - - {% endfor %} - -
NomPrénomPseudoAdministrer
{{member.last_name}}{{member.first_name}}{{member.username}} - {% if member in manager_group.user_set.all %} - - - Enlever le privilège Administrateur - - {% else %} - - - Promouvoir administrateur - - {% endif %} -
-{% endif %} + + + Éditer +

Contenus

{% if manager_right in perms %} diff --git a/users/urls.py b/users/urls.py index 79a06a2..2fcf4f3 100644 --- a/users/urls.py +++ b/users/urls.py @@ -1,79 +1,45 @@ -from django.urls import path -from .views import ( - CreateUser, - CreateSchool, - EditSchoolName, - EditSchoolPhone, - DeleteSchool, - Login, - Logout, - PasswordChange, - Profile, - School, - promote_user, - degrade_user -) +from django.urls import path, include +from . import views app_name = 'users' urlpatterns = [ path( 'user/new', - CreateUser.as_view(), + views.create_user, name='new-user' ), path( - 'login', - Login.as_view(), - name='login' - ), - path( - 'logout', - Logout.as_view(), - name='logout', - ), - path( - 'change_password', - PasswordChange.as_view(), - name='change-password' - ), - path( - 'user/', - Profile.as_view(), - name='profile', + 'user/', + include('django.contrib.auth.urls') ), path( 'school/new', - CreateSchool.as_view(), + views.create_school, name='new-school' ), path( 'school/', - School.as_view(), - name='school' - ), - path( - 'school//degrade/', - degrade_user, - name='degrade-user' - ), - path( - 'school//promote/', - promote_user, - name='promote-user' - ), - path( - 'school//edit_name', - EditSchoolName.as_view(), - name='edit-school-name' - ), + views.school, + name='school', + ) path( 'school//edit_phone', - EditSchoolPhone.as_view(), + views.edit_phone, name='edit-school-phone' ), path( - 'school//delete', - DeleteSchool.as_view(), - name='delete-school' + 'school//edit_mail', + views.edit_mail, + name='edit-school-mail' + ), + path( + 'school//jury_1', + views.edit_jury_1, + name='edit-jury-1' + ), + path( + 'school//jury_2', + views.edit_jury_2, + name='edit-jury-2' ), ] diff --git a/users/views.py b/users/views.py index 145b406..ffe6d23 100644 --- a/users/views.py +++ b/users/views.py @@ -1,199 +1,181 @@ -from django.contrib.auth.models import User, Group -from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin -from django.views.generic import CreateView, UpdateView, DeleteView, DetailView -from django.contrib.auth.views import LoginView, LogoutView, PasswordChangeView, login_required -from django.contrib.auth.hashers import make_password -from django.contrib.messages.views import SuccessMessageMixin from django.contrib import messages -from django.urls import reverse, reverse_lazy -from django.shortcuts import get_object_or_404, redirect +from django.urls import reverse +from django.shortcuts import get_object_or_404, redirect, render +from django.contrib.admin.views.decorators import staff_member_required + +from content.models import Category from .models import School -from content.models import Content +from . import forms -class CreateUser(CreateView): - model = User - fields = [ - 'first_name', - 'last_name', - 'email', - 'username', - 'password', - ] - template_name = 'edit.html' - - def get_success_url(self): - return reverse( - 'users:create-userprofile', - kwargs={'pk': self.object.pk} - ) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['title'] = "Inscription" - context['validate'] = "S'inscrire" - return context - - def form_valid(self, form): - r = super().form_valid(form) - self.object.set_password(form.cleaned_data['password']) - self.object.save() - return r - -class Profile(LoginRequiredMixin, UpdateView): - model = User - template_name = 'users/profile.html' - fields = [ - 'username', - 'first_name', - 'last_name', - 'email' - ] - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['title'] = self.object.username - context['validate'] = "Modifier" - return context - - def get_success_url(self): - return reverse( - 'users:profile', - kwargs={'pk': self.object.pk} - ) +@staff_member_required +def create_user(request): + user_form = forms.CreateUser(request.POST or None) + if user_form.is_valid(): + u = user_form.save() + messages.success(request, "L'utilisateur {} {} a bien été créé.".format( + u.first_name, u.last_name)) + return redirect(reverse('settings:index')) + return render(request, 'edit.html', { + 'form': user_form, + 'title': "Création d'un utilisateur", + 'validate': "Créer" + }) -class CreateSchool(LoginRequiredMixin, PermissionRequiredMixin, CreateView): - permission_required = 'users.add_schoolprofile' - model = School - fields = ['name'] - template_name = 'edit.html' - success_url = reverse_lazy('settings:index') - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['title'] = "Création de l'école" - context['validate'] = "Créer" - return context - - def form_valid(self, form): - response = super(CreateSchool, self).form_valid(form) - profile = School() - profile.group = form.instance - profile.save() - return response +@staff_member_required +def create_school(request): + school_form = forms.CreateSchool(request.POST or None) + if school_form.is_valid(): + s = school_form.save() + messages.success(request, "L'école {} a bien été créée.".format(s.name)) + return redirect(redirect('settings:index')) + return render(request, 'edit.html', { + 'form': school_form, + 'title': "Création d'une école", + 'validate': "Créer" + }) -class EditSchoolName(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): - model = School - fields = ['name'] - template_name = 'edit.html' - - def get_success_url(self): - return reverse('users:edit-school-phone', kwargs={'pk':self.object.school.pk}) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['title'] = "Édition de l'école" - context['validate'] = "Modifier" - return context - - def has_permission(self): - return self.request.user.has_perm('users.manage_'+str(self.kwargs['pk'])) - - def form_valid(self, *args, **kwargs): - r = super().form_valid(*args, **kwargs) - self.object.school.save() - return r +def school(request, pk): + school = get_object_or_404(School, pk=pk) + can = request.user.is_staff or request.user == school.admin + if not can: + messages.error(request, 'Vous ne pouvez pas accéder à cette page') + return redirect(reverse('home')) + return render(request, 'users/school.html', {'school':school}) -class EditSchoolPhone(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): - model = School - fields = ['phone'] - template_name = 'edit.html' - - def get_success_url(self): - return reverse('users:school', kwargs={'pk':self.object.group.pk}) - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context['title'] = "Édition de l'école" - context['validate'] = "Modifier" - return context - - def has_permission(self): - return self.request.user.has_perm('users.manage_'+str(self.kwargs['pk'])) +def edit_phone(request, pk): + school = get_object_or_404(School, pk=pk) + can = request.user.is_staff or request.user == school.admin + if not can: + messages.error(request, 'Vous ne pouvez pas accéder à cette page') + return redirect(reverse('settings:index')) + school_form = forms.EditPhone(request.POST or None, instance=school) + if school_form.is_valid(): + s = school_form.save() + messages.success(request, "L'école {} a bien été modifiée.".format(s.name)) + return redirect(redirect('settings:index')) + return render(request, 'edit.html', { + 'form': school_form, + 'title': "Édition du numéro de téléphone", + 'validate': "Modifier" + }) -class DeleteSchool(LoginRequiredMixin, PermissionRequiredMixin, DeleteView): - model = Group - permission_required = 'users.delete_schoolprofile' +def edit_logo(request, pk): + school = get_object_or_404(School, pk=pk) + can = request.user.is_staff or request.user == school.admin + if not can: + messages.error(request, 'Vous ne pouvez pas accéder à cette page') + return redirect(reverse('settings:index')) + school_form = forms.EditLogo(request.POST or None, instance=school) + if school_form.is_valid(): + s = school_form.save() + messages.success(request, "L'école {} a bien été modifiée.".format(s.name)) + return redirect(redirect('settings:index')) + return render(request, 'edit.html', { + 'form': school_form, + 'title': "Édition du logo", + 'validate': "Modifier" + }) -class School(LoginRequiredMixin, PermissionRequiredMixin, DetailView): - model = Group - template_name = "users/school.html" - - def get_context_data(self, **kwargs): - context = super().get_context_data() - context['contents'] = Content.objects.filter(school_owner=self.object.school) - context['school'] = True - context['members'] = User.objects.filter(userprofile__school=self.object.school) - context['manager_right'] = 'users.manage_' + str(self.object.pk) - context['manager_group'],_ = Group.objects.get_or_create(name=str(self.object.pk)+'_admins') - return context - - def has_permission(self): - return self.request.user.has_perm('users.view_'+str(self.kwargs['pk'])) +def edit_mail(request, pk): + school = get_object_or_404(School, pk=pk) + can = request.user.is_staff or request.user == school.admin + if not can: + messages.error(request, 'Vous ne pouvez pas accéder à cette page') + return redirect(reverse('settings:index')) + user_form = forms.EditMail(request.POST or None, instance=school.admin) + if user_form.is_valid(): + s = user_form.save() + messages.success(request, "L'école {} a bien été modifiée.".format(s.name)) + return redirect(redirect('settings:index')) + return render(request, 'edit.html', { + 'form': user_form, + 'title': "Édition du numéro du mail", + 'validate': "Modifier" + }) -class Logout(SuccessMessageMixin, LogoutView): - success_message = "Vous vous êtes bien déconnecté." +def edit_jury_1(request, pk): + school = get_object_or_404(School, pk=pk) + can = request.user.is_staff or request.user == school.admin + if not can: + messages.error(request, 'Vous ne pouvez pas accéder à cette page') + return redirect(reverse('settings:index')) + school_form = forms.EditJury1(request.POST or None, instance=school) + if school_form.is_valid(): + s = school_form.save() + messages.success(request, "L'école {} a bien été modifiée.".format(s.name)) + return redirect(redirect('settings:index')) + return render(request, 'edit.html', { + 'form': school_form, + 'title': "Édition du jury 1", + 'validate': "Modifier" + }) -class Login(SuccessMessageMixin, LoginView): - template_name = "edit.html" - success_message = "Bienvenue !" - extra_context = { - 'title' : "Connexion", - 'validate' : "Se connecter", - } +def edit_jury_2(request, pk): + school = get_object_or_404(School, pk=pk) + can = request.user.is_staff or request.user == school.admin + if not can: + messages.error(request, 'Vous ne pouvez pas accéder à cette page') + return redirect(reverse('settings:index')) + school_form = forms.EditJury2(request.POST or None, instance=school) + if school_form.is_valid(): + s = school_form.save() + messages.success(request, "L'école {} a bien été modifiée.".format(s.name)) + return redirect(redirect('settings:index')) + return render(request, 'edit.html', { + 'form': school_form, + 'title': "Édition du jury 2", + 'validate': "Modifier" + }) -class PasswordChange(SuccessMessageMixin, PasswordChangeView): - template_name = "edit.html" - success_url = reverse_lazy("home") - success_message = "Le mot de passe a été changé." - extra_context = { - 'title' : "Changer le mot de passe", - 'validate' : "Changer", - } +def validate(request, pk): + school = get_object_or_404(School, pk=pk) + can = request.user.is_staff or request.user == school.admin + if not can: + messages.error(request, 'Vous ne pouvez pas accéder à cette page') + return redirect(reverse('settings:index')) + jury_1_ok = any([ + school.first_name_j1 is not None, + school.last_name_j1 is not None, + school.phone_j1 is not None, + school.mail_j1 is not None + ]) + jury_2_ok = any([ + school.first_name_j2 is not None, + school.last_name_j2 is not None, + school.phone_j2 is not None, + school.mail_j2 is not None + ]) + logo_ok = school.logo is not None + phone_ok = school.phone is not None + mail_ok = school.admin.email is not None + if not jury_1_ok: + messages.warning(request, 'Pas de jury n°1 défini.') + if not jury_2_ok: + messages.warning(request, 'Pas de jury n°2 défini.') + if not logo_ok: + messages.warning(request, 'Pas de logo défini.') + if not phone_ok: + messages.error(request, 'Pas de téléphone défini.') + if not mail_ok: + messages.error(request, 'Pas de mail défini.') + for category in Category.objects.all(): + if not category.content_set.filter(school_owner=school): + messages.warning(request, 'Pas de contenu dans la catégorie {}.'.format(category.name)) -@login_required -def promote_user(request, school_pk, user_pk): - school = get_object_or_404(Group, pk=school_pk) - user = get_object_or_404(User, pk=user_pk) - if request.user.has_perm('manage_'+str(school.pk)): - admins,_ = Group.objects.get_or_create(name=str(school.pk)+'_admins') - user.groups.add(admins) - user.save() - messages.success(request, user.username + ' a été ajouté aux administrateurs de ' + school.name) - return redirect(reverse('users:school', kwargs={'pk':school.pk})) - messages.error(request, "Vous n'aves pas ce droit.") - return redirect('home') + if phone_ok and mail_ok: + school.validated = True + school.save() + messages.success(request, 'Inscription validée.') - -@login_required -def degrade_user(request, school_pk, user_pk): - school = get_object_or_404(Group, pk=school_pk) - user = get_object_or_404(User, pk=user_pk) - if request.user.has_perm('manage_'+str(school.pk)): - admins,_ = Group.objects.get_or_create(name=str(school.pk)+'_admins') - user.groups.remove(admins) - user.save() - messages.success(request, user.username + ' a été enlevé des administrateurs de ' + school.name) - return redirect(reverse('users:school', kwargs={'pk':school.pk})) - messages.error(request, "Vous n'aves pas ce droit.") - return redirect('home') + return redirect(reverse('settings:index')) From c606570a99ca2da65a03c2747486bd8694d15d7d Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Fri, 9 Mar 2018 11:44:49 +0100 Subject: [PATCH 03/10] =?UTF-8?q?Vues=20d'affichage=20et=20d'=C3=A9dition?= =?UTF-8?q?=20pour=20les=20nouveaux=20mod=C3=A8les?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/migrations/0002_auto_20180309_1116.py | 23 +++ content/models.py | 8 +- content/templates/content/content.html | 4 +- content/templates/content/content_list.html | 8 +- content/urls.py | 14 +- content/views.py | 19 +-- settings/templates/settings/settings.html | 32 ++-- settings/views.py | 14 +- templates/nav_bar.html | 7 +- users/admin.py | 6 + users/forms.py | 10 +- users/migrations/0002_school_validated.py | 18 +++ users/migrations/0003_school_name.py | 18 +++ users/models.py | 9 +- users/templates/users/school.html | 151 ++++++++++++++++-- users/urls.py | 12 +- users/views.py | 68 +++++--- 17 files changed, 319 insertions(+), 102 deletions(-) create mode 100644 content/migrations/0002_auto_20180309_1116.py create mode 100644 users/migrations/0002_school_validated.py create mode 100644 users/migrations/0003_school_name.py diff --git a/content/migrations/0002_auto_20180309_1116.py b/content/migrations/0002_auto_20180309_1116.py new file mode 100644 index 0000000..392f4dd --- /dev/null +++ b/content/migrations/0002_auto_20180309_1116.py @@ -0,0 +1,23 @@ +# Generated by Django 2.0.1 on 2018-03-09 10:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='category', + name='description_short', + field=models.TextField(null=True, verbose_name='Description courte'), + ), + migrations.AlterField( + model_name='category', + name='description', + field=models.TextField(default='', verbose_name='Description de la catégorie'), + ), + ] diff --git a/content/models.py b/content/models.py index 9597d81..256b91f 100644 --- a/content/models.py +++ b/content/models.py @@ -13,8 +13,12 @@ class Category(models.Model): max_length=255, verbose_name="Nom de la catégorie" ) + description_short = models.TextField( + verbose_name="Description courte", + null=True, + ) description = models.TextField( - verbose_name="Descriton de la catégorie", + verbose_name="Description de la catégorie", default="" ) image = models.ImageField( @@ -23,7 +27,7 @@ class Category(models.Model): ) def get_absolute_url(self): - return reverse('content:category-list', kwargs={'pk': self.pk}) + return reverse('content:category', kwargs={'pk': self.pk}) def __str__(self): return self.name diff --git a/content/templates/content/content.html b/content/templates/content/content.html index 3785644..21d579d 100644 --- a/content/templates/content/content.html +++ b/content/templates/content/content.html @@ -5,15 +5,13 @@ diff --git a/content/templates/content/content_list.html b/content/templates/content/content_list.html index d6fb175..cc56d5b 100644 --- a/content/templates/content/content_list.html +++ b/content/templates/content/content_list.html @@ -22,15 +22,13 @@ $('html, body').animate({scrollTop: $('#category-content').offset().top}, 800);

{{category.name}}

-

{{category.description}}

+

{{category.description_short}}

Aller voir !

-
- {% for content in contents %} - {% include "content/content.html" %} - {% endfor %} +
+ {{category.description|safe}}


diff --git a/content/urls.py b/content/urls.py index ab53c2a..2ae991c 100644 --- a/content/urls.py +++ b/content/urls.py @@ -1,8 +1,8 @@ from django.urls import path from .views import ( - ContentCategoryList, CreateCategory, + ViewCategory, DeleteCategory, EditCategory, CreateContent, @@ -12,11 +12,6 @@ from .views import ( app_name = 'content' urlpatterns = [ - path( - 'category//', - ContentCategoryList.as_view(), - name='category-list' - ), path( 'category/delete/', DeleteCategory.as_view(), @@ -28,7 +23,12 @@ urlpatterns = [ name='category-new' ), path( - 'category/edit/', + 'category/', + ViewCategory.as_view(), + name='category', + ), + path( + 'category//edit', EditCategory.as_view(), name='category-edit', ), diff --git a/content/views.py b/content/views.py index 0548aef..6cee7dd 100644 --- a/content/views.py +++ b/content/views.py @@ -8,24 +8,11 @@ from .models import Content, Category from settings.models import SiteSettings -class ContentCategoryList(generic.ListView): - """Affiche les contenus d'une catégorie.""" - model = Content - context_object_name = "contents" +class ViewCategory(generic.DetailView): + """Affiche une catégorie.""" + model = Category template_name = "content/content_list.html" - def get_queryset(self): - pk = self.kwargs['pk'] - category = get_object_or_404(Category, pk=pk) - return Content.objects.filter(category=category) - - def get_context_data(self, **kwargs): - context = super(generic.ListView, self).get_context_data(**kwargs) - pk = self.kwargs['pk'] - category = get_object_or_404(Category, pk=pk) - context['category'] = category - return context - class CreateCategory(PermissionRequiredMixin, generic.CreateView): """Création de catégorie.""" diff --git a/settings/templates/settings/settings.html b/settings/templates/settings/settings.html index 4c24c22..06e86d0 100644 --- a/settings/templates/settings/settings.html +++ b/settings/templates/settings/settings.html @@ -24,7 +24,7 @@ {{admin.last_name}} {{admin.username}} - + Enlever le privilège Administrateur @@ -76,26 +76,28 @@ - - + {% for school in schools %} - - + - {% endfor %} @@ -142,9 +144,5 @@ {% endif %} - - - -
NomNombre de membres Nombre de contenus Nombre de catégories Numéro de téléphoneInscription
{{school.group.name}}{{school.group.user_set.count}}{{school.name}} {{school.content_set.count}} {{school.number_of_categories}} {{school.phone}} - - Éditer - - - - Supprimer - + + {% if school.validated %} + + + Inscription validée + + {% else %} + + + Inscription non validée + + {% endif %}
Nombre minimal de catégories{{ site_settings.min_number_of_categories }}
{% endblock %} diff --git a/settings/views.py b/settings/views.py index 6fdfd7c..ab09c6a 100644 --- a/settings/views.py +++ b/settings/views.py @@ -1,7 +1,7 @@ from django.views.generic import TemplateView, UpdateView from django.urls import reverse_lazy, reverse from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin -from django.contrib.auth.decorators import permission_required +from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth.models import Group, User from django.shortcuts import get_object_or_404, redirect, render from django.contrib import messages @@ -22,7 +22,7 @@ class SettingsView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView): context['site_settings'], _ = SiteSettings.objects.get_or_create() context['schools'] = School.objects.all() context['settings'] = True - context['administrators'] = Group.objects.get(name='admins').user_set.all() + context['administrators'] = User.objects.filter(is_staff=True) return context class EditSiteSettingsView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): @@ -42,24 +42,22 @@ class EditSiteSettingsView(LoginRequiredMixin, PermissionRequiredMixin, UpdateVi return context -@permission_required('auth.change_user') +@staff_member_required def degrade_user(request, pk): user = get_object_or_404(User, pk=pk) - admins,_ = Group.objects.get_or_create(name='admins') - user.groups.remove(admins) + user.is_staff = False user.save() messages.success(request, user.username + ' a été enlevé des administrateurs du site') return redirect(reverse('settings:index')) -@permission_required('auth.change_user') +@staff_member_required def promote_user(request): user_form = SelectUserForm(request.POST or None) user_form.populate() if user_form.is_valid(): user=user_form.get_user() - admins,_ = Group.objects.get_or_create(name='admins') - user.groups.add(admins) + user.is_staff = True user.save() messages.success(request, user.username + ' a été ajouté des administrateurs du site') return redirect(reverse('settings:index')) diff --git a/templates/nav_bar.html b/templates/nav_bar.html index 424cd60..8461033 100644 --- a/templates/nav_bar.html +++ b/templates/nav_bar.html @@ -17,14 +17,14 @@ {% for c in categories %} {% endfor %} diff --git a/users/templates/users/password_reset_mail.html b/users/templates/users/password_reset_mail.html new file mode 100644 index 0000000..3c51d46 --- /dev/null +++ b/users/templates/users/password_reset_mail.html @@ -0,0 +1,14 @@ +{% load i18n %}{% autoescape off %} +{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %} + +{% trans "Please go to the following page and choose a new password:" %} +{% block reset_link %} +{{ protocol }}://festart.rezometz.org{% url 'users:password-reset-confirm' uidb64=uid token=token %} +{% endblock %} +{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }} + +{% trans "Thanks for using our site!" %} + +{% blocktrans %}The {{ site_name }} team{% endblocktrans %} + +{% endautoescape %} diff --git a/users/templates/users/school.html b/users/templates/users/school.html index 6d10b98..f94f4ae 100644 --- a/users/templates/users/school.html +++ b/users/templates/users/school.html @@ -11,6 +11,10 @@ Inscription validée

{{school.name}}

+ + + Changer mon mot de passe + Éditer diff --git a/users/templates/users/welcome_user.txt b/users/templates/users/welcome_user.txt new file mode 100644 index 0000000..3313877 --- /dev/null +++ b/users/templates/users/welcome_user.txt @@ -0,0 +1,14 @@ +Bienvenue sur le site d'Il était une fois dans l'Est. + +Vous recevez cet email car vous avez été désigné responsable des productions +vidéos pour votre école. + +Votre identifiant est : {{id}} + +Rendez-vous ici : http://festart.rezometz.org/users/reset pour réinitialiser +votre mot de passe (en utilisant cette adresse email). + +Vous pouvez retrouver l'ensemble des informations sur l'évènement ici : +http://festart.rezometz.org + +L'équipe de Il était une fois dans l'Est. diff --git a/users/urls.py b/users/urls.py index f29190f..30e307e 100644 --- a/users/urls.py +++ b/users/urls.py @@ -1,4 +1,5 @@ from django.urls import path +from django.urls import reverse_lazy from django.contrib.auth import views as auth_views from . import views @@ -26,17 +27,22 @@ urlpatterns = [ ), path( 'password_change/done', - auth_views.PasswordChangeDoneView.as_view(template_name="base.html"), + views.PasswordChangeDoneView.as_view(), name='password-change-done' ), + path( + 'reset', + views.PasswordResetView.as_view(), + name='password-reset' + ), path( 'reset///', - auth_views.PasswordResetConfirmView.as_view(template_name="edit.html"), + auth_views.PasswordResetConfirmView.as_view(template_name="edit.html", success_url=reverse_lazy('users:password-reset-done')), name='password-reset-confirm' ), path( 'reset/done/', - auth_views.PasswordResetCompleteView.as_view(template_name="base.html"), + views.PasswordResetCompleteView.as_view(), name='password-reset-done' ), path( diff --git a/users/views.py b/users/views.py index 3162735..5dea366 100644 --- a/users/views.py +++ b/users/views.py @@ -1,7 +1,10 @@ from django.contrib import messages -from django.urls import reverse +from django.urls import reverse, reverse_lazy +from django.core.mail import send_mail from django.shortcuts import get_object_or_404, redirect, render from django.contrib.admin.views.decorators import staff_member_required +from django.template.loader import render_to_string +from django.contrib.auth import views as auth_views from settings.forms import SelectUserForm from content.models import Category @@ -15,7 +18,14 @@ def create_user(request): user_form = forms.CreateUser(request.POST or None) if user_form.is_valid(): u = user_form.save() - messages.success(request, "L'utilisateur {} {} a bien été créé.".format( + send_mail( + "Bienvenue sur Il était une fois dans l'Est.", + render_to_string("users/welcome_user.txt", {'id':u.username}), + "noreply.festart@rezometz.org", + [u.email], + fail_silently=False + ) + messages.success(request, "L'utilisateur {} {} a bien été créé un mail lui a été envoyé pour réinitialiser son mot de passe.".format( u.first_name, u.last_name)) return redirect(reverse('settings:index')) return render(request, 'edit.html', { @@ -226,3 +236,31 @@ def validate(request, pk): messages.success(request, 'Inscription validée.') return redirect(school.get_absolute_url()) + + +class PasswordChangeDoneView(auth_views.PasswordChangeDoneView): + template_name = "home.html" + + def dispatch(self, *args, **kwargs): + r = super().dispatch(*args, **kwargs) + messages.success(self.request, "Le mot de passe a été changé.") + return r + + +class PasswordResetView(auth_views.PasswordResetView): + template_name = "edit.html" + success_url = reverse_lazy('home') + email_template_name = "users/password_reset_mail.html" + + def form_valid(self, form): + messages.success(self.request, "Un mail pour le changement de mot de passe a été envoyé.") + return super().form_valid(form) + + +class PasswordResetCompleteView(auth_views.PasswordResetCompleteView): + template_name = "home.html" + + def dispatch(self, *args, **kwargs): + r = super().dispatch(*args, **kwargs) + messages.success(self.request, "Votre mot de passe a été réinitialisé.") + return r From 0f25a87bf6d37338b2f6dbe4c352a0feab28409b Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Sun, 11 Mar 2018 23:25:59 +0100 Subject: [PATCH 10/10] Pages statiques --- settings/templates/settings/settings.html | 27 ++++++++ settings/templates/settings/static_page.html | 5 ++ settings/templatetags/load_settings.py | 13 +++- settings/urls.py | 23 ++++++- settings/views.py | 66 +++++++++++++++++++- templates/nav_bar.html | 7 +++ 6 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 settings/templates/settings/static_page.html diff --git a/settings/templates/settings/settings.html b/settings/templates/settings/settings.html index 9f99ea0..fe9cd93 100644 --- a/settings/templates/settings/settings.html +++ b/settings/templates/settings/settings.html @@ -65,6 +65,33 @@ {% endfor %} +

Pages statiques

+
+ + Créer une nouvelle page statique + +
+
+ + + + + +{% for p in static_pages %} + + + + +{% endfor %} +
Nom
{{p.name}} + + Éditer + + + + Supprimer + +

Écoles

diff --git a/settings/templates/settings/static_page.html b/settings/templates/settings/static_page.html new file mode 100644 index 0000000..f81fe10 --- /dev/null +++ b/settings/templates/settings/static_page.html @@ -0,0 +1,5 @@ +{% extends "base.html" %} +{% block content %} +

{{object.name}}

+{{object.text|safe}} +{% endblock %} diff --git a/settings/templatetags/load_settings.py b/settings/templatetags/load_settings.py index e45c9b1..a1f1f6a 100644 --- a/settings/templatetags/load_settings.py +++ b/settings/templatetags/load_settings.py @@ -1,5 +1,5 @@ from django import template -from settings.models import SiteSettings +from settings.models import SiteSettings, StaticPage register = template.Library() @@ -9,7 +9,18 @@ def load_site_settings(parser, token): return LoadSiteSettingsNode() +@register.tag('load_static_pages') +def load_static_pages(parser, token): + return LoadStaticPagesNode() + + class LoadSiteSettingsNode(template.Node): def render(self, context): context['site_settings'] = SiteSettings.get_settings() return '' + + +class LoadStaticPagesNode(template.Node): + def render(self, context): + context['static_pages'] = StaticPage.objects.all() + return '' diff --git a/settings/urls.py b/settings/urls.py index 9293762..c21ba79 100644 --- a/settings/urls.py +++ b/settings/urls.py @@ -1,5 +1,5 @@ from django.urls import path -from .views import SettingsView, EditSiteSettingsView, degrade_user, promote_user +from .views import SettingsView, EditSiteSettingsView, degrade_user, promote_user, CreateStaticPageView, StaticPageView, DeleteStaticPageView, EditStaticPageView app_name = 'settings' urlpatterns = [ @@ -22,6 +22,25 @@ urlpatterns = [ 'promote_user', promote_user, name='promote-user', + ), + path( + 'static_page/new', + CreateStaticPageView.as_view(), + name='staticpage-new' + ), + path( + 'static_page/', + StaticPageView.as_view(), + name='staticpage' + ), + path( + 'static_page//delete', + DeleteStaticPageView.as_view(), + name='staticpage-delete' + ), + path( + 'static_page//edit', + EditStaticPageView.as_view(), + name='staticpage-edit' ) - ] diff --git a/settings/views.py b/settings/views.py index ab09c6a..7ce5dab 100644 --- a/settings/views.py +++ b/settings/views.py @@ -1,4 +1,4 @@ -from django.views.generic import TemplateView, UpdateView +from django.views.generic import TemplateView, UpdateView, CreateView, DetailView, DeleteView from django.urls import reverse_lazy, reverse from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin from django.contrib.admin.views.decorators import staff_member_required @@ -8,7 +8,7 @@ from django.contrib import messages from content.models import Category from users.models import School -from .models import SiteSettings +from .models import SiteSettings, StaticPage from .forms import SelectUserForm @@ -23,8 +23,10 @@ class SettingsView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView): context['schools'] = School.objects.all() context['settings'] = True context['administrators'] = User.objects.filter(is_staff=True) + context['static_pages'] = StaticPage.objects.all() return context + class EditSiteSettingsView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView): template_name = "edit.html" model = SiteSettings @@ -42,6 +44,66 @@ class EditSiteSettingsView(LoginRequiredMixin, PermissionRequiredMixin, UpdateVi return context +class CreateStaticPageView(LoginRequiredMixin, CreateView): + template_name = "edit.html" + model = StaticPage + fields = '__all__' + success_url = reverse_lazy('settings:index') + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["title"] = "Création de page statique" + context["validate"] = "Créer" + return context + + @classmethod + def as_view(self, *args, **kwargs): + view = super().as_view(*args, **kwargs) + return staff_member_required(view) + + +class StaticPageView(DetailView): + template_name = "settings/static_page.html" + model = StaticPage + fields = '__all__' + @classmethod + def as_view(self, *args, **kwargs): + view = super().as_view(*args, **kwargs) + return staff_member_required(view) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['page'] = self.object + return context + + +class DeleteStaticPageView(DeleteView): + template_name = "confirm_delete.html" + model = StaticPage + success_url = reverse_lazy('settings:index') + @classmethod + def as_view(self, *args, **kwargs): + view = super().as_view(*args, **kwargs) + return staff_member_required(view) + + +class EditStaticPageView(UpdateView): + template_name = "edit.html" + model = StaticPage + success_url = reverse_lazy('settings:index') + fields = '__all__' + @classmethod + def as_view(self, *args, **kwargs): + view = super().as_view(*args, **kwargs) + return staff_member_required(view) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["title"] = "Édition de page statique" + context["validate"] = "Éditer" + return context + + @staff_member_required def degrade_user(request, pk): user = get_object_or_404(User, pk=pk) diff --git a/templates/nav_bar.html b/templates/nav_bar.html index f48ddd9..215eae3 100644 --- a/templates/nav_bar.html +++ b/templates/nav_bar.html @@ -2,6 +2,7 @@ {% load load_settings %} {% load_categories %} {% load_site_settings %} +{% load_static_pages %}