Gestion des contenus.

This commit is contained in:
Klafyvel 2018-02-28 21:25:44 +01:00
parent 0d237b52a8
commit 95895d23f1
18 changed files with 175 additions and 79 deletions

View file

@ -1,4 +1,4 @@
# Generated by Django 2.0.1 on 2018-02-28 12:53
# Generated by Django 2.0.1 on 2018-02-28 18:43
from django.db import migrations, models
import django.db.models.deletion
@ -9,7 +9,6 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
]
operations = [
@ -27,9 +26,8 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Nom du contenu')),
('content_url', models.URLField(null=True, verbose_name='URL du contenu')),
('file', models.FileField(upload_to='', verbose_name='Fichier')),
('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='content.Category', verbose_name='Catégorie')),
('group_owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
],
),
]

View file

@ -0,0 +1,22 @@
# Generated by Django 2.0.1 on 2018-02-28 18:43
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('content', '0001_initial'),
('users', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='content',
name='school_owner',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.SchoolProfile'),
),
]

View file

@ -3,6 +3,7 @@ from django.urls import reverse
from django.contrib.auth.models import Group
from django.conf import settings
from users.models import SchoolProfile
class Category(models.Model):
"""Une catégorie de contenu."""
@ -31,20 +32,19 @@ class Content(models.Model):
max_length=255,
verbose_name="Nom du contenu"
)
group_owner = models.ForeignKey(
Group,
school_owner = models.ForeignKey(
SchoolProfile,
on_delete=models.CASCADE,
)
content_url = models.URLField(
verbose_name='URL du contenu',
null=True,
)
category = models.ForeignKey(
Category,
on_delete=models.SET_NULL,
verbose_name="Catégorie",
null=True
)
file = models.FileField(
verbose_name="Fichier"
)
def __str__(self):
return self.name

View file

@ -0,0 +1,18 @@
<div class=" col-md-4 text-center overflow-hidden">
<div class="card mb-4 box-shadow">
<video controls class="card-img-top">
<source src="{{content.file.url}}" type="video/mp4">
</video>
<div class="card-body">
<h2 class="display-5">{{content.name}}</h2>
<p class="lead">Contenu proposé par {{content.school_owner.group.name}}</p>
<div class="d-flex justify-content-between align-items-center">
<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-danger" href="{% url "content:content-delete" content.pk %}" ><i class="fa fa-trash"></i> Supprimer</a>
</div>
</div>
</div>
</div>
</div>

View file

@ -27,18 +27,11 @@ $('html, body').animate({scrollTop: $('#category-content').offset().top}, 800);
</div>
</div>
<br />
<span id="category-content"></span>
<div class="row text-center" id="category-content">
{% for content in contents %}
<div class="bg-dark pt-3 px-3 pt-md-5 px-md-5 text-center text-white overflow-hidden">
<div class="my-3 py-3">
<h2 class="display-5">{{content.name}}</h2>
<p class="lead">Contenu proposé par {{content.group_owner.name}}</p>
</div>
<video controls>
<source src="{{content.content_url}}" type="video/mp4">
</video>
</div>
{% include "content/content.html" %}
{% endfor %}
</div>
<br />
<br />
</div>

View file

@ -5,6 +5,9 @@ from .views import (
CreateCategory,
DeleteCategory,
EditCategory,
CreateContent,
DeleteContent,
EditContent,
)
app_name = 'content'
@ -28,5 +31,21 @@ urlpatterns = [
'category/edit/<int:pk>',
EditCategory.as_view(),
name='category-edit',
)
),
path(
'new',
CreateContent.as_view(),
name='content-new',
),
path(
'<int:pk>/delete',
DeleteContent.as_view(),
name="content-delete",
),
path(
'<int:pk>/edit',
EditContent.as_view(),
name="content-edit",
),
]

View file

@ -54,3 +54,53 @@ class EditCategory(generic.UpdateView):
return context
class CreateContent(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 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
class DeleteContent(generic.DeleteView):
"""Suppression de contenu"""
model = Content
template_name = "confirm_delete.html"
def get_success_url(self):
return self.object.school_owner.get_absolute_url()
class EditContent(generic.UpdateView):
"""É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()

View file

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

View file

@ -1,7 +1,6 @@
# Generated by Django 2.0.1 on 2018-02-28 12:53
# Generated by Django 2.0.1 on 2018-02-28 18:43
from django.db import migrations, models
import settings.aes_field
class Migration(migrations.Migration):
@ -12,15 +11,6 @@ class Migration(migrations.Migration):
]
operations = [
migrations.CreateModel(
name='ContentSettings',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ftp_url', models.URLField(default='', max_length=255, verbose_name='URL du FTP')),
('ftp_id', models.CharField(default='', max_length=255, verbose_name='Identifiant sur le FTP')),
('ftp_pass', settings.aes_field.AESEncryptedField(default='', max_length=255, verbose_name='Mot de passe')),
],
),
migrations.CreateModel(
name='SiteSettings',
fields=[

View file

@ -3,25 +3,6 @@ from django.db import models
from .aes_field import AESEncryptedField
class ContentSettings(models.Model):
PRETTY_NAME = "Réglages des contenus"
ftp_url = models.URLField(
max_length=255,
verbose_name="URL du FTP",
default="",
)
ftp_id = models.CharField(
max_length=255,
verbose_name="Identifiant sur le FTP",
default=""
)
ftp_pass = AESEncryptedField(
max_length=255,
verbose_name="Mot de passe",
default=""
)
class SiteSettings(models.Model):
PRETTY_NAME = "Réglages du site"
allow_upload = models.BooleanField(

View file

@ -61,7 +61,6 @@
{% endfor %}
</table>
<h2>Réglages</h2>
<h3>Réglages du site</h3>
<a class="btn btn-primary btn-sm" href="{% url 'settings:site-settings' %}">
<i class="fas fa-edit"></i>
Éditer
@ -84,22 +83,4 @@
<td>{{site_settings.home_message}}</td>
</tr>
</table>
<h3>Réglage du contenu</h3>
<a class="btn btn-primary btn-sm" href="">
<i class="fas fa-edit"></i>
Éditer
</a>
<br />
<br />
<table class="table table-striped">
<tr>
<th>URL du FTP</th>
<td>{{content_settings.ftp_url}}</td>
</tr>
<tr>
<th>Identifiant du FTP</th>
<td>{{content_settings.ftp_id}}</td>
</tr>
</table>
{% endblock %}

View file

@ -2,7 +2,7 @@ from django.views.generic import TemplateView, UpdateView
from django.urls import reverse_lazy
from content.models import Category
from users.models import SchoolProfile
from .models import ContentSettings, SiteSettings
from .models import SiteSettings
class SettingsView(TemplateView):
@ -12,7 +12,6 @@ class SettingsView(TemplateView):
context = super().get_context_data(**kwargs)
context['categories'] = Category.objects.all()
context['site_settings'], _ = SiteSettings.objects.get_or_create()
context['content_settings'], _ = ContentSettings.objects.get_or_create()
context['schools'] = SchoolProfile.objects.all()
context['settings'] = True
return context

View file

@ -1,5 +1,6 @@
{% extends 'base.html' %}
{% block content %}
<h1>Suppression</h1>
<form action="" method="post">{% csrf_token %}
<p>Êtes-vous certain de vouloir supprimer "{{ object }}"?</p>
<input type="submit" value="Confirmer" />

View file

@ -1,4 +1,4 @@
# Generated by Django 2.0.1 on 2018-02-28 12:53
# Generated by Django 2.0.1 on 2018-02-28 18:43
from django.conf import settings
from django.db import migrations, models
@ -10,8 +10,8 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('auth', '0009_alter_user_last_name_max_length'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
@ -19,7 +19,7 @@ class Migration(migrations.Migration):
name='SchoolProfile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='students', to='auth.Group')),
],
),
migrations.CreateModel(

View file

@ -1,16 +1,23 @@
from django.db import models
from django.contrib.auth.models import User, Group
from django.db.models.signals import post_save
from django.urls import reverse
from django.dispatch import receiver
class SchoolProfile(models.Model):
"""Ajoute un champ pour distinguer les groupes écoles des autres."""
group = models.OneToOneField(Group, on_delete=models.CASCADE)
group = models.OneToOneField(
Group,
on_delete=models.CASCADE,
related_name="students"
)
def __str__(self):
return self.group.name
def get_absolute_url(self):
return reverse("users:school", kwargs={'pk':self.pk})
class UserProfile(models.Model):
"""Profil d'un utilisateur"""

View file

@ -0,0 +1,21 @@
{% extends 'base.html' %}
{% load bootstrap4 %}
{% block content %}
<h1>{{object.group.name}}</h1>
<a class="btn btn-primary btn-sm" href="{% url 'users:edit-school' object.pk %}">
<i class="fa fa-edit"></i>
Éditer
</a>
<a class="btn btn-success btn-sm" href="{% url 'content:content-new' %}">
<i class="fa fa-plus"></i>
Ajouter un contenu
</a>
<br />
<br />
<div class="row">
{% for content in contents %}
{% include "content/content.html" %}
{%endfor%}
</div>
{% endblock %}

View file

@ -9,6 +9,7 @@ from .views import (
Logout,
PasswordChange,
Profile,
School,
)
app_name = 'users'
@ -48,6 +49,11 @@ urlpatterns = [
CreateSchool.as_view(),
name='new-school'
),
path(
'school/<int:pk>',
School.as_view(),
name='school'
),
path(
'school/<int:pk>/edit',
EditSchool.as_view(),

View file

@ -1,5 +1,5 @@
from django.contrib.auth.models import User, Group
from django.views.generic import CreateView, UpdateView, DeleteView
from django.views.generic import CreateView, UpdateView, DeleteView, DetailView
from django.contrib.auth.views import LoginView, LogoutView, PasswordChangeView
from django.contrib.auth.hashers import make_password
from django.contrib.messages.views import SuccessMessageMixin
@ -7,6 +7,7 @@ from django.urls import reverse, reverse_lazy
from django.shortcuts import get_object_or_404
from .models import UserProfile, SchoolProfile
from content.models import Content
class CreateUser(CreateView):
@ -116,6 +117,16 @@ class DeleteSchool(DeleteView):
model = Group
class School(DetailView):
model = SchoolProfile
template_name = "users/school.html"
def get_context_data(self, **kwargs):
context = super().get_context_data()
context['contents'] = Content.objects.filter(school_owner=self.object)
return context
class Logout(SuccessMessageMixin, LogoutView):
success_message = "Vous vous êtes bien déconnecté."