Style d'affichage sur les catégories

This commit is contained in:
Klafyvel 2018-02-28 15:06:55 +01:00
parent 8cdef202c7
commit 47d96bbef9
30 changed files with 113 additions and 265 deletions

View file

@ -1,4 +1,4 @@
# Generated by Django 2.0.1 on 2018-01-24 10:29 # Generated by Django 2.0.1 on 2018-02-28 12:53
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -17,7 +17,9 @@ class Migration(migrations.Migration):
name='Category', name='Category',
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')),
('Nom de la catégorie', models.CharField(max_length=255)), ('name', models.CharField(max_length=255, verbose_name='Nom de la catégorie')),
('description', models.TextField(default='', verbose_name='Descriton de la catégorie')),
('image', models.ImageField(null=True, upload_to='', verbose_name='Illustration de la catégorie')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(

View file

@ -1,23 +0,0 @@
# Generated by Django 2.0.1 on 2018-01-24 10:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('content', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='category',
name='Nom de la catégorie',
),
migrations.AddField(
model_name='category',
name='name',
field=models.CharField(default='Nom de la catégorie', max_length=255, verbose_name='Nom de la catégorie'),
preserve_default=False,
),
]

View file

@ -1,6 +1,7 @@
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.conf import settings
class Category(models.Model): class Category(models.Model):
@ -9,6 +10,14 @@ 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 = models.TextField(
verbose_name="Descriton de la catégorie",
default=""
)
image = models.ImageField(
verbose_name="Illustration de la catégorie",
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-list', kwargs={'pk':self.pk})

View file

@ -1,17 +1,42 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% load staticfiles %}
{% block style %}
{% if category %} .page-title
<h1>{{category.name}}</h1> {
{% else %} background-image : url("{{category.image.url}}");
<h1>Liste des contenus</h1> background-attachment : fixed;
{% endif %} background-position: center;
}
{% for content in contents %} .title-block
<div> {
<h2>{{content.name}}</h2> background-color: rgba(248, 249, 250, 0.6);
<h3>Contenu proposé par {{content.group_owner.name}}</h3> }
<a href="{{content.content_url}}">C'est ici que ça se passe</a> {% endblock %}
</div> {% block content %}
{% endfor %} <script>
function show_content () {
$('html, body').animate({scrollTop: $('#category-content').offset().top}, 800);
}
</script>
<div class="position-relative overflow-hidden p-3 p-md-5 m-md-3 text-center bg-light page-title">
<div class="col-md-5 p-lg-5 mx-auto my-5 title-block">
<h1 class="display-4 font-weight-normal">{{category.name}}</h1>
<p class="lead font-weight-normal">{{category.description}}</p>
<a class="btn btn-outline-secondary smooth-scroll" href="#category-content">Aller voir !</a>
</div>
</div>
<br />
<span id="category-content"></span>
{% 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>
{% endfor %}
</div>
{% endblock %} {% endblock %}

View file

@ -28,6 +28,12 @@ class CreateCategory(generic.CreateView):
"""Création de catégorie.""" """Création de catégorie."""
model = Category model = Category
fields = '__all__' fields = '__all__'
template_name = "edit.html"
def get_context_data(self, **kwargs):
context = super(generic.CreateView, self).get_context_data(**kwargs)
context['title'] = "Création de catégorie"
return context
class DeleteCategory(generic.DeleteView): class DeleteCategory(generic.DeleteView):
@ -42,3 +48,9 @@ class EditCategory(generic.UpdateView):
model = Category model = Category
fields = '__all__' fields = '__all__'
template_name = "edit.html" template_name = "edit.html"
def get_context_data(self, **kwargs):
context = super(generic.UpdateView, self).get_context_data(**kwargs)
context['title'] = "Édition de " + self.object.name
return context

View file

@ -1,3 +1,5 @@
Django==2.0.1 Django==2.0.1
django-bootstrap4==0.0.6
Pillow==5.0.0
pycrypto==2.6.1 pycrypto==2.6.1
pytz==2017.3 pytz==2017.3

View file

@ -1,7 +1,7 @@
# Generated by Django 2.0.1 on 2018-01-14 18:04 # Generated by Django 2.0.1 on 2018-02-28 12:53
from django.db import migrations, models from django.db import migrations, models
import settings.models import settings.aes_field
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -16,17 +16,17 @@ class Migration(migrations.Migration):
name='ContentSettings', name='ContentSettings',
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')),
('URL du FTP', models.URLField(max_length=255)), ('ftp_url', models.URLField(default='', max_length=255, verbose_name='URL du FTP')),
('Identifiant sur le FTP', models.CharField(max_length=255)), ('ftp_id', models.CharField(default='', max_length=255, verbose_name='Identifiant sur le FTP')),
('Mot de passe', settings.models.AESEncryptedField(max_length=255)), ('ftp_pass', settings.aes_field.AESEncryptedField(default='', max_length=255, verbose_name='Mot de passe')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
name='SiteSettings', name='SiteSettings',
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')),
('allow_upload', models.BooleanField(help_text="Autoriser l'upload de vidéos.")), ('allow_upload', models.BooleanField(default=False, verbose_name="Autoriser l'upload de vidéos.")),
('site_name', models.CharField(help_text='Nom du site', max_length=255)), ('home_message', models.TextField(default='', verbose_name="Message de la page d'accueil")),
], ],
), ),
] ]

View file

@ -1,31 +0,0 @@
# Generated by Django 2.0.1 on 2018-01-14 18:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('settings', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='sitesettings',
name='allow_upload',
),
migrations.RemoveField(
model_name='sitesettings',
name='site_name',
),
migrations.AddField(
model_name='sitesettings',
name="Autoriser l'upload de vidéos.",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='sitesettings',
name="Message de la page d'accueil",
field=models.TextField(default=''),
),
]

View file

@ -1,59 +0,0 @@
# Generated by Django 2.0.1 on 2018-01-14 18:37
from django.db import migrations, models
import settings.models
class Migration(migrations.Migration):
dependencies = [
('settings', '0002_auto_20180114_1832'),
]
operations = [
migrations.RemoveField(
model_name='contentsettings',
name='Identifiant sur le FTP',
),
migrations.RemoveField(
model_name='contentsettings',
name='Mot de passe',
),
migrations.RemoveField(
model_name='contentsettings',
name='URL du FTP',
),
migrations.RemoveField(
model_name='sitesettings',
name="Autoriser l'upload de vidéos.",
),
migrations.RemoveField(
model_name='sitesettings',
name="Message de la page d'accueil",
),
migrations.AddField(
model_name='contentsettings',
name='ftp_id',
field=models.CharField(default='', max_length=255, verbose_name='Identifiant sur le FTP'),
),
migrations.AddField(
model_name='contentsettings',
name='ftp_pass',
field=settings.models.AESEncryptedField(default='', max_length=255, verbose_name='Mot de passe'),
),
migrations.AddField(
model_name='contentsettings',
name='ftp_url',
field=models.URLField(default='', max_length=255, verbose_name='URL du FTP'),
),
migrations.AddField(
model_name='sitesettings',
name='allow_upload',
field=models.BooleanField(default=False, verbose_name="Autoriser l'upload de vidéos."),
),
migrations.AddField(
model_name='sitesettings',
name='home_message',
field=models.TextField(default='', verbose_name="Message de la page d'accueil"),
),
]

View file

@ -4,6 +4,7 @@ from .aes_field import AESEncryptedField
class ContentSettings(models.Model): class ContentSettings(models.Model):
PRETTY_NAME = "Réglages des contenus"
ftp_url = models.URLField( ftp_url = models.URLField(
max_length=255, max_length=255,
verbose_name="URL du FTP", verbose_name="URL du FTP",
@ -22,6 +23,7 @@ class ContentSettings(models.Model):
class SiteSettings(models.Model): class SiteSettings(models.Model):
PRETTY_NAME = "Réglages du site"
allow_upload = models.BooleanField( allow_upload = models.BooleanField(
verbose_name="Autoriser l'upload de vidéos.", verbose_name="Autoriser l'upload de vidéos.",
default=False, default=False,

View file

@ -26,3 +26,10 @@ class EditSiteSettingsView(UpdateView):
def get_object(self, queryset=None): def get_object(self, queryset=None):
obj,_ = self.model.objects.get_or_create() obj,_ = self.model.objects.get_or_create()
return obj return obj
def get_context_data(self, **kwargs):
context = super(UpdateView, self).get_context_data(**kwargs)
context['title'] = "Édition des " + self.object.PRETTY_NAME
return context

View file

@ -39,9 +39,9 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'bootstrap4',
'settings', 'settings',
'content', 'content',
'vote',
'users', 'users',
] ]
@ -124,3 +124,6 @@ USE_TZ = True
# https://docs.djangoproject.com/en/2.0/howto/static-files/ # https://docs.djangoproject.com/en/2.0/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'static', 'media')

View file

@ -15,6 +15,8 @@ Including another URLconf
""" """
from django.contrib import admin from django.contrib import admin
from django.urls import include, path from django.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
from . import views from . import views
@ -23,6 +25,7 @@ urlpatterns = [
path('', views.home, name="home"), path('', views.home, name="home"),
path('content/', include('content.urls')), path('content/', include('content.urls')),
path('settings/', include('settings.urls')), path('settings/', include('settings.urls')),
path('vote/', include('vote.urls')),
path('users/', include('users.urls')), path('users/', include('users.urls')),
] ]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View file

@ -6,6 +6,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script defer src="https://use.fontawesome.com/releases/v5.0.6/js/all.js"></script> <script defer src="https://use.fontawesome.com/releases/v5.0.6/js/all.js"></script>
<style>
{% block style %}{% endblock %}
</style>
</head> </head>
<body> <body>
{% include 'nav_bar.html' %} {% include 'nav_bar.html' %}

View file

@ -1,13 +1,12 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load bootstrap3 %} {% load bootstrap4 %}
{% block content %} {% block content %}
{% if title %} {% if title %}
<h1>{{title}}</h1> <h1>{{title}}</h1>
{% endif %} {% endif %}
<form action="" method="post">{% csrf_token %} <form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
{% bootstrap_form form %} {% bootstrap_form form %}
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary">
{% bootstrap_icon "star" %}
{% if validate %} {% if validate %}
{{validate}} {{validate}}
{% else %} {% else %}

View file

@ -14,6 +14,7 @@
</a></li> </a></li>
{% endfor %} {% endfor %}
<li class="nav-item {% if vote %}active{% endif %}"><a class="nav-link" href="{% url 'vote:home' %}">Vote</a></li>
<li class="nav-item {% if settings %}active{% endif %}"><a class="nav-link" href="{% url 'settings:index' %}">Administration</a></li> <li class="nav-item {% if settings %}active{% endif %}"><a class="nav-link" href="{% url 'settings:index' %}">Administration</a></li>
</ul>
</div>
</nav> </nav>

View file

@ -1,4 +1,4 @@
# Generated by Django 2.0.1 on 2018-01-31 09:12 # Generated by Django 2.0.1 on 2018-02-28 12:53
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@ -10,8 +10,8 @@ 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),
('auth', '0009_alter_user_last_name_max_length'),
] ]
operations = [ operations = [
@ -19,7 +19,6 @@ class Migration(migrations.Migration):
name='SchoolProfile', name='SchoolProfile',
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')),
('is_school', models.BooleanField()),
('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')), ('group', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
], ],
), ),
@ -27,7 +26,7 @@ class Migration(migrations.Migration):
name='UserProfile', name='UserProfile',
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')),
('school', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.SchoolProfile')), ('school', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.SchoolProfile')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
], ],
), ),

View file

@ -1,23 +0,0 @@
# Generated by Django 2.0.1 on 2018-01-31 10:52
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('users', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='schoolprofile',
name='is_school',
),
migrations.AlterField(
model_name='userprofile',
name='school',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='users.SchoolProfile'),
),
]

View file

@ -4,6 +4,7 @@ from .views import (
CreateUserProfile, CreateUserProfile,
CreateSchool, CreateSchool,
EditSchool, EditSchool,
DeleteSchool,
) )
app_name = 'users' app_name = 'users'
@ -28,4 +29,9 @@ urlpatterns = [
EditSchool.as_view(), EditSchool.as_view(),
name='edit-school' name='edit-school'
), ),
path(
'school/<int:pk>/delete',
DeleteSchool.as_view(),
name='delete-school'
),
] ]

View file

@ -1,5 +1,5 @@
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from django.views.generic import CreateView, UpdateView from django.views.generic import CreateView, UpdateView, DeleteView
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@ -79,3 +79,8 @@ class EditSchool(UpdateView):
context['title'] = "Édition de l'école" context['title'] = "Édition de l'école"
context['validate'] = "Modifier" context['validate'] = "Modifier"
return context return context
class DeleteSchool(DeleteView):
model = Group

View file

View file

@ -1,5 +0,0 @@
from django.contrib import admin
from .models import Vote, Poll
admin.site.register(Vote)
admin.site.register(Poll)

View file

@ -1,5 +0,0 @@
from django.apps import AppConfig
class VoteConfig(AppConfig):
name = 'vote'

View file

@ -1,39 +0,0 @@
# Generated by Django 2.0.1 on 2018-01-24 10:29
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('content', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Poll',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=1024)),
('contents', models.ManyToManyField(to='content.Content')),
('voters_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')),
],
),
migrations.CreateModel(
name='Vote',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('vote', models.IntegerField(validators=[django.core.validators.MaxValueValidator(5), django.core.validators.MinValueValidator(0)])),
('content', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='content.Content')),
('poll', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='vote.Poll')),
('votant', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
]

View file

@ -1,22 +0,0 @@
from django.db import models
from django.core import validators
from content.models import Content
from django.contrib.auth.models import Group, User
class Poll(models.Model):
voters_group = models.ForeignKey(Group, on_delete=models.CASCADE)
contents = models.ManyToManyField(Content)
title = models.CharField(max_length=1024)
class Vote(models.Model):
votant = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.ForeignKey(Content, on_delete=models.CASCADE)
poll = models.ForeignKey(Poll, on_delete=models.CASCADE)
vote = models.IntegerField(
validators=[
validators.MaxValueValidator(5),
validators.MinValueValidator(0)
]
)

View file

@ -1,6 +0,0 @@
{% extends 'base.html' %}
{% block content %}
<div class="container">
<h2>Votes disponibles</h2>
</div>
{% endblock %}

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,7 +0,0 @@
from django.urls import path
from . import views
app_name = 'vote'
urlpatterns = [
path('home', views.home, name='home')
]

View file

@ -1,7 +0,0 @@
from django.shortcuts import render
# Create your views here.
def home(request):
return render(request, 'vote/home.html')