Merge branch 'master' of https://gitlab.rezometz.org/klafyvel/site_tps
This commit is contained in:
commit
7404de04e3
46 changed files with 1150 additions and 747 deletions
30
content/forms.py
Normal file
30
content/forms.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
from .models import Content, Category
|
||||||
|
|
||||||
|
|
||||||
|
class CreateContent(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Content
|
||||||
|
fields = [
|
||||||
|
'name',
|
||||||
|
'category',
|
||||||
|
'file',
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, school, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.instance.school = school
|
||||||
|
|
||||||
|
already_created = map(lambda x:x.category.pk, school.content_set.select_related('category'))
|
||||||
|
self.fields['category'].queryset = Category.objects.exclude(pk__in=already_created)
|
||||||
|
|
||||||
|
|
||||||
|
class ContentEdit(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Content
|
||||||
|
fields = [
|
||||||
|
'name',
|
||||||
|
'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
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
@ -9,6 +10,7 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
('users', '0001_initial'),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
@ -26,8 +28,9 @@ class Migration(migrations.Migration):
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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')),
|
('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')),
|
('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')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
23
content/migrations/0002_auto_20180309_1116.py
Normal file
23
content/migrations/0002_auto_20180309_1116.py
Normal file
|
@ -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'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
19
content/migrations/0003_auto_20180309_1233.py
Normal file
19
content/migrations/0003_auto_20180309_1233.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.0.1 on 2018-03-09 11:33
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('content', '0002_auto_20180309_1116'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='content',
|
||||||
|
name='school_owner',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='users.School'),
|
||||||
|
),
|
||||||
|
]
|
19
content/migrations/0004_auto_20180309_1235.py
Normal file
19
content/migrations/0004_auto_20180309_1235.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.0.1 on 2018-03-09 11:35
|
||||||
|
|
||||||
|
import content.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('content', '0003_auto_20180309_1233'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='content',
|
||||||
|
name='file',
|
||||||
|
field=models.FileField(upload_to=content.models.get_upload_to, verbose_name='Fichier'),
|
||||||
|
),
|
||||||
|
]
|
18
content/migrations/0005_auto_20180309_1255.py
Normal file
18
content/migrations/0005_auto_20180309_1255.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.0.1 on 2018-03-09 11:55
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('content', '0004_auto_20180309_1235'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='content',
|
||||||
|
name='file',
|
||||||
|
field=models.FileField(upload_to='', verbose_name='Fichier'),
|
||||||
|
),
|
||||||
|
]
|
19
content/migrations/0006_auto_20180309_1257.py
Normal file
19
content/migrations/0006_auto_20180309_1257.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.0.1 on 2018-03-09 11:57
|
||||||
|
|
||||||
|
import content.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('content', '0005_auto_20180309_1255'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='content',
|
||||||
|
name='file',
|
||||||
|
field=models.FileField(upload_to=content.models.get_upload_to, verbose_name='Fichier'),
|
||||||
|
),
|
||||||
|
]
|
25
content/migrations/0007_auto_20180309_1315.py
Normal file
25
content/migrations/0007_auto_20180309_1315.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 2.0.1 on 2018-03-09 12:15
|
||||||
|
|
||||||
|
import content.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('content', '0006_auto_20180309_1257'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='content',
|
||||||
|
name='file',
|
||||||
|
field=models.FileField(upload_to=content.models.get_upload_to, validators=[content.models.validate_file_extension], verbose_name='Fichier'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='content',
|
||||||
|
name='school_owner',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.School'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,9 +1,11 @@
|
||||||
from django.db import models
|
import os
|
||||||
from django.urls import reverse
|
|
||||||
from django.contrib.auth.models import Group
|
from django.db import models
|
||||||
from django.conf import settings
|
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):
|
class Category(models.Model):
|
||||||
"""Une catégorie de contenu."""
|
"""Une catégorie de contenu."""
|
||||||
|
@ -11,21 +13,40 @@ class Category(models.Model):
|
||||||
max_length=255,
|
max_length=255,
|
||||||
verbose_name="Nom de la catégorie"
|
verbose_name="Nom de la catégorie"
|
||||||
)
|
)
|
||||||
|
description_short = models.TextField(
|
||||||
|
verbose_name="Description courte",
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
description = models.TextField(
|
description = models.TextField(
|
||||||
verbose_name="Descriton de la catégorie",
|
verbose_name="Description de la catégorie",
|
||||||
default=""
|
default=""
|
||||||
)
|
)
|
||||||
image = models.ImageField(
|
image = models.ImageField(
|
||||||
verbose_name="Illustration de la catégorie",
|
verbose_name="Illustration de la catégorie",
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
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):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
def get_upload_to(instance, filename):
|
||||||
|
extension = filename.split('.')[-1]
|
||||||
|
proper_school = ''.join(e for e in instance.school_owner.name if e.isalnum() and ord(e)<128)
|
||||||
|
proper_name = ''.join(e for e in instance.category.name if e.isalnum() and ord(e)<128)
|
||||||
|
return "static/media/"+proper_school+"/"+proper_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'Format non supporté : {}'.format(ext))
|
||||||
|
|
||||||
|
|
||||||
class Content(models.Model):
|
class Content(models.Model):
|
||||||
"""Un contenu du site (vidéo)."""
|
"""Un contenu du site (vidéo)."""
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
|
@ -33,7 +54,7 @@ class Content(models.Model):
|
||||||
verbose_name="Nom du contenu"
|
verbose_name="Nom du contenu"
|
||||||
)
|
)
|
||||||
school_owner = models.ForeignKey(
|
school_owner = models.ForeignKey(
|
||||||
SchoolProfile,
|
School,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
category = models.ForeignKey(
|
category = models.ForeignKey(
|
||||||
|
@ -43,11 +64,10 @@ class Content(models.Model):
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
file = models.FileField(
|
file = models.FileField(
|
||||||
verbose_name="Fichier"
|
verbose_name="Fichier",
|
||||||
|
validators=[validate_file_extension],
|
||||||
|
upload_to=get_upload_to
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def manager_right(self):
|
|
||||||
return 'users.manage_' + str(self.school_owner.group.pk)
|
|
||||||
|
|
|
@ -5,15 +5,13 @@
|
||||||
</video>
|
</video>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="display-5">{{content.name}}</h2>
|
<h2 class="display-5">{{content.name}}</h2>
|
||||||
<p class="lead">Contenu proposé par {{content.school_owner.group.name}}</p>
|
<p class="lead">Catégorie : {{content.category.name}}</p>
|
||||||
{% if content.manager_right in perms %}
|
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a class="btn btn-sm btn-outline-primary"i href="{% url "content:content-edit" content.pk %}"><i class="fa fa-edit"></i> Éditer</a>
|
<a class="btn btn-sm btn-outline-primary"i href="{% url "content:content-edit" content.pk %}"><i class="fa fa-edit"></i> Éditer</a>
|
||||||
<a class="btn btn-sm btn-outline-danger" href="{% url "content:content-delete" content.pk %}" ><i class="fa fa-trash"></i> Supprimer</a>
|
<a class="btn btn-sm btn-outline-danger" href="{% url "content:content-delete" content.pk %}" ><i class="fa fa-trash"></i> Supprimer</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,15 +22,13 @@ $('html, body').animate({scrollTop: $('#category-content').offset().top}, 800);
|
||||||
<div class="position-relative overflow-hidden p-3 p-md-5 text-center bg-light page-title">
|
<div class="position-relative overflow-hidden p-3 p-md-5 text-center bg-light page-title">
|
||||||
<div class="col-md-5 p-lg-5 mx-auto my-5 title-block">
|
<div class="col-md-5 p-lg-5 mx-auto my-5 title-block">
|
||||||
<h1 class="display-4 font-weight-normal">{{category.name}}</h1>
|
<h1 class="display-4 font-weight-normal">{{category.name}}</h1>
|
||||||
<p class="lead font-weight-normal">{{category.description}}</p>
|
<p class="lead font-weight-normal">{{category.description_short}}</p>
|
||||||
<a class="btn btn-outline-secondary smooth-scroll" href="#category-content">Aller voir !</a>
|
<a class="btn btn-outline-secondary smooth-scroll" href="#category-content">Aller voir !</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div class="row text-center" id="category-content">
|
<div id="category-content">
|
||||||
{% for content in contents %}
|
{{category.description|safe}}
|
||||||
{% include "content/content.html" %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -1,22 +1,17 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
from .views import (
|
from .views import (
|
||||||
ContentCategoryList,
|
|
||||||
CreateCategory,
|
CreateCategory,
|
||||||
|
ViewCategory,
|
||||||
DeleteCategory,
|
DeleteCategory,
|
||||||
EditCategory,
|
EditCategory,
|
||||||
CreateContent,
|
|
||||||
DeleteContent,
|
DeleteContent,
|
||||||
EditContent,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
app_name = 'content'
|
app_name = 'content'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(
|
|
||||||
'category/<int:pk>/',
|
|
||||||
ContentCategoryList.as_view(),
|
|
||||||
name='category-list'
|
|
||||||
),
|
|
||||||
path(
|
path(
|
||||||
'category/delete/<int:pk>',
|
'category/delete/<int:pk>',
|
||||||
DeleteCategory.as_view(),
|
DeleteCategory.as_view(),
|
||||||
|
@ -28,13 +23,18 @@ urlpatterns = [
|
||||||
name='category-new'
|
name='category-new'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'category/edit/<int:pk>',
|
'category/<int:pk>',
|
||||||
|
ViewCategory.as_view(),
|
||||||
|
name='category',
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'category/<int:pk>/edit',
|
||||||
EditCategory.as_view(),
|
EditCategory.as_view(),
|
||||||
name='category-edit',
|
name='category-edit',
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'new',
|
'new/<int:school_pk>',
|
||||||
CreateContent.as_view(),
|
views.create_content,
|
||||||
name='content-new',
|
name='content-new',
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
|
@ -44,7 +44,7 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'<int:pk>/edit',
|
'<int:pk>/edit',
|
||||||
EditContent.as_view(),
|
views.edit_content,
|
||||||
name="content-edit",
|
name="content-edit",
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
126
content/views.py
126
content/views.py
|
@ -1,31 +1,21 @@
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
|
||||||
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
from .models import Content, Category
|
from .models import Content, Category
|
||||||
|
from users.models import School
|
||||||
|
from . import forms
|
||||||
from settings.models import SiteSettings
|
from settings.models import SiteSettings
|
||||||
|
|
||||||
|
|
||||||
class ContentCategoryList(generic.ListView):
|
class ViewCategory(generic.DetailView):
|
||||||
"""Affiche les contenus d'une catégorie."""
|
"""Affiche une catégorie."""
|
||||||
model = Content
|
model = Category
|
||||||
context_object_name = "contents"
|
|
||||||
template_name = "content/content_list.html"
|
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):
|
class CreateCategory(PermissionRequiredMixin, generic.CreateView):
|
||||||
"""Création de catégorie."""
|
"""Création de catégorie."""
|
||||||
|
@ -60,39 +50,6 @@ class EditCategory(PermissionRequiredMixin, generic.UpdateView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class CreateContent(PermissionRequiredMixin, generic.CreateView):
|
|
||||||
"""Création de contenu."""
|
|
||||||
model = Content
|
|
||||||
fields = [
|
|
||||||
'name',
|
|
||||||
'category',
|
|
||||||
'file'
|
|
||||||
]
|
|
||||||
template_name = "edit.html"
|
|
||||||
extra_context = {
|
|
||||||
'title' : 'Envoi de contenu',
|
|
||||||
'validate' : 'Envoyer'
|
|
||||||
}
|
|
||||||
|
|
||||||
def has_permission(self):
|
|
||||||
return self.request.user.has_perm('users.manage_'+str(self.request.user.userprofile.school.group.pk))
|
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
return self.object.school_owner.get_absolute_url()
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
form.instance.school_owner = self.request.user.userprofile.school
|
|
||||||
r = super().form_valid(form)
|
|
||||||
return r
|
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
settings,_ = SiteSettings.objects.get_or_create()
|
|
||||||
if not settings.allow_upload :
|
|
||||||
messages.error(request, "Le téléversement de contenu n'est pas autorisé actuellement.")
|
|
||||||
return redirect(reverse("home"))
|
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteContent(PermissionRequiredMixin, generic.DeleteView):
|
class DeleteContent(PermissionRequiredMixin, generic.DeleteView):
|
||||||
"""Suppression de contenu"""
|
"""Suppression de contenu"""
|
||||||
model = Content
|
model = Content
|
||||||
|
@ -103,34 +60,53 @@ class DeleteContent(PermissionRequiredMixin, generic.DeleteView):
|
||||||
|
|
||||||
def has_permission(self):
|
def has_permission(self):
|
||||||
school = get_object_or_404(Content, pk=self.kwargs['pk']).school_owner
|
school = get_object_or_404(Content, pk=self.kwargs['pk']).school_owner
|
||||||
return self.request.user.has_perm('users.manage_'+str(school.group.pk))
|
return self.request.user.is_staff or self.request.user == school.admin
|
||||||
|
|
||||||
|
|
||||||
class EditContent(PermissionRequiredMixin, generic.UpdateView):
|
def create_content(request, school_pk):
|
||||||
"""Édition d'un contenu"""
|
|
||||||
model = Content
|
|
||||||
template_name = "edit.html"
|
|
||||||
fields = [
|
|
||||||
'name',
|
|
||||||
'category',
|
|
||||||
'file'
|
|
||||||
]
|
|
||||||
template_name = "edit.html"
|
|
||||||
extra_context = {
|
|
||||||
'title' : 'Édition de contenu',
|
|
||||||
'validate' : 'Envoyer'
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_success_url(self):
|
|
||||||
return self.object.school_owner.get_absolute_url()
|
|
||||||
|
|
||||||
def has_permission(self):
|
|
||||||
school = get_object_or_404(Content, pk=self.kwargs['pk']).school_owner
|
|
||||||
return self.request.user.has_perm('users.manage_'+str(school.group.pk))
|
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
|
||||||
settings,_ = SiteSettings.objects.get_or_create()
|
settings,_ = SiteSettings.objects.get_or_create()
|
||||||
if not settings.allow_upload :
|
if not settings.allow_upload :
|
||||||
messages.error(request, "Le téléversement de contenu n'est pas autorisé actuellement.")
|
messages.error(request, "Le téléversement de contenu n'est pas autorisé actuellement.")
|
||||||
return redirect(reverse("home"))
|
return redirect(reverse("home"))
|
||||||
return super().dispatch(request, *args, **kwargs)
|
school = get_object_or_404(School, pk=school_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'))
|
||||||
|
|
||||||
|
content_form = forms.CreateContent(school, request.POST or None, request.FILES or None)
|
||||||
|
content_form.instance.school_owner = school
|
||||||
|
|
||||||
|
if content_form.is_valid():
|
||||||
|
content_form.save()
|
||||||
|
messages.success(request, "Contenu ajouté.")
|
||||||
|
return redirect(school.get_absolute_url())
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form' : content_form,
|
||||||
|
'title' : 'Ajout de contenu',
|
||||||
|
'validate' : 'Ajouter'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def edit_content(request, pk):
|
||||||
|
settings,_ = SiteSettings.objects.get_or_create()
|
||||||
|
if not settings.allow_upload :
|
||||||
|
messages.error(request, "Le téléversement de contenu n'est pas autorisé actuellement.")
|
||||||
|
return redirect(reverse("home"))
|
||||||
|
content = get_object_or_404(Content, pk=pk)
|
||||||
|
school = content.school_owner
|
||||||
|
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'))
|
||||||
|
|
||||||
|
content_form = forms.ContentEdit(request.POST or None, request.FILES or None, instance=content)
|
||||||
|
if content_form.is_valid():
|
||||||
|
content_form.save()
|
||||||
|
messages.success(request, "Contenu modifié.")
|
||||||
|
return redirect(school.get_absolute_url())
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form' : content_form,
|
||||||
|
'title' : 'Modifier un contenu',
|
||||||
|
'validate' : 'Modifier'
|
||||||
|
})
|
||||||
|
|
|
@ -15,5 +15,5 @@ class SelectUserForm(forms.Form):
|
||||||
|
|
||||||
def populate(self):
|
def populate(self):
|
||||||
admins,_ = Group.objects.get_or_create(name='admins')
|
admins,_ = Group.objects.get_or_create(name='admins')
|
||||||
choices = [(u.pk, u.first_name + ' ' + u.last_name + '(' + u.username + ')') for u in User.objects.all()]
|
choices = [(u.pk, u.first_name + ' ' + u.last_name + ' (' + u.username + ')') for u in User.objects.all()]
|
||||||
self.fields['pk'].choices = choices
|
self.fields['pk'].choices = choices
|
||||||
|
|
|
@ -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
|
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')),
|
('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.")),
|
('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")),
|
('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')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,7 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from .aes_field import AESEncryptedField
|
|
||||||
|
|
||||||
|
|
||||||
class SiteSettings(models.Model):
|
class SiteSettings(models.Model):
|
||||||
PRETTY_NAME = "Réglages du site"
|
PRETTY_NAME = "Réglages du site"
|
||||||
|
@ -23,11 +21,17 @@ class SiteSettings(models.Model):
|
||||||
null=True,
|
null=True,
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
min_number_of_categories = models.PositiveIntegerField(
|
|
||||||
verbose_name="Nombre minimal de catégories dans laquelle participer",
|
|
||||||
default=0,
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_settings(cls):
|
def get_settings(cls):
|
||||||
return cls.objects.get_or_create()[0]
|
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"
|
||||||
|
)
|
||||||
|
|
|
@ -65,6 +65,33 @@
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
<h2>Pages statiques</h2>
|
||||||
|
<a class="btn btn-success btn-sm" role="button" href="{% url 'settings:staticpage-new' %}">
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
Créer une nouvelle page statique
|
||||||
|
</a>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>Nom</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
{% for p in static_pages %}
|
||||||
|
<tr>
|
||||||
|
<td><a href="{% url 'settings:staticpage' p.pk %}">{{p.name}}</a></td>
|
||||||
|
<td><a class="btn btn-outline-primary btn-sm" href="{% url 'settings:staticpage-edit' p.pk %}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
Éditer
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-outline-danger btn-sm" title="Supprimer" href="{% url 'settings:staticpage-delete' p.pk %}">
|
||||||
|
<i class="fas fa-trash-alt"></i>
|
||||||
|
Supprimer
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
<h2>Écoles</h2>
|
<h2>Écoles</h2>
|
||||||
<a class="btn btn-success btn-sm" role="button" href="{% url 'users:new-school' %}">
|
<a class="btn btn-success btn-sm" role="button" href="{% url 'users:new-school' %}">
|
||||||
|
@ -76,30 +103,52 @@
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Nom</th>
|
<th>Nom</th>
|
||||||
<th>Nombre de membres</th>
|
|
||||||
<th>Nombre de contenus</th>
|
<th>Nombre de contenus</th>
|
||||||
<th>Nombre de catégories</th>
|
<th>Nombre de catégories</th>
|
||||||
<th>Numéro de téléphone</th>
|
<th>Numéro de téléphone</th>
|
||||||
|
<th>Inscription</th>
|
||||||
|
<th>Administrateur</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
{% for school in schools %}
|
{% for school in schools %}
|
||||||
<tr>
|
<tr>
|
||||||
<th><a href="{{school.get_absolute_url}}">{{school.group.name}}</a></th>
|
<th><a href="{{school.get_absolute_url}}">{{school.name}}</a></th>
|
||||||
<td>{{school.group.user_set.count}}</td>
|
|
||||||
<td>{{school.content_set.count}}</td>
|
<td>{{school.content_set.count}}</td>
|
||||||
<td>{{school.number_of_categories}}</td>
|
<td>{{school.number_of_categories}}</td>
|
||||||
<td>{{school.phone}}</td>
|
<td>{{school.phone}}</td>
|
||||||
<td><a class="btn btn-outline-primary btn-sm" href="{% url "users:edit-school-name" pk=school.group.pk%}">
|
<td>
|
||||||
<i class="fas fa-edit"></i>
|
{% if school.validated %}
|
||||||
Éditer
|
<span class="badge badge-success">
|
||||||
</a>
|
<i class="fa fa-check"></i>
|
||||||
<a class="btn btn-outline-danger btn-sm" title="Supprimer" href="">
|
Inscription validée
|
||||||
<i class="fas fa-trash-alt"></i>
|
</span>
|
||||||
Supprimer
|
{% else %}
|
||||||
|
<span class="badge badge-danger">
|
||||||
|
<i class="fa fa-exclamation"></i>
|
||||||
|
Inscription non validée
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if school.admin %}
|
||||||
|
{{school.admin.first_name}} {{school.admin.last_name}} ({{school.admin.username}})
|
||||||
|
{% else %}
|
||||||
|
Non défini
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'users:edit-admin' school.pk %}" class="btn btn-outline-primary btn-sm">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
Définir
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
<h2>Utilisateurs</h2>
|
||||||
|
<a class="btn btn-success btn-lg" href="{% url 'users:new-user' %}">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
Ajouter un utilisateur
|
||||||
|
</a>
|
||||||
<h2>Réglages</h2>
|
<h2>Réglages</h2>
|
||||||
<a class="btn btn-primary btn-sm" href="{% url 'settings:site-settings' %}">
|
<a class="btn btn-primary btn-sm" href="{% url 'settings:site-settings' %}">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
|
@ -142,9 +191,5 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th>Nombre minimal de catégories</th>
|
|
||||||
<td>{{ site_settings.min_number_of_categories }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
5
settings/templates/settings/static_page.html
Normal file
5
settings/templates/settings/static_page.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{object.name}}</h1>
|
||||||
|
{{object.text|safe}}
|
||||||
|
{% endblock %}
|
|
@ -1,5 +1,5 @@
|
||||||
from django import template
|
from django import template
|
||||||
from settings.models import SiteSettings
|
from settings.models import SiteSettings, StaticPage
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@ -9,7 +9,18 @@ def load_site_settings(parser, token):
|
||||||
return LoadSiteSettingsNode()
|
return LoadSiteSettingsNode()
|
||||||
|
|
||||||
|
|
||||||
|
@register.tag('load_static_pages')
|
||||||
|
def load_static_pages(parser, token):
|
||||||
|
return LoadStaticPagesNode()
|
||||||
|
|
||||||
|
|
||||||
class LoadSiteSettingsNode(template.Node):
|
class LoadSiteSettingsNode(template.Node):
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
context['site_settings'] = SiteSettings.get_settings()
|
context['site_settings'] = SiteSettings.get_settings()
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
class LoadStaticPagesNode(template.Node):
|
||||||
|
def render(self, context):
|
||||||
|
context['static_pages'] = StaticPage.objects.all()
|
||||||
|
return ''
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django.urls import path
|
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'
|
app_name = 'settings'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -22,6 +22,25 @@ urlpatterns = [
|
||||||
'promote_user',
|
'promote_user',
|
||||||
promote_user,
|
promote_user,
|
||||||
name='promote-user',
|
name='promote-user',
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'static_page/new',
|
||||||
|
CreateStaticPageView.as_view(),
|
||||||
|
name='staticpage-new'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'static_page/<int:pk>',
|
||||||
|
StaticPageView.as_view(),
|
||||||
|
name='staticpage'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'static_page/<int:pk>/delete',
|
||||||
|
DeleteStaticPageView.as_view(),
|
||||||
|
name='staticpage-delete'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'static_page/<int:pk>/edit',
|
||||||
|
EditStaticPageView.as_view(),
|
||||||
|
name='staticpage-edit'
|
||||||
)
|
)
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
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.urls import reverse_lazy, reverse
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
|
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.contrib.auth.models import Group, User
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
from content.models import Category
|
from content.models import Category
|
||||||
from users.models import SchoolProfile
|
from users.models import School
|
||||||
from .models import SiteSettings
|
from .models import SiteSettings, StaticPage
|
||||||
from .forms import SelectUserForm
|
from .forms import SelectUserForm
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,11 +20,13 @@ class SettingsView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['categories'] = Category.objects.all()
|
context['categories'] = Category.objects.all()
|
||||||
context['site_settings'], _ = SiteSettings.objects.get_or_create()
|
context['site_settings'], _ = SiteSettings.objects.get_or_create()
|
||||||
context['schools'] = SchoolProfile.objects.all()
|
context['schools'] = School.objects.all()
|
||||||
context['settings'] = True
|
context['settings'] = True
|
||||||
context['administrators'] = Group.objects.get(name='admins').user_set.all()
|
context['administrators'] = User.objects.filter(is_staff=True)
|
||||||
|
context['static_pages'] = StaticPage.objects.all()
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EditSiteSettingsView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
class EditSiteSettingsView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
||||||
template_name = "edit.html"
|
template_name = "edit.html"
|
||||||
model = SiteSettings
|
model = SiteSettings
|
||||||
|
@ -42,24 +44,82 @@ class EditSiteSettingsView(LoginRequiredMixin, PermissionRequiredMixin, UpdateVi
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@permission_required('auth.change_user')
|
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):
|
def degrade_user(request, pk):
|
||||||
user = get_object_or_404(User, pk=pk)
|
user = get_object_or_404(User, pk=pk)
|
||||||
admins,_ = Group.objects.get_or_create(name='admins')
|
user.is_staff = False
|
||||||
user.groups.remove(admins)
|
|
||||||
user.save()
|
user.save()
|
||||||
messages.success(request, user.username + ' a été enlevé des administrateurs du site')
|
messages.success(request, user.username + ' a été enlevé des administrateurs du site')
|
||||||
return redirect(reverse('settings:index'))
|
return redirect(reverse('settings:index'))
|
||||||
|
|
||||||
|
|
||||||
@permission_required('auth.change_user')
|
@staff_member_required
|
||||||
def promote_user(request):
|
def promote_user(request):
|
||||||
user_form = SelectUserForm(request.POST or None)
|
user_form = SelectUserForm(request.POST or None)
|
||||||
user_form.populate()
|
user_form.populate()
|
||||||
if user_form.is_valid():
|
if user_form.is_valid():
|
||||||
user=user_form.get_user()
|
user=user_form.get_user()
|
||||||
admins,_ = Group.objects.get_or_create(name='admins')
|
user.is_staff = True
|
||||||
user.groups.add(admins)
|
|
||||||
user.save()
|
user.save()
|
||||||
messages.success(request, user.username + ' a été ajouté des administrateurs du site')
|
messages.success(request, user.username + ' a été ajouté des administrateurs du site')
|
||||||
return redirect(reverse('settings:index'))
|
return redirect(reverse('settings:index'))
|
||||||
|
|
|
@ -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 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
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site_tps.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "site_tps.settings")
|
||||||
|
|
||||||
application = get_wsgi_application()
|
application = get_wsgi_application()
|
||||||
|
|
Binary file not shown.
BIN
static/Western Dead.ttf
Normal file
BIN
static/Western Dead.ttf
Normal file
Binary file not shown.
|
@ -28,11 +28,12 @@ body {
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Valeria';
|
font-family: 'Valeria';
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
src: url("/static/ValeriaBoldGrunge.ttf");
|
src: url("/static/Western Dead.ttf");
|
||||||
}
|
}
|
||||||
h1.site-title
|
h1.site-title
|
||||||
{
|
{
|
||||||
font-family: 'Valeria';
|
font-family: 'Valeria';
|
||||||
|
font-size: 5rem;
|
||||||
}
|
}
|
||||||
{% block style %}{% endblock %}
|
{% block style %}{% endblock %}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{% extends 'base.html'%}
|
{% extends 'base.html'%}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="site-title">IL ETAIT UNE FOIS DANS L'EST</h1>
|
<h1 class="site-title text-center">IL ETAIT UNE FOIS DANS L'EST</h1>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
{% load load_settings %}
|
{% load load_settings %}
|
||||||
{% load_categories %}
|
{% load_categories %}
|
||||||
{% load_site_settings %}
|
{% load_site_settings %}
|
||||||
|
{% load_static_pages %}
|
||||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
<a class="navbar-brand" href="{% url "home"%}">
|
<a class="navbar-brand" href="{% url "home"%}">
|
||||||
{% if site_settings.site_logo %}
|
{% if site_settings.site_logo %}
|
||||||
|
@ -17,14 +18,20 @@
|
||||||
{% for c in categories %}
|
{% for c in categories %}
|
||||||
<li class="nav-item
|
<li class="nav-item
|
||||||
{% if category.pk == c.pk %}active{%endif%}">
|
{% if category.pk == c.pk %}active{%endif%}">
|
||||||
<a class="nav-link" href="{% url 'content:category-list' c.pk %}">{{c.name}}
|
<a class="nav-link" href="{% url 'content:category' c.pk %}">{{c.name}}
|
||||||
|
</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
{% for p in static_pages %}
|
||||||
|
<li class="nav-item
|
||||||
|
{% if page.pk == p.pk %}active{%endif%}">
|
||||||
|
<a class="nav-link" href="{% url 'settings:staticpage' p.pk %}">{{p.name}}
|
||||||
</a></li>
|
</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav ml-auto">
|
<ul class="navbar-nav ml-auto">
|
||||||
{% if request.user.userprofile.school %}
|
{% if request.user.school %}
|
||||||
<li class="nav-item {% if school %}active{% endif %}"><a class="nav-link" href="{% url 'users:school' request.user.userprofile.school.group.pk %}"><i class="fas fa-graduation-cap"></i> Mon école</a></li>
|
<li class="nav-item {% if school %}active{% endif %}"><a class="nav-link" href="{% url 'users:school' request.user.school.pk %}"><i class="fas fa-graduation-cap"></i> Mon école</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="nav-item {% if settings %}active{% endif %}"><a class="nav-link" href="{% url 'settings:index' %}"><i class="fas fa-cogs"></i> Administration</a></li>
|
<li class="nav-item {% if settings %}active{% endif %}"><a class="nav-link" href="{% url 'settings:index' %}"><i class="fas fa-cogs"></i> Administration</a></li>
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
|
@ -33,7 +40,6 @@
|
||||||
{{request.user}}
|
{{request.user}}
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
|
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
|
||||||
<a class="dropdown-item" href="{% url 'users:profile' request.user.pk%}"><i class="fa fa-user"></i> Accéder à mon profil</a>
|
|
||||||
<a class="dropdown-item" href="{% url 'users:logout' %}"><i class="fa fa-sign-out-alt"></i> Se déconnecter</a>
|
<a class="dropdown-item" href="{% url 'users:logout' %}"><i class="fa fa-sign-out-alt"></i> Se déconnecter</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -41,8 +47,8 @@
|
||||||
<li class="nav-item {% if active == 4 %}active{% endif %}">
|
<li class="nav-item {% if active == 4 %}active{% endif %}">
|
||||||
<a class="nav-link" href="{% url 'users:login' %}">Connexion<span class="sr-only">(current)</span></a>
|
<a class="nav-link" href="{% url 'users:login' %}">Connexion<span class="sr-only">(current)</span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li>
|
||||||
<a class="nav-link" href="{% url 'users:new-user' %}">Inscription<span class="sr-only">(current)</span></a>
|
<a class="nav-link" href="{% url "users:password-reset" %}">(Mot de passe oublié)</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,44 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
from .models import School
|
||||||
from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
|
|
||||||
from django.contrib.auth.models import User, Group
|
|
||||||
|
|
||||||
from .models import UserProfile, SchoolProfile
|
class SchoolAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
# Define an inline admin descriptor for Employee model
|
admin.site.register(School, SchoolAdmin)
|
||||||
# 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)
|
|
||||||
|
|
72
users/forms.py
Normal file
72
users/forms.py
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
from django import forms
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from .models import School
|
||||||
|
|
||||||
|
|
||||||
|
class CreateSchool(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = School
|
||||||
|
fields = ['name', 'admin']
|
||||||
|
|
||||||
|
|
||||||
|
class EditName(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = School
|
||||||
|
fields = ['name']
|
||||||
|
|
||||||
|
|
||||||
|
class CreateUser(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = [
|
||||||
|
'username',
|
||||||
|
'first_name',
|
||||||
|
'last_name',
|
||||||
|
'email',
|
||||||
|
'groups',
|
||||||
|
'password',
|
||||||
|
]
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields['password'].widget = forms.PasswordInput()
|
||||||
|
|
||||||
|
|
||||||
|
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'
|
||||||
|
]
|
|
@ -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
|
from django.conf import settings
|
||||||
|
import django.core.validators
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
import users.models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
@ -10,24 +12,25 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('auth', '0009_alter_user_last_name_max_length'),
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='SchoolProfile',
|
name='School',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('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')),
|
('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')),
|
||||||
migrations.CreateModel(
|
('last_name_j1', models.CharField(max_length=255, verbose_name='Nom juré n°1')),
|
||||||
name='UserProfile',
|
('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')),
|
||||||
fields=[
|
('mail_j1', models.EmailField(max_length=254, verbose_name='Email juré n°1')),
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('first_name_j2', models.CharField(max_length=255, verbose_name='Prénom juré n°2')),
|
||||||
('school', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.SchoolProfile')),
|
('last_name_j2', models.CharField(max_length=255, verbose_name='Nom juré n°2')),
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
('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")),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
18
users/migrations/0002_school_validated.py
Normal file
18
users/migrations/0002_school_validated.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.0.1 on 2018-03-09 08:55
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='school',
|
||||||
|
name='validated',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Inscription validé.'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
18
users/migrations/0003_school_name.py
Normal file
18
users/migrations/0003_school_name.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.0.1 on 2018-03-09 09:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('users', '0002_school_validated'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='school',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(default='', max_length=255, verbose_name="Nom de l'école"),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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'),
|
|
||||||
),
|
|
||||||
]
|
|
129
users/models.py
129
users/models.py
|
@ -7,18 +7,22 @@ from django.dispatch import receiver
|
||||||
from django.core import validators
|
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."""
|
"""Ajoute un champ pour distinguer les groupes écoles des autres."""
|
||||||
group = models.OneToOneField(
|
name = models.CharField(
|
||||||
Group,
|
verbose_name="Nom de l'école",
|
||||||
on_delete=models.CASCADE,
|
max_length=255,
|
||||||
related_name="school",
|
default=""
|
||||||
)
|
)
|
||||||
admins = models.OneToOneField(
|
admin = models.OneToOneField(
|
||||||
Group,
|
User,
|
||||||
|
verbose_name="Administrateur de l'école",
|
||||||
|
null=True,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
related_name="admin_of",
|
|
||||||
null=True
|
|
||||||
)
|
)
|
||||||
phone = models.CharField(
|
phone = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
|
@ -31,65 +35,64 @@ class SchoolProfile(models.Model):
|
||||||
"Veuillez entrer un numéro à 10 chiffres."),
|
"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,
|
||||||
|
)
|
||||||
|
validated = models.BooleanField(
|
||||||
|
verbose_name="Inscription validé.",
|
||||||
|
default=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):
|
def __str__(self):
|
||||||
return self.group.name
|
return self.name
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("users:school", kwargs={'pk':self.group.pk})
|
return reverse("users:school", kwargs={'pk':self.pk})
|
||||||
|
|
||||||
def number_of_categories(self):
|
def number_of_categories(self):
|
||||||
return self.content_set.values('category').distinct().count()
|
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)
|
|
||||||
|
|
||||||
|
|
14
users/templates/users/password_reset_mail.html
Normal file
14
users/templates/users/password_reset_mail.html
Normal file
|
@ -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 %}
|
|
@ -2,61 +2,163 @@
|
||||||
{% load bootstrap4 %}
|
{% load bootstrap4 %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{object.name}}</h1>
|
{% if school.validated %}
|
||||||
{% if manager_right in perms %}
|
<span class="badge badge-success">
|
||||||
Numéro de téléphone :
|
<i class="fa fa-check"></i>
|
||||||
{% if object.school.phone %}{{object.school.phone}}
|
Inscription validée
|
||||||
<a class="btn btn-primary btn-sm" href="{% url 'users:edit-school-name' object.pk %}">
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
<h1>
|
||||||
|
{{school.name}}
|
||||||
|
</h1>
|
||||||
|
<a class="btn btn-primary btn-sm" href="{% url 'users:password-change' %}">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
Changer mon mot de passe
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-primary btn-sm" href="{% url 'users:edit-school-name' school.pk %}">
|
||||||
<i class="fa fa-edit"></i>
|
<i class="fa fa-edit"></i>
|
||||||
Éditer
|
Éditer
|
||||||
</a>
|
</a>
|
||||||
{%else%}
|
|
||||||
Non indiqué{%endif%}<br/>
|
|
||||||
{%endif%}
|
|
||||||
{% if manager_right in perms %}
|
|
||||||
<h2>Membres</h2>
|
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
|
||||||
<th>Nom</th>
|
|
||||||
<th>Prénom</th>
|
|
||||||
<th>Pseudo</th>
|
|
||||||
<th>Administrer</th>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for member in members %}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{member.last_name}}</td>
|
<th>
|
||||||
<td>{{member.first_name}}</td>
|
Numéro de téléphone
|
||||||
<td>{{member.username}}</td>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
{% if member in manager_group.user_set.all %}
|
{% if school.phone %}{{school.phone}}{%else%}
|
||||||
<a class="btn btn-outline-danger btn-sm" href="{% url 'users:degrade-user' object.pk member.pk %}">
|
Non indiqué{%endif%}
|
||||||
<i class="fa fa-trash"></i>
|
</td>
|
||||||
Enlever le privilège Administrateur
|
<td>
|
||||||
|
<a class="btn btn-primary btn-sm" href="{% url 'users:edit-school-phone' school.pk %}">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
Éditer
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Email
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.admin.email}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-primary btn-sm" href="{% url 'users:edit-school-mail' school.pk %}">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
Éditer
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Juré n°1
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Nom
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.last_name_j1}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Prénom
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.first_name_j1}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Email
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.mail_j1}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
N° de téléphone
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.phone_j1}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-primary btn-sm" href="{% url 'users:edit-jury-1' school.pk %}">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
Éditer
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Juré n°2
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Nom
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.last_name_j2}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Prénom
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.first_name_j2}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Email
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.mail_j2}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
N° de téléphone
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
{{school.phone_j2}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-primary btn-sm" href="{% url 'users:edit-jury-2' school.pk %}">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
Éditer
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
|
||||||
<a class="btn btn-outline-warning btn-sm" href="{% url 'users:promote-user' object.pk member.pk %}">
|
|
||||||
<i class="fa fa-star"></i>
|
|
||||||
Promouvoir administrateur
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
{% endif %}
|
|
||||||
|
<a class="btn btn-success btn-lg" href="{% url 'users:validate' school.pk %}">
|
||||||
|
<i class="fa fa-check"></i>
|
||||||
|
Valider mon inscription
|
||||||
|
</a>
|
||||||
|
|
||||||
<h2>Contenus</h2>
|
<h2>Contenus</h2>
|
||||||
{% if manager_right in perms %}
|
<a class="btn btn-success btn-sm" href="{% url 'content:content-new' school.pk %}">
|
||||||
<a class="btn btn-success btn-sm" href="{% url 'content:content-new' %}">
|
|
||||||
<i class="fa fa-plus"></i>
|
<i class="fa fa-plus"></i>
|
||||||
Ajouter un contenu
|
Ajouter un contenu
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for content in contents %}
|
{% for content in school.content_set.all %}
|
||||||
{% include "content/content.html" %}
|
{% include "content/content.html" %}
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
</div>
|
</div>
|
||||||
|
|
14
users/templates/users/welcome_user.txt
Normal file
14
users/templates/users/welcome_user.txt
Normal file
|
@ -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.
|
110
users/urls.py
110
users/urls.py
|
@ -1,85 +1,93 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from .views import (
|
from django.urls import reverse_lazy
|
||||||
CreateUser,
|
from django.contrib.auth import views as auth_views
|
||||||
CreateUserProfile,
|
from . import views
|
||||||
CreateSchool,
|
|
||||||
EditSchoolName,
|
|
||||||
EditSchoolPhone,
|
|
||||||
DeleteSchool,
|
|
||||||
Login,
|
|
||||||
Logout,
|
|
||||||
PasswordChange,
|
|
||||||
Profile,
|
|
||||||
School,
|
|
||||||
promote_user,
|
|
||||||
degrade_user
|
|
||||||
)
|
|
||||||
|
|
||||||
app_name = 'users'
|
app_name = 'users'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(
|
path(
|
||||||
'user/new',
|
'new',
|
||||||
CreateUser.as_view(),
|
views.create_user,
|
||||||
name='new-user'
|
name='new-user'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'login',
|
'login',
|
||||||
Login.as_view(),
|
auth_views.LoginView.as_view(template_name="edit.html"),
|
||||||
name='login'
|
name='login'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'logout',
|
'logout',
|
||||||
Logout.as_view(),
|
auth_views.LogoutView.as_view(),
|
||||||
name='logout',
|
name='logout'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'change_password',
|
'password_change',
|
||||||
PasswordChange.as_view(),
|
auth_views.PasswordChangeView.as_view(template_name="edit.html"),
|
||||||
name='change-password'
|
name='password-change'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'user/<int:pk>/set_school',
|
'password_change/done',
|
||||||
CreateUserProfile.as_view(),
|
views.PasswordChangeDoneView.as_view(),
|
||||||
name='create-userprofile'
|
name='password-change-done'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'user/<int:pk>',
|
'reset',
|
||||||
Profile.as_view(),
|
views.PasswordResetView.as_view(),
|
||||||
name='profile',
|
name='password-reset'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'reset/<uidb64>/<token>/',
|
||||||
|
auth_views.PasswordResetConfirmView.as_view(template_name="edit.html", success_url=reverse_lazy('users:password-reset-done')),
|
||||||
|
name='password-reset-confirm'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'reset/done/',
|
||||||
|
views.PasswordResetCompleteView.as_view(),
|
||||||
|
name='password-reset-done'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'school/new',
|
'school/new',
|
||||||
CreateSchool.as_view(),
|
views.create_school,
|
||||||
name='new-school'
|
name='new-school'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'school/<int:pk>',
|
'school/<int:pk>',
|
||||||
School.as_view(),
|
views.school,
|
||||||
name='school'
|
name='school',
|
||||||
),
|
|
||||||
path(
|
|
||||||
'school/<int:school_pk>/degrade/<int:user_pk>',
|
|
||||||
degrade_user,
|
|
||||||
name='degrade-user'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'school/<int:school_pk>/promote/<int:user_pk>',
|
|
||||||
promote_user,
|
|
||||||
name='promote-user'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'school/<int:pk>/edit_name',
|
|
||||||
EditSchoolName.as_view(),
|
|
||||||
name='edit-school-name'
|
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'school/<int:pk>/edit_phone',
|
'school/<int:pk>/edit_phone',
|
||||||
EditSchoolPhone.as_view(),
|
views.edit_phone,
|
||||||
name='edit-school-phone'
|
name='edit-school-phone'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
'school/<int:pk>/delete',
|
'school/<int:pk>/edit_name',
|
||||||
DeleteSchool.as_view(),
|
views.edit_name,
|
||||||
name='delete-school'
|
name='edit-school-name'
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
'school/<int:pk>/edit_mail',
|
||||||
|
views.edit_mail,
|
||||||
|
name='edit-school-mail'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'school/<int:pk>/jury_1',
|
||||||
|
views.edit_jury_1,
|
||||||
|
name='edit-jury-1'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'school/<int:pk>/jury_2',
|
||||||
|
views.edit_jury_2,
|
||||||
|
name='edit-jury-2'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'school/<int:pk>/edit_admin',
|
||||||
|
views.edit_admin,
|
||||||
|
name='edit-admin'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'school/<int:pk>/validate',
|
||||||
|
views.validate,
|
||||||
|
name='validate',
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
450
users/views.py
450
users/views.py
|
@ -1,220 +1,266 @@
|
||||||
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.contrib import messages
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
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 .models import UserProfile, SchoolProfile
|
from settings.forms import SelectUserForm
|
||||||
from content.models import Content
|
from content.models import Category
|
||||||
|
|
||||||
|
from .models import School
|
||||||
|
from . import forms
|
||||||
|
|
||||||
|
|
||||||
class CreateUser(CreateView):
|
@staff_member_required
|
||||||
model = User
|
def create_user(request):
|
||||||
fields = [
|
user_form = forms.CreateUser(request.POST or None)
|
||||||
'first_name',
|
if user_form.is_valid():
|
||||||
'last_name',
|
u = user_form.save()
|
||||||
'email',
|
send_mail(
|
||||||
'username',
|
"Bienvenue sur Il était une fois dans l'Est.",
|
||||||
'password',
|
render_to_string("users/welcome_user.txt", {'id':u.username}),
|
||||||
]
|
"noreply.festart@rezometz.org",
|
||||||
template_name = 'edit.html'
|
[u.email],
|
||||||
|
fail_silently=False
|
||||||
def get_success_url(self):
|
|
||||||
return reverse(
|
|
||||||
'users:create-userprofile',
|
|
||||||
kwargs={'pk': self.object.pk}
|
|
||||||
)
|
)
|
||||||
|
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', {
|
||||||
|
'form': user_form,
|
||||||
|
'title': "Création d'un utilisateur",
|
||||||
|
'validate': "Créer"
|
||||||
|
})
|
||||||
|
|
||||||
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):
|
@staff_member_required
|
||||||
r = super().form_valid(form)
|
def create_school(request):
|
||||||
self.object.set_password(form.cleaned_data['password'])
|
school_form = forms.CreateSchool(request.POST or None)
|
||||||
self.object.save()
|
if school_form.is_valid():
|
||||||
|
s = school_form.save()
|
||||||
|
messages.success(
|
||||||
|
request, "L'école {} a bien été créée.".format(s.name))
|
||||||
|
return redirect(reverse('settings:index'))
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form': school_form,
|
||||||
|
'title': "Création d'une école",
|
||||||
|
'validate': "Créer"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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})
|
||||||
|
|
||||||
|
|
||||||
|
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('home'))
|
||||||
|
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(s.get_absolute_url())
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form': school_form,
|
||||||
|
'title': "Édition du numéro de téléphone",
|
||||||
|
'validate': "Modifier"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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('home'))
|
||||||
|
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(s.get_absolute_url())
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form': school_form,
|
||||||
|
'title': "Édition du logo",
|
||||||
|
'validate': "Modifier"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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('home'))
|
||||||
|
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.school.name))
|
||||||
|
return redirect(s.school.get_absolute_url())
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form': user_form,
|
||||||
|
'title': "Édition du numéro du mail",
|
||||||
|
'validate': "Modifier"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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('home'))
|
||||||
|
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(s.get_absolute_url())
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form': school_form,
|
||||||
|
'title': "Édition du jury 1",
|
||||||
|
'validate': "Modifier"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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('home'))
|
||||||
|
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(s.get_absolute_url())
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form': school_form,
|
||||||
|
'title': "Édition du jury 2",
|
||||||
|
'validate': "Modifier"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def edit_name(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'))
|
||||||
|
school_form = forms.EditName(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(s.get_absolute_url())
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form': school_form,
|
||||||
|
'title': "Édition du nom",
|
||||||
|
'validate': "Modifier"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@staff_member_required
|
||||||
|
def edit_admin(request, pk):
|
||||||
|
school = get_object_or_404(School, pk=pk)
|
||||||
|
user_form = SelectUserForm(request.POST or None)
|
||||||
|
user_form.populate()
|
||||||
|
if user_form.is_valid():
|
||||||
|
user = user_form.get_user()
|
||||||
|
school.admin = user
|
||||||
|
school.save()
|
||||||
|
user.save()
|
||||||
|
messages.success(request, user.username +
|
||||||
|
' a été nommé admin de ' + school.name)
|
||||||
|
return redirect(reverse('settings:index'))
|
||||||
|
return render(request, 'edit.html', {
|
||||||
|
'form': user_form,
|
||||||
|
'title': "Définir l'administrateur de {}".format(school.name),
|
||||||
|
'validate': 'Ajouter'
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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('home'))
|
||||||
|
jury_1_ok = any([
|
||||||
|
school.first_name_j1,
|
||||||
|
school.last_name_j1,
|
||||||
|
school.phone_j1,
|
||||||
|
school.mail_j1
|
||||||
|
])
|
||||||
|
jury_2_ok = any([
|
||||||
|
school.first_name_j2,
|
||||||
|
school.last_name_j2,
|
||||||
|
school.phone_j2,
|
||||||
|
school.mail_j2
|
||||||
|
])
|
||||||
|
logo_ok = school.logo
|
||||||
|
phone_ok = school.phone
|
||||||
|
mail_ok = school.admin.email
|
||||||
|
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))
|
||||||
|
|
||||||
|
if phone_ok and mail_ok:
|
||||||
|
school.validated = True
|
||||||
|
school.save()
|
||||||
|
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
|
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}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class CreateUserProfile(CreateView):
|
|
||||||
model = UserProfile
|
|
||||||
fields = ['school']
|
|
||||||
template_name = 'edit.html'
|
|
||||||
|
|
||||||
|
class PasswordResetView(auth_views.PasswordResetView):
|
||||||
|
template_name = "edit.html"
|
||||||
success_url = reverse_lazy('home')
|
success_url = reverse_lazy('home')
|
||||||
|
email_template_name = "users/password_reset_mail.html"
|
||||||
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):
|
def form_valid(self, form):
|
||||||
form.instance.user = get_object_or_404(User, pk=self.kwargs['pk'])
|
messages.success(self.request, "Un mail pour le changement de mot de passe a été envoyé.")
|
||||||
return super(CreateUserProfile, self).form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class CreateSchool(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
class PasswordResetCompleteView(auth_views.PasswordResetCompleteView):
|
||||||
permission_required = 'users.add_schoolprofile'
|
template_name = "home.html"
|
||||||
model = Group
|
|
||||||
fields = ['name']
|
|
||||||
template_name = 'edit.html'
|
|
||||||
success_url = reverse_lazy('settings:index')
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def dispatch(self, *args, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
r = super().dispatch(*args, **kwargs)
|
||||||
context['title'] = "Création de l'école"
|
messages.success(self.request, "Votre mot de passe a été réinitialisé.")
|
||||||
context['validate'] = "Créer"
|
|
||||||
return context
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
|
||||||
response = super(CreateSchool, self).form_valid(form)
|
|
||||||
profile = SchoolProfile()
|
|
||||||
profile.group = form.instance
|
|
||||||
profile.save()
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
class EditSchoolName(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
||||||
model = Group
|
|
||||||
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})
|
|
||||||
|
|
||||||
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
|
return r
|
||||||
|
|
||||||
|
|
||||||
class EditSchoolPhone(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
||||||
model = SchoolProfile
|
|
||||||
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']))
|
|
||||||
|
|
||||||
|
|
||||||
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()
|
|
||||||
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']))
|
|
||||||
|
|
||||||
|
|
||||||
class Logout(SuccessMessageMixin, LogoutView):
|
|
||||||
success_message = "Vous vous êtes bien déconnecté."
|
|
||||||
|
|
||||||
|
|
||||||
class Login(SuccessMessageMixin, LoginView):
|
|
||||||
template_name = "edit.html"
|
|
||||||
success_message = "Bienvenue !"
|
|
||||||
extra_context = {
|
|
||||||
'title' : "Connexion",
|
|
||||||
'validate' : "Se connecter",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@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')
|
|
||||||
|
|
||||||
|
|
||||||
@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')
|
|
||||||
|
|
Loading…
Reference in a new issue