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
import django.db.models.deletion
@ -17,7 +17,9 @@ class Migration(migrations.Migration):
name='Category',
fields=[
('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(

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.urls import reverse
from django.contrib.auth.models import Group
from django.conf import settings
class Category(models.Model):
@ -9,6 +10,14 @@ class Category(models.Model):
max_length=255,
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):
return reverse('content:category-list', kwargs={'pk':self.pk})

View file

@ -1,17 +1,42 @@
{% extends "base.html" %}
{% load staticfiles %}
{% block style %}
.page-title
{
background-image : url("{{category.image.url}}");
background-attachment : fixed;
background-position: center;
}
.title-block
{
background-color: rgba(248, 249, 250, 0.6);
}
{% endblock %}
{% block content %}
{% if category %}
<h1>{{category.name}}</h1>
{% else %}
<h1>Liste des contenus</h1>
{% endif %}
<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>
<h2>{{content.name}}</h2>
<h3>Contenu proposé par {{content.group_owner.name}}</h3>
<a href="{{content.content_url}}">C'est ici que ça se passe</a>
<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 %}

View file

@ -28,6 +28,12 @@ class CreateCategory(generic.CreateView):
"""Création de catégorie."""
model = Category
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):
@ -42,3 +48,9 @@ class EditCategory(generic.UpdateView):
model = Category
fields = '__all__'
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-bootstrap4==0.0.6
Pillow==5.0.0
pycrypto==2.6.1
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
import settings.models
import settings.aes_field
class Migration(migrations.Migration):
@ -16,17 +16,17 @@ class Migration(migrations.Migration):
name='ContentSettings',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('URL du FTP', models.URLField(max_length=255)),
('Identifiant sur le FTP', models.CharField(max_length=255)),
('Mot de passe', settings.models.AESEncryptedField(max_length=255)),
('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=[
('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.")),
('site_name', models.CharField(help_text='Nom du site', max_length=255)),
('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")),
],
),
]

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

View file

@ -26,3 +26,10 @@ class EditSiteSettingsView(UpdateView):
def get_object(self, queryset=None):
obj,_ = self.model.objects.get_or_create()
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.messages',
'django.contrib.staticfiles',
'bootstrap4',
'settings',
'content',
'vote',
'users',
]
@ -124,3 +124,6 @@ USE_TZ = True
# https://docs.djangoproject.com/en/2.0/howto/static-files/
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.urls import include, path
from django.conf import settings
from django.conf.urls.static import static
from . import views
@ -23,6 +25,7 @@ urlpatterns = [
path('', views.home, name="home"),
path('content/', include('content.urls')),
path('settings/', include('settings.urls')),
path('vote/', include('vote.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">
<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>
<style>
{% block style %}{% endblock %}
</style>
</head>
<body>
{% include 'nav_bar.html' %}

View file

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

View file

@ -14,6 +14,7 @@
</a></li>
{% 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>
</ul>
</div>
</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.db import migrations, models
@ -10,8 +10,8 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0009_alter_user_last_name_max_length'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('auth', '0009_alter_user_last_name_max_length'),
]
operations = [
@ -19,7 +19,6 @@ class Migration(migrations.Migration):
name='SchoolProfile',
fields=[
('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')),
],
),
@ -27,7 +26,7 @@ class Migration(migrations.Migration):
name='UserProfile',
fields=[
('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)),
],
),

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,
CreateSchool,
EditSchool,
DeleteSchool,
)
app_name = 'users'
@ -28,4 +29,9 @@ urlpatterns = [
EditSchool.as_view(),
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.views.generic import CreateView, UpdateView
from django.views.generic import CreateView, UpdateView, DeleteView
from django.urls import reverse, reverse_lazy
from django.shortcuts import get_object_or_404
@ -79,3 +79,8 @@ class EditSchool(UpdateView):
context['title'] = "Édition de l'école"
context['validate'] = "Modifier"
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')