Nouvelle orientation du projet, redéfinition des structures de données.

This commit is contained in:
Hugo LEVY-FALK 2018-03-08 23:16:03 +01:00
parent be45b37ed4
commit b5a51e1bec
19 changed files with 141 additions and 350 deletions

View file

@ -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')),
],
),
]

View file

@ -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'),
),
]

View file

@ -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)

View file

@ -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')),
],
),
]

View file

@ -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'),
),
]

View file

@ -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'),
),
]

View file

@ -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"
)

View file

@ -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

View file

@ -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()

View file

@ -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)

View file

@ -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")),
],
),
]

View file

@ -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'),
),
]

View file

@ -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'),
),
]

View file

@ -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'),
),
]

View file

@ -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'),
),
]

View file

@ -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'),
),
]

View file

@ -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)

View file

@ -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/<int:pk>/set_school',
CreateUserProfile.as_view(),
name='create-userprofile'
),
path(
'user/<int:pk>',
Profile.as_view(),

View file

@ -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()