From 4808650fa05f1ee859885476dd2b82a8315835a5 Mon Sep 17 00:00:00 2001 From: Qwann Date: Thu, 9 Feb 2017 14:05:29 +0100 Subject: [PATCH 001/150] kfet_open is updatable --- kfet/migrations/00048_kfet_open_cache.py | 24 +++++++++++++++++++++++ kfet/models.py | 2 ++ kfet/urls.py | 3 +++ kfet/views.py | 25 +++++++++++++++++++++++- 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 kfet/migrations/00048_kfet_open_cache.py diff --git a/kfet/migrations/00048_kfet_open_cache.py b/kfet/migrations/00048_kfet_open_cache.py new file mode 100644 index 00000000..ed9b7041 --- /dev/null +++ b/kfet/migrations/00048_kfet_open_cache.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('kfet', '0047_auto_20170104_1528'), + ] + + operations = [ + migrations.AddField( + model_name='settings', + name='value_boolean', + field=models.NullBooleanField(default=None), + ), + migrations.AddField( + model_name='settings', + name='value_datetime', + field=models.DateTimeField(blank=True, null=True, default=None), + ), + ] diff --git a/kfet/models.py b/kfet/models.py index 419cd0a0..359bdfca 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -569,6 +569,8 @@ class GlobalPermissions(models.Model): ('special_add_account', "Créer un compte avec une balance initiale") ) + + class Settings(models.Model): name = models.CharField( max_length = 45, diff --git a/kfet/urls.py b/kfet/urls.py index 271ed917..11d2a1b9 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -167,6 +167,9 @@ urlpatterns = [ permission_required('kfet.change_settings') (views.SettingsUpdate.as_view()), name='kfet.settings.update'), + url('^settings/kfet_open/$', + views.UpdateKfetOpen.as_view(), + name='kfet.settings.kfet_open'), # ----- # Transfers urls diff --git a/kfet/views.py b/kfet/views.py index 7083d489..023dab55 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -7,7 +7,7 @@ from builtins import * from django.shortcuts import render, get_object_or_404, redirect from django.core.exceptions import PermissionDenied, ValidationError from django.core.cache import cache -from django.views.generic import ListView, DetailView +from django.views.generic import ListView, DetailView, View from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView from django.core.urlresolvers import reverse_lazy from django.contrib import messages @@ -40,6 +40,29 @@ import statistics def home(request): return render(request, "kfet/base.html") + +def KFET_OPEN(): + kfet_open_date = cache.get('KFET_OPEN_DATE') + kfet_open = cache.get('KFET_OPEN') + if not kfet_open_date: + kfet_open_date = timezone.now() + cache.set('KFET_OPEN_DATE', kfet_open_date) + if not kfet_open: + kfet_open = False + cache.set('KFET_OPEN', kfet_open) + return (kfet_open, kfet_open_date) + + +class UpdateKfetOpen(View): + def get(self, request, *args, **kwargs): + open_string = request.GET.get('open') + is_open = not (open_string == "false" or open_string == "False") + cache.set('KFET_OPEN', is_open) + cache.set('KFET_OPEN_DATE', timezone.now()) + (is_open_get, time) = KFET_OPEN() + return HttpResponse("%r at %s" % (is_open_get, time.isoformat())) + + @teamkfet_required def login_genericteam(request): # Check si besoin de déconnecter l'utilisateur de CAS From f87f1ceff138ee2c41853a1538dac16ab79e3269 Mon Sep 17 00:00:00 2001 From: Qwann Date: Sat, 11 Feb 2017 00:29:12 +0100 Subject: [PATCH 002/150] kfetOpen bullet working --- cof/settings_dev.py | 1 + kfet/consumers.py | 18 +++++++++++ kfet/context_processors.py | 10 ++++++ kfet/routing.py | 1 + kfet/static/kfet/css/nav.css | 20 +++++++++++- kfet/static/kfet/js/kfet_open.js | 54 +++++++++++++++++++++++++++++++ kfet/templates/kfet/base.html | 2 ++ kfet/templates/kfet/base_nav.html | 7 ++-- kfet/templates/kfet/kpsul.html | 1 - kfet/views.py | 13 ++++++-- 10 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 kfet/static/kfet/js/kfet_open.js diff --git a/cof/settings_dev.py b/cof/settings_dev.py index f6521222..4d604cac 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -83,6 +83,7 @@ TEMPLATES = [ 'django.core.context_processors.static', 'gestioncof.shared.context_processor', 'kfet.context_processors.auth', + 'kfet.context_processors.kfet_open', ], }, }, diff --git a/kfet/consumers.py b/kfet/consumers.py index dcd69bdf..72e3b21e 100644 --- a/kfet/consumers.py +++ b/kfet/consumers.py @@ -24,3 +24,21 @@ class KPsul(JsonWebsocketConsumer): def disconnect(self, message, **kwargs): pass + +class KfetOpen(JsonWebsocketConsumer): + + # Set to True if you want them, else leave out + strict_ordering = False + slight_ordering = False + + def connection_groups(self, **kwargs): + return ['kfet.is_open'] + + def connect(self, message, **kwargs): + pass + + def receive(self, content, **kwargs): + pass + + def disconnect(self, message, **kwargs): + pass diff --git a/kfet/context_processors.py b/kfet/context_processors.py index ef4f2e64..f3b8f76f 100644 --- a/kfet/context_processors.py +++ b/kfet/context_processors.py @@ -5,6 +5,8 @@ from __future__ import (absolute_import, division, from builtins import * from django.contrib.auth.context_processors import PermWrapper +from .views import KFET_OPEN + def auth(request): if hasattr(request, 'real_user'): @@ -13,3 +15,11 @@ def auth(request): 'perms': PermWrapper(request.real_user), } return {} + + +def kfet_open(resquest): + (kfet_open, kfet_open_date) = KFET_OPEN() + return { + 'kfet_open': kfet_open, + 'kfet_open_date': kfet_open_date, + } diff --git a/kfet/routing.py b/kfet/routing.py index 5ea343cb..5db0101f 100644 --- a/kfet/routing.py +++ b/kfet/routing.py @@ -9,4 +9,5 @@ from kfet import consumers channel_routing = [ route_class(consumers.KPsul, path=r"^/ws/k-fet/k-psul/$"), + route_class(consumers.KfetOpen, path=r"^/ws/k-fet/is_open/$"), ] diff --git a/kfet/static/kfet/css/nav.css b/kfet/static/kfet/css/nav.css index 5ffc7b24..9e2c5462 100644 --- a/kfet/static/kfet/css/nav.css +++ b/kfet/static/kfet/css/nav.css @@ -14,7 +14,7 @@ nav { } nav .navbar-brand { - padding:3px 25px; + padding:3px 15px 3px 25px; } nav .navbar-brand img { @@ -44,6 +44,24 @@ nav a { background-color:#C8102E; } +#kfet-open { + font-weight: bold; + font-size: 14px; + width:10px; + height:10px; + text-transform: uppercase; + border-radius: 50%; + background-color: white; + display: inline-block; +} + +#kfet-open-wrapper { + padding-top: 18px; + margin: 0px 10px; + display: inline-block; + line-height: 10px; +} + .dropdown-menu { padding:0; } diff --git a/kfet/static/kfet/js/kfet_open.js b/kfet/static/kfet/js/kfet_open.js new file mode 100644 index 00000000..9f5e4c22 --- /dev/null +++ b/kfet/static/kfet/js/kfet_open.js @@ -0,0 +1,54 @@ +function kfet_open(init_date, init_satus) { + // VARIABLES + var kfet_open_bullet = $('#kfet-open'); + var open_color = "#73C252"; + var closed_color = "#B42B26"; + var unknown_color = "#ECD03E"; + var kfet_open_date = init_date; + var kfet_open = init_status; + // INITIALISAITION + update_open_bullet(); + // FONCTIONS + function nb_min_diff() { + var date_now = new Date(); + // On calcule le nb de minutes depuis le dernier + // envoi d'information + tmp = date_now - kfet_open_date; + + tmp = Math.floor(tmp/1000); // Nombre de secondes entre les 2 dates + diff_sec = tmp % 60; // Extraction du nombre de secondes + + tmp = Math.floor((tmp-diff_sec)/60); // Nombre de minutes (partie entière) + + return tmp; + } + function update_open_bullet() { + nb_min = nb_min_diff(); + console.log("K-Fêt ouverte : " + kfet_open); + console.log(nb_min + " minute(s) depuis la dernière mise à jour"); + if (nb_min > 5) { + kfet_open_bullet.css({'background-color': unknown_color}); + } else if (kfet_open){ + kfet_open_bullet.css({'background-color': open_color}); + } else { + kfet_open_bullet.css({'background-color': closed_color}); + } + } + // SYNCHRONIZATION + websocket_msg_default = {'last_op': 0} + + var websocket_protocol = window.location.protocol == 'https:' ? 'wss' : 'ws'; + var location_host = window.location.host; + var location_url = window.location.pathname.startsWith('/gestion/') ? location_host + '/gestion' : location_host; + var socket = new ReconnectingWebSocket(websocket_protocol+"://" + location_url + "/ws/k-fet/is_open/"); + + socket.onmessage = function(e) { + var data = $.extend({}, websocket_msg_default, JSON.parse(e.data)); + console.log("Message reçu de la part de la porte."); + + kfet_open_date = new Date(data['kfet_open_date']); + kfet_open = data['kfet_open']; + + update_open_bullet(); + } +} diff --git a/kfet/templates/kfet/base.html b/kfet/templates/kfet/base.html index 173a5fb7..7587cb7b 100644 --- a/kfet/templates/kfet/base.html +++ b/kfet/templates/kfet/base.html @@ -18,6 +18,8 @@ + + {% block extra_head %}{% endblock %} diff --git a/kfet/templates/kfet/base_nav.html b/kfet/templates/kfet/base_nav.html index b5c98375..d884d110 100644 --- a/kfet/templates/kfet/base_nav.html +++ b/kfet/templates/kfet/base_nav.html @@ -12,6 +12,7 @@ + - - diff --git a/kfet/templates/kfet/home.html b/kfet/templates/kfet/home.html index 40a1debd..6d4f163f 100644 --- a/kfet/templates/kfet/home.html +++ b/kfet/templates/kfet/home.html @@ -20,8 +20,8 @@
?????
diff --git a/kfet/urls.py b/kfet/urls.py index aad89cd4..47f14b52 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -211,7 +211,10 @@ urlpatterns = [ url('^kfet_open/$', views.UpdateKfetOpen.as_view(), - name='kfet.settings.kfet_open'), + name='kfet.kfet_open'), + url('^force_close/$', + views.UpdateForceClose.as_view(), + name='kfet.force_close'), # ----- # Transfers urls diff --git a/kfet/views.py b/kfet/views.py index 7856cf22..77bb061d 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -94,15 +94,37 @@ class UpdateKfetOpen(View): cache.set('KFET_OPEN_DATE', timezone.now()) # Websocket - websocket_data = {} - websocket_data['kfet_open'] = is_open - websocket_data['kfet_open_date'] = timezone.now() + websocket_data = { + 'door_action': { + 'kfet_open': is_open, + 'kfet_open_date': timezone.now(), + }, + } consumers.KfetOpen.group_send('kfet.is_open', websocket_data) (is_open_get, time) = KFET_OPEN() return HttpResponse("%r at %s" % (is_open_get, time.isoformat())) +class UpdateForceClose(View): + def get(self, request, *args, **kwargs): + force_close = "close" in request.GET + cache.set('KFET_FORCE_CLOSE', force_close) + + # Websocket + websocket_data = { + 'force_action': { + 'force_close': force_close, + }, + } + consumers.KfetOpen.group_send('kfet.is_open', websocket_data) + + force_close_get = KFET_FORCE_CLOSE() + time = timezone.now() + return HttpResponse("closed : %r at %s" % (force_close_get, + time.isoformat())) + + @teamkfet_required def login_genericteam(request): # Check si besoin de déconnecter l'utilisateur de CAS From f18bb9f336dbca42af6375a227232106325bf083 Mon Sep 17 00:00:00 2001 From: Qwann Date: Thu, 9 Mar 2017 17:27:58 +0100 Subject: [PATCH 012/150] permission added --- kfet/templates/kfet/home.html | 2 ++ kfet/views.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/kfet/templates/kfet/home.html b/kfet/templates/kfet/home.html index 6d4f163f..a4f9ee4c 100644 --- a/kfet/templates/kfet/home.html +++ b/kfet/templates/kfet/home.html @@ -19,11 +19,13 @@
?????
+ {% if perms.kfet.is_team %} + {% endif %}
diff --git a/kfet/views.py b/kfet/views.py index 77bb061d..4278aa88 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -124,6 +124,11 @@ class UpdateForceClose(View): return HttpResponse("closed : %r at %s" % (force_close_get, time.isoformat())) + @method_decorator(login_required) + @method_decorator(teamkfet_required) + def dispatch(self, *args, **kwargs): + return super(UpdateForceClose, self).dispatch(*args, **kwargs) + @teamkfet_required def login_genericteam(request): From cd31c5525459b380b2ad0676f84b48a5ac8966a9 Mon Sep 17 00:00:00 2001 From: Qwann Date: Fri, 10 Mar 2017 16:40:36 +0100 Subject: [PATCH 013/150] permission working --- kfet/decorators.py | 4 ++++ kfet/models.py | 2 +- kfet/static/kfet/js/kfet_open.js | 38 ++++++++++++++++++++++++++------ kfet/views.py | 3 ++- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/kfet/decorators.py b/kfet/decorators.py index 9af9247f..accfa143 100644 --- a/kfet/decorators.py +++ b/kfet/decorators.py @@ -9,4 +9,8 @@ from django_cas_ng.decorators import user_passes_test def kfet_is_team(user): return user.has_perm('kfet.is_team') +def can_force_close(user): + return user.has_perm('force_close_kfet') + teamkfet_required = user_passes_test(lambda u: kfet_is_team(u)) +force_close_required = user_passes_test(lambda u: can_force_close(u)) diff --git a/kfet/models.py b/kfet/models.py index b95755b7..928b7d88 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -594,7 +594,7 @@ class GlobalPermissions(models.Model): ('edit_balance_account', "Modifier la balance d'un compte"), ('change_account_password', "Modifier le mot de passe d'une personne de l'équipe"), ('special_add_account', "Créer un compte avec une balance initiale"), - ('can_close_kfet', "Peut fermer manuelement la K-Fêt"), + ('force_close_kfet', "Fermer manuelement la K-Fêt"), ) diff --git a/kfet/static/kfet/js/kfet_open.js b/kfet/static/kfet/js/kfet_open.js index 93374094..8ea0be70 100644 --- a/kfet/static/kfet/js/kfet_open.js +++ b/kfet/static/kfet/js/kfet_open.js @@ -17,13 +17,7 @@ function kfet_open(init_date, init_satus, init_force_close, force_close_url, for var force_close = init_force_close; // EVENT - force_close_button.click(function() { - if (force_close) { - $.get(force_open_url, function(data) {}); - } else { - $.get(force_close_url, function(data) {}); - } - }); + force_close_button.click(forceClose); // INITIALISAITION update_open(); @@ -36,6 +30,36 @@ function kfet_open(init_date, init_satus, init_force_close, force_close_url, for }, 30 * 1000); // 60 * 1000 milsec // FONCTIONS + function forceClose(password = '') { + if (force_close) { + force_url = force_open_url; + } else { + force_url = force_close_url; + } + $.ajax({ + dataType: "html", + url : force_url, + method : "GET", + beforeSend: function ($xhr) { + if (password != '') + $xhr.setRequestHeader("KFetPassword", password); + }, + }) + .done(function() {}) + .fail(function($xhr) { + var data = $xhr.responseJSON; + switch ($xhr.status) { + case 403: + requestAuth({'errors':{}}, forceClose); + break; + case 400: + alert('lol'); + break; + } + lock = 0; + }); + } + function nb_min_diff() { var date_now = new Date(); // On calcule le nb de minutes depuis le dernier diff --git a/kfet/views.py b/kfet/views.py index 4278aa88..af633cd7 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -22,7 +22,7 @@ from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.decorators import method_decorator from gestioncof.models import CofProfile, Clipper -from kfet.decorators import teamkfet_required +from kfet.decorators import teamkfet_required, force_close_required from kfet.models import ( Account, Checkout, Article, Settings, AccountNegative, CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory, @@ -126,6 +126,7 @@ class UpdateForceClose(View): @method_decorator(login_required) @method_decorator(teamkfet_required) + @method_decorator(force_close_required) def dispatch(self, *args, **kwargs): return super(UpdateForceClose, self).dispatch(*args, **kwargs) From b0643c09288cdca6edd4c98c53d3884d13334fe1 Mon Sep 17 00:00:00 2001 From: Qwann Date: Sat, 11 Mar 2017 02:04:30 +0100 Subject: [PATCH 014/150] typo --- kfet/context_processors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/context_processors.py b/kfet/context_processors.py index 0d98c7e1..6c053ea9 100644 --- a/kfet/context_processors.py +++ b/kfet/context_processors.py @@ -17,7 +17,7 @@ def auth(request): return {} -def kfet_open(resquest): +def kfet_open(request): (kfet_open, kfet_open_date) = KFET_OPEN() kfet_force_close = KFET_FORCE_CLOSE() return { From c3d740ade00f54a299231456ee07269b98b12f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 1 Apr 2017 21:45:05 +0100 Subject: [PATCH 015/150] Handle incomplete values from the LDAP Sometime `uid` is not set in the objects fetched from the LDAP. This case has to be handled. Also, the `.uid` and `.cn` attributes of these objects in the python abstractions have a `.value` method which we should use. --- gestioncof/autocomplete.py | 32 ++++++++++++++++++++------------ kfet/autocomplete.py | 32 ++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index 1eae6920..98363377 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -14,6 +14,10 @@ from gestioncof.decorators import buro_required class Clipper(object): def __init__(self, clipper, fullname): + if fullname is None: + fullname = "" + assert isinstance(clipper, str) + assert isinstance(fullname, str) self.clipper = clipper self.fullname = fullname @@ -60,18 +64,22 @@ def autocomplete(request): ['(cn=*{bit:s}*)(uid=*{bit:s}*)'.format(**{"bit": bit}) for bit in bits] )) - with Connection(settings.LDAP_SERVER_URL) as conn: - conn.search( - 'dc=spi,dc=ens,dc=fr', ldap_query, - attributes=['uid', 'cn'] - ) - queries['clippers'] = conn.entries - # Clearing redundancies - queries['clippers'] = [ - Clipper(clipper.uid, clipper.cn) - for clipper in queries['clippers'] - if str(clipper.uid) not in usernames - ] + if ldap_query != "(&)": + # If none of the bits were legal, we do not perform the query + entries = None + with Connection(settings.LDAP_SERVER_URL) as conn: + conn.search( + 'dc=spi,dc=ens,dc=fr', ldap_query, + attributes=['uid', 'cn'] + ) + entries = conn.entries + # Clearing redundancies + queries['clippers'] = [ + Clipper(entry.uid.value, entry.cn.value) + for entry in entries + if entry.uid.value is not None + and entry.uid.value not in usernames + ] # Resulting data data.update(queries) diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py index 64fa52cf..acc6ebd8 100644 --- a/kfet/autocomplete.py +++ b/kfet/autocomplete.py @@ -14,6 +14,10 @@ from kfet.models import Account class Clipper(object): def __init__(self, clipper, fullname): + if fullname is None: + fullname = "" + assert isinstance(clipper, str) + assert isinstance(fullname, str) self.clipper = clipper self.fullname = fullname @@ -79,18 +83,22 @@ def account_create(request): ['(cn=*{bit:s}*)(uid=*{bit:s}*)'.format(bit=word) for word in search_words] )) - with Connection(settings.LDAP_SERVER_URL) as conn: - conn.search( - 'dc=spi,dc=ens,dc=fr', ldap_query, - attributes=['uid', 'cn'] - ) - queries['clippers'] = conn.entries - # Clearing redundancies - queries['clippers'] = [ - Clipper(clipper.uid, clipper.cn) - for clipper in queries['clippers'] - if str(clipper.uid) not in usernames - ] + if ldap_query != "(&)": + # If none of the bits were legal, we do not perform the query + entries = None + with Connection(settings.LDAP_SERVER_URL) as conn: + conn.search( + 'dc=spi,dc=ens,dc=fr', ldap_query, + attributes=['uid', 'cn'] + ) + entries = conn.entries + # Clearing redundancies + queries['clippers'] = [ + Clipper(entry.uid.value, entry.cn.value) + for entry in entries + if entry.uid.value is not None + and entry.uid.value not in usernames + ] # Resulting data data.update(queries) From f6d43dffa1e0d45d978dfef9a412cc48933504d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 1 Apr 2017 22:07:32 +0100 Subject: [PATCH 016/150] exclude empty strings from ldap results The uid attribute in a LDAP's entry cannot be an empty string. We need to get an actual identifier. --- gestioncof/autocomplete.py | 2 +- kfet/autocomplete.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gestioncof/autocomplete.py b/gestioncof/autocomplete.py index 98363377..ccf8804e 100644 --- a/gestioncof/autocomplete.py +++ b/gestioncof/autocomplete.py @@ -77,7 +77,7 @@ def autocomplete(request): queries['clippers'] = [ Clipper(entry.uid.value, entry.cn.value) for entry in entries - if entry.uid.value is not None + if entry.uid.value and entry.uid.value not in usernames ] diff --git a/kfet/autocomplete.py b/kfet/autocomplete.py index acc6ebd8..c97779c1 100644 --- a/kfet/autocomplete.py +++ b/kfet/autocomplete.py @@ -96,7 +96,7 @@ def account_create(request): queries['clippers'] = [ Clipper(entry.uid.value, entry.cn.value) for entry in entries - if entry.uid.value is not None + if entry.uid.value and entry.uid.value not in usernames ] From ef8fec89fed8b401f0c8db714f6c498736395be2 Mon Sep 17 00:00:00 2001 From: Qwann Date: Wed, 5 Apr 2017 17:50:49 +0200 Subject: [PATCH 017/150] migration renamed --- kfet/migrations/0049_merge.py | 1 - .../{0048_kfet_open_cache.py => 0053_kfet_open_cache.py} | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) rename kfet/migrations/{0048_kfet_open_cache.py => 0053_kfet_open_cache.py} (92%) diff --git a/kfet/migrations/0049_merge.py b/kfet/migrations/0049_merge.py index dedc340b..0ce9a525 100644 --- a/kfet/migrations/0049_merge.py +++ b/kfet/migrations/0049_merge.py @@ -7,7 +7,6 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('kfet', '0048_kfet_open_cache'), ('kfet', '0048_article_hidden'), ('kfet', '0048_default_datetime'), ] diff --git a/kfet/migrations/0048_kfet_open_cache.py b/kfet/migrations/0053_kfet_open_cache.py similarity index 92% rename from kfet/migrations/0048_kfet_open_cache.py rename to kfet/migrations/0053_kfet_open_cache.py index ed9b7041..9669e684 100644 --- a/kfet/migrations/0048_kfet_open_cache.py +++ b/kfet/migrations/0053_kfet_open_cache.py @@ -7,7 +7,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('kfet', '0047_auto_20170104_1528'), + ('kfet', '0052_category_addcost'), ] operations = [ From deb0d4de1e4331dbc25ffb6dc9aef1934ceea58f Mon Sep 17 00:00:00 2001 From: Qwann Date: Fri, 7 Apr 2017 17:23:41 +0200 Subject: [PATCH 018/150] moving migration again --- kfet/migrations/0053_kfet_open_cache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/migrations/0053_kfet_open_cache.py b/kfet/migrations/0053_kfet_open_cache.py index 9669e684..a1a8f213 100644 --- a/kfet/migrations/0053_kfet_open_cache.py +++ b/kfet/migrations/0053_kfet_open_cache.py @@ -7,7 +7,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('kfet', '0052_category_addcost'), + ('kfet', '0053_kfet_open_cache'), ] operations = [ From e18c2c698c4b38c9de7b98e12664570e42dcfb6e Mon Sep 17 00:00:00 2001 From: Qwann Date: Fri, 7 Apr 2017 17:41:23 +0200 Subject: [PATCH 019/150] new migration --- kfet/migrations/0053_kfet_open_cache.py | 24 ------------------- kfet/migrations/0054_force_kfet_close_perm.py | 18 ++++++++++++++ 2 files changed, 18 insertions(+), 24 deletions(-) delete mode 100644 kfet/migrations/0053_kfet_open_cache.py create mode 100644 kfet/migrations/0054_force_kfet_close_perm.py diff --git a/kfet/migrations/0053_kfet_open_cache.py b/kfet/migrations/0053_kfet_open_cache.py deleted file mode 100644 index a1a8f213..00000000 --- a/kfet/migrations/0053_kfet_open_cache.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('kfet', '0053_kfet_open_cache'), - ] - - operations = [ - migrations.AddField( - model_name='settings', - name='value_boolean', - field=models.NullBooleanField(default=None), - ), - migrations.AddField( - model_name='settings', - name='value_datetime', - field=models.DateTimeField(blank=True, null=True, default=None), - ), - ] diff --git a/kfet/migrations/0054_force_kfet_close_perm.py b/kfet/migrations/0054_force_kfet_close_perm.py new file mode 100644 index 00000000..52290026 --- /dev/null +++ b/kfet/migrations/0054_force_kfet_close_perm.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('kfet', '0053_created_at'), + ] + + operations = [ + migrations.AlterModelOptions( + name='globalpermissions', + options={'managed': False, 'permissions': (('is_team', 'Is part of the team'), ('perform_deposit', 'Effectuer une charge'), ('perform_negative_operations', 'Enregistrer des commandes en négatif'), ('override_frozen_protection', "Forcer le gel d'un compte"), ('cancel_old_operations', 'Annuler des commandes non récentes'), ('manage_perms', 'Gérer les permissions K-Fêt'), ('manage_addcosts', 'Gérer les majorations'), ('perform_commented_operations', 'Enregistrer des commandes avec commentaires'), ('view_negs', 'Voir la liste des négatifs'), ('order_to_inventory', "Générer un inventaire à partir d'une commande"), ('edit_balance_account', "Modifier la balance d'un compte"), ('change_account_password', "Modifier le mot de passe d'une personne de l'équipe"), ('special_add_account', 'Créer un compte avec une balance initiale'), ('force_close_kfet', 'Fermer manuelement la K-Fêt'))}, + ), + ] From 15873085e11425d0cc1ca44ef3fd65c1091bfb8b Mon Sep 17 00:00:00 2001 From: Qwann Date: Sun, 9 Apr 2017 20:01:52 +0200 Subject: [PATCH 020/150] small fixes --- kfet/consumers.py | 5 ----- kfet/decorators.py | 2 -- kfet/static/kfet/js/kfet_open.js | 16 ++++++---------- kfet/urls.py | 5 +++-- kfet/views.py | 13 +++---------- 5 files changed, 12 insertions(+), 29 deletions(-) diff --git a/kfet/consumers.py b/kfet/consumers.py index 72e3b21e..8a0df05f 100644 --- a/kfet/consumers.py +++ b/kfet/consumers.py @@ -26,11 +26,6 @@ class KPsul(JsonWebsocketConsumer): pass class KfetOpen(JsonWebsocketConsumer): - - # Set to True if you want them, else leave out - strict_ordering = False - slight_ordering = False - def connection_groups(self, **kwargs): return ['kfet.is_open'] diff --git a/kfet/decorators.py b/kfet/decorators.py index 592bf566..3dc76767 100644 --- a/kfet/decorators.py +++ b/kfet/decorators.py @@ -9,6 +9,4 @@ def kfet_is_team(user): def can_force_close(user): return user.has_perm('force_close_kfet') -teamkfet_required = user_passes_test(lambda u: kfet_is_team(u)) -force_close_required = user_passes_test(lambda u: can_force_close(u)) teamkfet_required = user_passes_test(kfet_is_team) diff --git a/kfet/static/kfet/js/kfet_open.js b/kfet/static/kfet/js/kfet_open.js index 8ea0be70..e2cccf81 100644 --- a/kfet/static/kfet/js/kfet_open.js +++ b/kfet/static/kfet/js/kfet_open.js @@ -1,4 +1,4 @@ -function kfet_open(init_date, init_satus, init_force_close, force_close_url, force_open_url) { +function kfet_open(init_date, init_status, init_force_close, force_close_url, force_open_url) { // VARIABLES var kfet_open_bullet = $('#kfet-open'); var open_status = $('#open_status'); @@ -19,15 +19,15 @@ function kfet_open(init_date, init_satus, init_force_close, force_close_url, for // EVENT force_close_button.click(forceClose); - // INITIALISAITION + // INITIALISATION update_open(); update_force_button(); - // On recherge toute les 30sec - // (dans le cas où le statut deviendrait inconn) + // On recharge toute les 30sec + // (dans le cas où le statut deviendrait inconnu) setInterval(function() { update_open(); - }, 30 * 1000); // 60 * 1000 milsec + }, 30 * 1000); // 30 * 1000 milsec // FONCTIONS function forceClose(password = '') { @@ -45,16 +45,12 @@ function kfet_open(init_date, init_satus, init_force_close, force_close_url, for $xhr.setRequestHeader("KFetPassword", password); }, }) - .done(function() {}) .fail(function($xhr) { var data = $xhr.responseJSON; switch ($xhr.status) { case 403: requestAuth({'errors':{}}, forceClose); break; - case 400: - alert('lol'); - break; } lock = 0; }); @@ -89,7 +85,7 @@ function kfet_open(init_date, init_satus, init_force_close, force_close_url, for open_status.html("?????"); } function update_open() { - nb_min = nb_min_diff(); + var nb_min = nb_min_diff(); console.log("K-Fêt ouverte : " + (kfet_open&&(!force_close))); console.log(nb_min + " minute(s) depuis la dernière mise à jour"); if (force_close) { diff --git a/kfet/urls.py b/kfet/urls.py index 718eac40..7b47d8c9 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -205,8 +205,9 @@ urlpatterns = [ url('^kfet_open/$', views.UpdateKfetOpen.as_view(), name='kfet.kfet_open'), - url('^force_close/$', - views.UpdateForceClose.as_view(), + url('^kfet_close/$', + permission_required('kfet.can_force_close') + (views.UpdateForceClose.as_view()), name='kfet.force_close'), # ----- diff --git a/kfet/views.py b/kfet/views.py index 51948de1..7865ec34 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -7,9 +7,8 @@ from django.shortcuts import render, get_object_or_404, redirect from django.core.exceptions import PermissionDenied from django.core.cache import cache from django.views.generic import ListView, DetailView, TemplateView, View -from django.views.generic.list import BaseListView, MultipleObjectTemplateResponseMixin -from django.views.generic.detail import BaseDetailView, SingleObjectTemplateResponseMixin -from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView +from django.views.generic.detail import BaseDetailView +from django.views.generic.edit import CreateView, UpdateView from django.core.urlresolvers import reverse, reverse_lazy from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin @@ -25,7 +24,7 @@ from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.decorators import method_decorator from gestioncof.models import CofProfile -from kfet.decorators import teamkfet_required, force_close_required +from kfet.decorators import teamkfet_required from kfet.models import ( Account, Checkout, Article, Settings, AccountNegative, CheckoutStatement, GenericTeamToken, Supplier, SupplierArticle, Inventory, @@ -125,12 +124,6 @@ class UpdateForceClose(View): return HttpResponse("closed : %r at %s" % (force_close_get, time.isoformat())) - @method_decorator(login_required) - @method_decorator(teamkfet_required) - @method_decorator(force_close_required) - def dispatch(self, *args, **kwargs): - return super(UpdateForceClose, self).dispatch(*args, **kwargs) - @teamkfet_required def login_genericteam(request): From 5c6a73c59733dca6e0953b181ba00ab02500967e Mon Sep 17 00:00:00 2001 From: Qwann Date: Sun, 9 Apr 2017 20:54:30 +0200 Subject: [PATCH 021/150] kfet_open uses moment.js --- kfet/context_processors.py | 2 +- kfet/static/kfet/js/kfet_open.js | 18 ++++-------------- kfet/templates/kfet/base.html | 6 +++++- kfet/templates/kfet/kpsul.html | 3 --- kfet/views.py | 2 +- 5 files changed, 11 insertions(+), 20 deletions(-) diff --git a/kfet/context_processors.py b/kfet/context_processors.py index 6c053ea9..9364c724 100644 --- a/kfet/context_processors.py +++ b/kfet/context_processors.py @@ -22,6 +22,6 @@ def kfet_open(request): kfet_force_close = KFET_FORCE_CLOSE() return { 'kfet_open': kfet_open, - 'kfet_open_date': kfet_open_date, + 'kfet_open_date': kfet_open_date.isoformat(), 'kfet_force_close': kfet_force_close, } diff --git a/kfet/static/kfet/js/kfet_open.js b/kfet/static/kfet/js/kfet_open.js index e2cccf81..a8f41757 100644 --- a/kfet/static/kfet/js/kfet_open.js +++ b/kfet/static/kfet/js/kfet_open.js @@ -56,18 +56,8 @@ function kfet_open(init_date, init_status, init_force_close, force_close_url, fo }); } - function nb_min_diff() { - var date_now = new Date(); - // On calcule le nb de minutes depuis le dernier - // envoi d'information - tmp = date_now - kfet_open_date; - - tmp = Math.floor(tmp/1000); // Nombre de secondes entre les 2 dates - diff_sec = tmp % 60; // Extraction du nombre de secondes - - tmp = Math.floor((tmp-diff_sec)/60); // Nombre de minutes (partie entière) - - return tmp; + function kfet_open_min() { + return moment().diff(kfet_open_date, 'minute') } function do_kfet_close() { kfet_open_bullet.css({'background-color': closed_color}); @@ -85,7 +75,7 @@ function kfet_open(init_date, init_status, init_force_close, force_close_url, fo open_status.html("?????"); } function update_open() { - var nb_min = nb_min_diff(); + var nb_min = kfet_open_min(); console.log("K-Fêt ouverte : " + (kfet_open&&(!force_close))); console.log(nb_min + " minute(s) depuis la dernière mise à jour"); if (force_close) { @@ -121,7 +111,7 @@ function kfet_open(init_date, init_status, init_force_close, force_close_url, fo if (data['door_action']) { console.log("* Message reçu de la part de la porte."); - kfet_open_date = new Date(data['door_action']['kfet_open_date']); + kfet_open_date = moment.utc(data['door_action']['kfet_open_date']); kfet_open = data['door_action']['kfet_open']; update_open(); diff --git a/kfet/templates/kfet/base.html b/kfet/templates/kfet/base.html index 81ca3dfd..d992b209 100644 --- a/kfet/templates/kfet/base.html +++ b/kfet/templates/kfet/base.html @@ -21,13 +21,17 @@ + + + + {# K-Fêt open #} - - - {% endblock %} diff --git a/kfet/views.py b/kfet/views.py index 7865ec34..0a3b6f99 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -97,7 +97,7 @@ class UpdateKfetOpen(View): websocket_data = { 'door_action': { 'kfet_open': is_open, - 'kfet_open_date': timezone.now(), + 'kfet_open_date': timezone.now().isoformat(), }, } consumers.KfetOpen.group_send('kfet.is_open', websocket_data) From cb9ba76a4f7bde681c92f5f030e945d8b359d652 Mon Sep 17 00:00:00 2001 From: Qwann Date: Mon, 10 Apr 2017 16:47:13 +0200 Subject: [PATCH 022/150] small fixes --- kfet/static/kfet/js/kfet_open.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kfet/static/kfet/js/kfet_open.js b/kfet/static/kfet/js/kfet_open.js index a8f41757..b6886c7b 100644 --- a/kfet/static/kfet/js/kfet_open.js +++ b/kfet/static/kfet/js/kfet_open.js @@ -57,7 +57,7 @@ function kfet_open(init_date, init_status, init_force_close, force_close_url, fo } function kfet_open_min() { - return moment().diff(kfet_open_date, 'minute') + return moment().diff(kfet_open_date, 'minute'); } function do_kfet_close() { kfet_open_bullet.css({'background-color': closed_color}); From e0b0a531125f82378a7aa0182a70d5ccfc4a5b3b Mon Sep 17 00:00:00 2001 From: Qwann Date: Mon, 10 Apr 2017 17:18:43 +0200 Subject: [PATCH 023/150] stupidness removed --- kfet/views.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index 0a3b6f99..dd4fb29a 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -68,20 +68,20 @@ class Home(TemplateView): def KFET_OPEN(): - kfet_open_date = cache.get('KFET_OPEN_DATE') - kfet_open = cache.get('KFET_OPEN') - if not kfet_open_date: + kfet_open_date = cache.get('KFET_OPEN_DATE', None) + kfet_open = cache.get('KFET_OPEN', None) + if kfet_open_date is None: kfet_open_date = timezone.now() cache.set('KFET_OPEN_DATE', kfet_open_date) - if not kfet_open: + if kfet_open is None: kfet_open = False cache.set('KFET_OPEN', kfet_open) return (kfet_open, kfet_open_date) def KFET_FORCE_CLOSE(): - kfet_force_close = cache.get('KFET_FORCE_CLOSE') - if not kfet_force_close: + kfet_force_close = cache.get('KFET_FORCE_CLOSE', None) + if kfet_force_close is None: kfet_force_close = False cache.set('KFET_FORCE_CLOSE', kfet_force_close) return kfet_force_close From be8d249ed7669cace82650856b731b3c8535113a Mon Sep 17 00:00:00 2001 From: Qwann Date: Mon, 10 Apr 2017 17:47:39 +0200 Subject: [PATCH 024/150] remove useless code --- kfet/static/kfet/js/kfet_open.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kfet/static/kfet/js/kfet_open.js b/kfet/static/kfet/js/kfet_open.js index b6886c7b..08a030a5 100644 --- a/kfet/static/kfet/js/kfet_open.js +++ b/kfet/static/kfet/js/kfet_open.js @@ -98,7 +98,6 @@ function kfet_open(init_date, init_status, init_force_close, force_close_url, fo } } // SYNCHRONIZATION - websocket_msg_default = {'last_op': 0} var websocket_protocol = window.location.protocol == 'https:' ? 'wss' : 'ws'; var location_host = window.location.host; @@ -106,7 +105,7 @@ function kfet_open(init_date, init_status, init_force_close, force_close_url, fo var socket = new ReconnectingWebSocket(websocket_protocol+"://" + location_url + "/ws/k-fet/is_open/"); socket.onmessage = function(e) { - var data = $.extend({}, websocket_msg_default, JSON.parse(e.data)); + var data = JSON.parse(e.data); if (data['door_action']) { console.log("* Message reçu de la part de la porte."); From 2c408389389a701f9e2e15ae1c23f65108d4a942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Mon, 10 Apr 2017 18:58:52 +0200 Subject: [PATCH 025/150] Add real cache support - Fix cache per process issue with a real cache system - Configuration seems too easy... but it seems to work --- provisioning/bootstrap.sh | 2 +- requirements.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index 269e4f25..e94d3ac4 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -9,7 +9,7 @@ DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" # Installation de paquets utiles apt-get update && apt-get install -y python3-pip python3-dev python3-venv \ - libmysqlclient-dev libjpeg-dev git redis-server + libmysqlclient-dev libjpeg-dev git redis-server memcached pip install -U pip # Configuration et installation de mysql. Le mot de passe root est le même que diff --git a/requirements.txt b/requirements.txt index ce081588..202f5dda 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,3 +21,4 @@ git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_customma ldap3 git+https://github.com/Aureplop/channels.git#egg=channels python-dateutil +python-memcached From ab31c20649601514a24411328021daf6a636a46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Mon, 10 Apr 2017 19:07:19 +0200 Subject: [PATCH 026/150] missing CACHES value... --- cof/settings_dev.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 18aadaad..3bc4b807 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -115,6 +115,15 @@ USE_L10N = True USE_TZ = True +# Cache system +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': '127.0.0.1:11211', + } +} + + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/ From 36771c2c4f6a3c31c0d71e26ce5f2adda8445017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Mon, 10 Apr 2017 21:36:00 +0200 Subject: [PATCH 027/150] Use redis for cache. - Cache use db #1 of redis. - Channel layer (of channels) use db #0 of redis. - `settings` try getting redis connection variables from environment. - Drop memcached system --- cof/settings_dev.py | 39 ++++++++++++++++++++++++++++----------- provisioning/bootstrap.sh | 2 +- requirements.txt | 2 +- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/cof/settings_dev.py b/cof/settings_dev.py index 3bc4b807..97b4bf7c 100644 --- a/cof/settings_dev.py +++ b/cof/settings_dev.py @@ -115,15 +115,6 @@ USE_L10N = True USE_TZ = True -# Cache system -CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', - 'LOCATION': '127.0.0.1:11211', - } -} - - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.8/howto/static-files/ @@ -176,13 +167,39 @@ RECAPTCHA_PUBLIC_KEY = "DUMMY" RECAPTCHA_PRIVATE_KEY = "DUMMY" RECAPTCHA_USE_SSL = True -# Channels settings + +# Redis settings (for cache and channel layers) + +REDIS_HOST = os.environ.get("REDIS_HOST", "localhost") +REDIS_USER = os.environ.get("REDIS_USER", "") +REDIS_PASS = os.environ.get("REDIS_PASS", "") +REDIS_PORT = os.environ.get("REDIS_PORT", "6379") + +REDIS_AUTH = REDIS_USER+":"+REDIS_PASS+"@" if REDIS_USER or REDIS_PASS else '' +REDIS_BASE_URL = "redis://" + REDIS_AUTH + REDIS_HOST + ":" + REDIS_PORT + + +# Cache settings (use db #1 of redis) + +CACHE_REDIS_URL = REDIS_BASE_URL + "/1" + +CACHES = { + 'default': { + 'BACKEND': 'redis_cache.RedisCache', + 'LOCATION': CACHE_REDIS_URL, + } +} + + +# Channels settings (use db #0 of redis) + +CHANNEL_REDIS_URL = REDIS_BASE_URL + "/0" CHANNEL_LAYERS = { "default": { "BACKEND": "asgi_redis.RedisChannelLayer", "CONFIG": { - "hosts": [(os.environ.get("REDIS_HOST", "localhost"), 6379)], + "hosts": [CHANNEL_REDIS_URL], }, "ROUTING": "cof.routing.channel_routing", } diff --git a/provisioning/bootstrap.sh b/provisioning/bootstrap.sh index e94d3ac4..269e4f25 100644 --- a/provisioning/bootstrap.sh +++ b/provisioning/bootstrap.sh @@ -9,7 +9,7 @@ DBPASSWD="4KZt3nGPLVeWSvtBZPSM3fSzXpzEU4" # Installation de paquets utiles apt-get update && apt-get install -y python3-pip python3-dev python3-venv \ - libmysqlclient-dev libjpeg-dev git redis-server memcached + libmysqlclient-dev libjpeg-dev git redis-server pip install -U pip # Configuration et installation de mysql. Le mot de passe root est le même que diff --git a/requirements.txt b/requirements.txt index 202f5dda..2012351a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ django-autoslug==1.9.3 django-cas-ng==3.5.5 django-grappelli==2.8.1 django-recaptcha==1.0.5 +django-redis-cache==1.7.1 mysqlclient==1.3.7 Pillow==3.3.0 six==1.10.0 @@ -21,4 +22,3 @@ git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_customma ldap3 git+https://github.com/Aureplop/channels.git#egg=channels python-dateutil -python-memcached From 0a21858b337c543b46d49a4cae9851dc17f86da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Fri, 14 Apr 2017 13:08:03 +0200 Subject: [PATCH 028/150] Use css for scroll positionning - Better rendering on scroll on pages with a left block (- It removes the warning on Firefox about scroll positionning) --- kfet/static/kfet/css/index.css | 7 +++++++ kfet/static/kfet/js/kfet.js | 10 ---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css index 0244a57b..ce7e0dff 100644 --- a/kfet/static/kfet/css/index.css +++ b/kfet/static/kfet/css/index.css @@ -134,6 +134,13 @@ textarea { padding:0; } +@media (min-width: 768px) { + .col-content-left { + position: sticky; + top:50px; + } +} + .content-left-top { background:#fff; padding:10px 30px; diff --git a/kfet/static/kfet/js/kfet.js b/kfet/static/kfet/js/kfet.js index cc369e32..72ae675a 100644 --- a/kfet/static/kfet/js/kfet.js +++ b/kfet/static/kfet/js/kfet.js @@ -1,14 +1,4 @@ $(document).ready(function() { - $(window).scroll(function() { - if ($(window).width() >= 768 && $(this).scrollTop() > 72.6) { - $('.col-content-left').css({'position':'fixed', 'top':'50px'}); - $('.col-content-right').addClass('col-sm-offset-4 col-md-offset-3'); - } else { - $('.col-content-left').css({'position':'relative', 'top':'0'}); - $('.col-content-right').removeClass('col-sm-offset-4 col-md-offset-3'); - } - }); - if (typeof Cookies !== 'undefined') { // Retrieving csrf token csrftoken = Cookies.get('csrftoken'); From ea81ab7b25b9819505a186c19b3505449b2e8aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sat, 15 Apr 2017 12:36:11 +0200 Subject: [PATCH 029/150] Few display improvements. - Current day remains on the screen on history. - Message for generic team user connection is sended only if user is connecting from a k-fet url. - Less contrast on history. --- kfet/signals.py | 16 +++++++++------- kfet/static/kfet/css/history.css | 5 ++++- kfet/static/kfet/css/index.css | 7 +++++-- kfet/static/kfet/css/kpsul.css | 4 ++++ kfet/templates/kfet/base_messages.html | 2 +- kfet/templates/kfet/history.html | 2 -- 6 files changed, 23 insertions(+), 13 deletions(-) diff --git a/kfet/signals.py b/kfet/signals.py index 3dd4d677..77c114e3 100644 --- a/kfet/signals.py +++ b/kfet/signals.py @@ -1,16 +1,18 @@ # -*- coding: utf-8 -*- -from __future__ import (absolute_import, division, - print_function, unicode_literals) -from builtins import * - from django.contrib import messages from django.contrib.auth.signals import user_logged_in from django.core.urlresolvers import reverse from django.dispatch import receiver + @receiver(user_logged_in) def messages_on_login(sender, request, user, **kwargs): - if (not user.username == 'kfet_genericteam' - and user.has_perm('kfet.is_team')): - messages.info(request, 'Connexion en utilisateur partagé ?' % reverse('kfet.login.genericteam'), extra_tags='safe') + if (not user.username == 'kfet_genericteam' and + user.has_perm('kfet.is_team') and + 'k-fet' in request.GET.get('next', '')): + messages.info( + request, + ('Connexion en utilisateur partagé ?' + .format(reverse('kfet.login.genericteam'))), + extra_tags='safe') diff --git a/kfet/static/kfet/css/history.css b/kfet/static/kfet/css/history.css index 976f5782..77ccaebb 100644 --- a/kfet/static/kfet/css/history.css +++ b/kfet/static/kfet/css/history.css @@ -14,12 +14,15 @@ padding-left:20px; font-size:16px; font-weight:bold; + position:sticky; + top:50px; + z-index:10; } #history .opegroup { height:30px; line-height:30px; - background-color:rgba(200,16,46,0.85); + background-color:rgba(200,16,46,0.75); color:#fff; font-weight:bold; padding-left:20px; diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css index ce7e0dff..d241e209 100644 --- a/kfet/static/kfet/css/index.css +++ b/kfet/static/kfet/css/index.css @@ -186,8 +186,11 @@ textarea { text-align:center; } -.content-right { - margin:0 15px; + +@media (min-width: 768px) { + .content-right { + margin: 0 15px; + } } .content-right-block { diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index ba88e433..3a08a3bb 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -423,3 +423,7 @@ input[type=number]::-webkit-outer-spin-button { .kpsul_middle_right_col { overflow:auto; } + +.kpsul_middle_right_col #history .day { + top: 0; +} diff --git a/kfet/templates/kfet/base_messages.html b/kfet/templates/kfet/base_messages.html index 440b8c10..3ac8512d 100644 --- a/kfet/templates/kfet/base_messages.html +++ b/kfet/templates/kfet/base_messages.html @@ -2,7 +2,7 @@
{% for message in messages %}
-
+
{% if 'safe' in message.tags %} {{ message|safe }} diff --git a/kfet/templates/kfet/history.html b/kfet/templates/kfet/history.html index ab1eef72..9e983079 100644 --- a/kfet/templates/kfet/history.html +++ b/kfet/templates/kfet/history.html @@ -14,7 +14,6 @@ - {% endblock %} @@ -30,7 +29,6 @@
opérations
-

Filtres

De
à
Caisses {{ filter_form.checkouts }}
From ce23eece6aff233f330eb4401a6e6d8eaa91c11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sat, 15 Apr 2017 13:03:01 +0200 Subject: [PATCH 030/150] Fix display on small screen devices. - Remove useless margin on small screens. - Better pills display on small screens. - Revert to transparent background for section title. --- kfet/static/kfet/css/index.css | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css index d241e209..d9c44a60 100644 --- a/kfet/static/kfet/css/index.css +++ b/kfet/static/kfet/css/index.css @@ -154,6 +154,14 @@ textarea { display:block; } +.content-left .buttons ul.nav-pills { + margin-bottom:5px; +} + +.content-left .buttons ul.nav-pills li { + margin:0 0 -5px; +} + .content-left-top.frozen-account { background:#000FBA; color:#fff; @@ -202,14 +210,6 @@ textarea { padding-bottom:15px; } -.content-right-block > div:not(.buttons-title) { - background:#fff; -} - -.content-right-block-transparent > div:not(.buttons-title) { - background-color: transparent; -} - .content-right-block .buttons-title { position:absolute; top:8px; From dbf5844f6a996399b2227f57a136a39897002673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sat, 15 Apr 2017 14:41:55 +0200 Subject: [PATCH 031/150] Clean settings redis --- cof/settings/common.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/cof/settings/common.py b/cof/settings/common.py index 98f4f713..a3b7527f 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -19,6 +19,26 @@ except ImportError: except KeyError: raise RuntimeError("Secrets missing") + +# Redis settings (for cache and channel layers) +try: + from .secret import REDIS_USER, REDIS_PASS +except ImportError: + REDIS_USER = os.environ.get("REDIS_USER", "") + REDIS_PASS = os.environ.get("REDIS_PASS", "") + +if REDIS_USER or REDIS_PASS: + REDIS_AUTH = REDIS_USER+":"+REDIS_PASS+"@" +else: + REDIS_AUTH = '' + +REDIS_HOST = os.environ.get("REDIS_HOST", "localhost") +REDIS_PORT = os.environ.get("REDIS_PORT", "6379") + +REDIS_BASE_URL = "redis://" + REDIS_AUTH + REDIS_HOST + ":" + REDIS_PORT +# To select a specific redis database, do: REDIS_BASE_URL + '/' + + # Other secrets try: from .secret import ( @@ -153,18 +173,6 @@ AUTHENTICATION_BACKENDS = ( RECAPTCHA_USE_SSL = True - -# Redis settings (for cache and channel layers) - -REDIS_HOST = os.environ.get("REDIS_HOST", "localhost") -REDIS_USER = os.environ.get("REDIS_USER", "") -REDIS_PASS = os.environ.get("REDIS_PASS", "") -REDIS_PORT = os.environ.get("REDIS_PORT", "6379") - -REDIS_AUTH = REDIS_USER+":"+REDIS_PASS+"@" if REDIS_USER or REDIS_PASS else '' -REDIS_BASE_URL = "redis://" + REDIS_AUTH + REDIS_HOST + ":" + REDIS_PORT - - # Cache settings (use db #1 of redis) CACHE_REDIS_URL = REDIS_BASE_URL + "/1" From 739990cdb698ae165c9bcfc7ed35bfc4b679ea05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Sat, 22 Apr 2017 01:17:23 +0200 Subject: [PATCH 032/150] Add total boxes to new inventory view + fix/clean - Add total boxes in cellar and bar to new inventory view. - On this view, table is "minified". - Revert background color for some templates. - Clean some margin (responsively). - Clean tab pills on account read. --- kfet/static/kfet/css/index.css | 59 +++++----- kfet/templates/kfet/account_read.html | 60 +++++----- kfet/templates/kfet/inventory_create.html | 133 ++++++++++++++-------- 3 files changed, 141 insertions(+), 111 deletions(-) diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css index d9c44a60..04bb438e 100644 --- a/kfet/static/kfet/css/index.css +++ b/kfet/static/kfet/css/index.css @@ -114,22 +114,6 @@ textarea { padding: 0 !important; } -.panel-md-margin{ - background-color: white; - overflow:hidden; - padding-left: 15px; - padding-right: 15px; - padding-bottom: 15px; - padding-top: 1px; -} - -@media (min-width: 992px) { - .panel-md-margin{ - margin:8px; - background-color: white; - } -} - .col-content-left, .col-content-right { padding:0; } @@ -194,20 +178,18 @@ textarea { text-align:center; } - @media (min-width: 768px) { .content-right { - margin: 0 15px; + margin: 15px; } } .content-right-block { - padding-bottom:5px; position:relative; } -.content-right-block:last-child { - padding-bottom:15px; +.content-right-block > div:not(.buttons-title) { + background: #fff; } .content-right-block .buttons-title { @@ -229,9 +211,8 @@ textarea { .content-right-block h3 { border-bottom: 1px solid #c8102e; - margin: 20px 15px 15px; - padding-bottom: 10px; - padding-left: 20px; + margin: 0px 15px 15px; + padding: 20px 20px 10px; font-size:25px; } @@ -239,12 +220,18 @@ textarea { * Pages tableaux seuls */ -.content-center > div { +.content-center { background:#fff; } +@media (min-width: 992px) { + .content-center { + margin: 15px; + } +} + .content-center tbody tr:not(.section) td { - padding:0px 5px !important; + padding:0px 5px; } .content-center .table .form-control { @@ -252,7 +239,15 @@ textarea { height:28px; margin:3px 0px; } - .content-center .auth-form { + +.content-center .table-condensed input.form-control { + margin: 0 !important; + border-top: 0; + border-bottom: 0; + border-radius: 0; +} + +.content-center .auth-form { margin:15px; } @@ -577,15 +572,21 @@ thead .tooltip { /* Inventaires */ +#inventoryform input[type=number] { + text-align: center; +} + .inventory_modified { background:rgba(236,100,0,0.15); } .stock_diff { padding-left: 5px; - color:#C8102E; + color:#C8102E; } .inventory_update { - display:none; + display: none; + width: 50px; + margin: 0 auto; } diff --git a/kfet/templates/kfet/account_read.html b/kfet/templates/kfet/account_read.html index b55f2b99..95df85a0 100644 --- a/kfet/templates/kfet/account_read.html +++ b/kfet/templates/kfet/account_read.html @@ -23,7 +23,7 @@ $(document).ready(function() { "{% url 'kfet.account.stat.balance.list' trigramme=account.trigramme %}", $("#stat_balance") ); - }); +}); {% endif %} {% endblock %} @@ -55,39 +55,33 @@ $(document).ready(function() {
{% include "kfet/base_messages.html" %}
-
-
- {% if account.user == request.user %} -
-
-

Statistiques

-
-

Ma balance

-
-

Ma consommation

-
-
-
-
- {% endif %} - {% if addcosts %} -

Gagné des majorations

-
-
    - {% for addcost in addcosts %} -
  • {{ addcost.date|date:'l j F' }}: +{{ addcost.sum_addcosts }}€
  • - {% endfor %} -
-
- {% endif %} -

Historique

-
- {% if account.user == request.user %} -
-
+
+ {% if account.user == request.user %} +
+

Statistiques

+
+

Ma balance

+
+

Ma consommation

+
+
+
{% endif %} -
-
+
+ {% if addcosts %} +

Gagné des majorations

+
+
    + {% for addcost in addcosts %} +
  • {{ addcost.date|date:'l j F' }}: +{{ addcost.sum_addcosts }}€
  • + {% endfor %} +
+
+ {% endif %} +

Historique

+
+
+
diff --git a/kfet/templates/kfet/inventory_create.html b/kfet/templates/kfet/inventory_create.html index d8109f8e..d1fe6e05 100644 --- a/kfet/templates/kfet/inventory_create.html +++ b/kfet/templates/kfet/inventory_create.html @@ -13,24 +13,25 @@ {% block content %} {% include 'kfet/base_messages.html' %} -
-
-
- - - - - - - - - - - - - - - {% for form in formset %} +
+
+
+ +
ArticleQuantité par caisseStock ThéoriqueCaisses en réserveCaisses en arrièreVracStock totalCompte terminé
+ + + + + + + + + + + + + + {% for form in formset %} {% ifchanged form.category %} @@ -41,42 +42,68 @@ {{ form.article }} - - + + + + + - - - - - {% endfor %} - -
ArticleQuantité par caisseStock théoriqueCaisses en réserveCaisses en arrièreVracStock totalCompte terminé
{{ form.category_name }}{{ form.name }} {{ form.box_capacity }}{{ form.stock_old }} -
-
- +
+ {{ form.stock_old }} + + + + + + + + {{ form.stock_new | attr:"readonly"| add_class:"form-control" }} + +
+ +
+
+
-
-
-
-
-
{{ form.stock_new | attr:"readonly"| add_class:"form-control" }}
-
-
- {{ formset.management_form }} - {% if not perms.kfet.add_inventory %} -
- {% include "kfet/form_authentication_snippet.html" %} -
- {% endif %} - - {% csrf_token %} -
+ {% endfor %} + + Totaux + + + + + + + + {{ formset.management_form }} + {% if not perms.kfet.add_inventory %} +
+ {% include "kfet/form_authentication_snippet.html" %} +
+ {% endif %} + + {% csrf_token %} + +
{% endblock %} diff --git a/kfet/templates/kfet/settings_update.html b/kfet/templates/kfet/settings_update.html index fdd5f5d4..b5f46c23 100644 --- a/kfet/templates/kfet/settings_update.html +++ b/kfet/templates/kfet/settings_update.html @@ -5,21 +5,6 @@ {% block content %} -{% include "kfet/base_messages.html" %} - -
-
-
-
- {% csrf_token %} - {% include 'kfet/form_snippet.html' with form=form %} - {% if not perms.kfet.change_settings %} - {% include 'kfet/form_authentication_snippet.html' %} - {% endif %} - {% include 'kfet/form_submit_snippet.html' with value="Mettre à jour" %} -
-
-
-
+{% include "kfet/base_form.html" with authz=perms.kfet.change_settings submit_text="Mettre à jour"%} {% endblock %} diff --git a/kfet/templates/kfet/supplier_form.html b/kfet/templates/kfet/supplier_form.html index 168f74d9..434b9382 100644 --- a/kfet/templates/kfet/supplier_form.html +++ b/kfet/templates/kfet/supplier_form.html @@ -1,27 +1,10 @@ {% extends 'kfet/base.html' %} -{% load widget_tweaks %} -{% load staticfiles %} {% block title %}Fournisseur - Modification{% endblock %} {% block content-header-title %}Fournisseur - Modification{% endblock %} {% block content %} -{% include 'kfet/base_messages.html' %} - -
-
-
-
- {% csrf_token %} - {% include 'kfet/form_snippet.html' with form=form %} - {% if not perms.kfet.change_supplier %} - {% include 'kfet/form_authentication_snippet.html' %} - {% endif %} - {% include 'kfet/form_submit_snippet.html' with value="Mettre à jour" %} -
-
-
-
+{% include 'kfet/base_form.html' with authz=perms.kfet.change_supplier submit_text="Mettre à jour" %} {% endblock %} diff --git a/kfet/views.py b/kfet/views.py index 60dbb44b..7b1674c4 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -85,6 +85,8 @@ def login_genericteam(request): user = authenticate(username="kfet_genericteam", token=token.token) login(request, user) + messages.success(request, "Connecté en utilisateur partagé") + if need_cas_logout: # Vue de déconnexion de CAS return logout_cas @@ -514,6 +516,10 @@ def account_update(request, trigramme): return render(request, "kfet/account_update.html", { 'account': account, + 'forms': [ + user_form, cof_form, account_form, group_form, pwd_form, + negative_form, + ], 'account_form': account_form, 'cof_form': cof_form, 'user_form': user_form, From 1a661c1fd3d784a2c784ab2ff8d90442871f004a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Thu, 18 May 2017 20:29:29 +0200 Subject: [PATCH 035/150] revert --- kfet/views.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index 7b1674c4..fa94bb35 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -516,10 +516,6 @@ def account_update(request, trigramme): return render(request, "kfet/account_update.html", { 'account': account, - 'forms': [ - user_form, cof_form, account_form, group_form, pwd_form, - negative_form, - ], 'account_form': account_form, 'cof_form': cof_form, 'user_form': user_form, From e9073e22654a9908c86854f9bc04ad270a4429bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Thu, 18 May 2017 21:41:23 +0200 Subject: [PATCH 036/150] Improve multiple select inputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Group edition form gains success message, is prettier + Fix: K-Fêt prefix for group name on this form --- kfet/static/kfet/css/index.css | 13 +++++ kfet/templates/kfet/account_group_form.html | 59 +++++++++++++++------ kfet/templates/kfet/base_form.html | 2 +- kfet/templates/kfet/history.html | 3 ++ kfet/views.py | 2 +- 5 files changed, 60 insertions(+), 19 deletions(-) diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css index 50d2cae8..4fc02014 100644 --- a/kfet/static/kfet/css/index.css +++ b/kfet/static/kfet/css/index.css @@ -595,3 +595,16 @@ thead .tooltip { width: 50px; margin: 0 auto; } + +/* Multiple select customizations */ + +.ms-choice { + height: 34px !important; + line-height: 34px !important; + border: 1px solid #ccc !important; + box-shadow: inset 0 1px 1px rgba(0,0,0,.075) !important; +} + +.ms-choice > div { + top: 4px !important; +} diff --git a/kfet/templates/kfet/account_group_form.html b/kfet/templates/kfet/account_group_form.html index e37bdd89..00e7809b 100644 --- a/kfet/templates/kfet/account_group_form.html +++ b/kfet/templates/kfet/account_group_form.html @@ -1,37 +1,62 @@ {% extends 'kfet/base.html' %} {% load staticfiles %} +{% load widget_tweaks %} {% block extra_head %} {% endblock %} +{% block title %}Permissions - Édition{% endblock %} +{% block content-header-title %}Modification des permissions{% endblock %} + {% block content %} -
- {% csrf_token %} -
- {{ form.name.errors }} - {{ form.name.label_tag }} -
- K-Fêt - {{ form.name }} +{% include "kfet/base_messages.html" %} + +
+
+
+ + {% csrf_token %} +
+ +
+
+ K-Fêt + {{ form.name|add_class:"form-control" }} +
+ {% if form.name.errors %}{{ form.name.errors }}{% endif %} + {% if form.name.help_text %}{{ form.name.help_text }}{% endif %} +
+
+ {% include "kfet/form_field_snippet.html" with field=form.permissions %} + {% if not perms.kfet.manage_perms %} + {% include "kfet/form_authentication_snippet.html" %} + {% endif %} + {% include "kfet/form_submit_snippet.html" with value="Enregistrer" %} +
-
- {{ form.permissions.errors }} - {{ form.permissions.label_tag }} - {{ form.permissions }} -
- - +
diff --git a/kfet/templates/kfet/base_form.html b/kfet/templates/kfet/base_form.html index b83e888a..ba6a84ac 100644 --- a/kfet/templates/kfet/base_form.html +++ b/kfet/templates/kfet/base_form.html @@ -3,7 +3,7 @@
-
+ {% csrf_token %} {% include "kfet/form_snippet.html" %} {% if not authz %} diff --git a/kfet/templates/kfet/history.html b/kfet/templates/kfet/history.html index 9e983079..add461ab 100644 --- a/kfet/templates/kfet/history.html +++ b/kfet/templates/kfet/history.html @@ -128,6 +128,9 @@ $(document).ready(function() { $("select").multipleSelect({ width: '100%', filter: true, + allSelected: " ", + selectAllText: "Tout-te-s", + countSelected: "# sur %" }); $("input").on('dp.change change', function() { diff --git a/kfet/views.py b/kfet/views.py index fa94bb35..0cce165e 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -539,7 +539,7 @@ class AccountGroupCreate(SuccessMessageMixin, CreateView): success_message = 'Nouveau groupe : %(name)s' success_url = reverse_lazy('kfet.account.group') -class AccountGroupUpdate(UpdateView): +class AccountGroupUpdate(SuccessMessageMixin, UpdateView): queryset = Group.objects.filter(name__icontains='K-Fêt') template_name = 'kfet/account_group_form.html' form_class = GroupForm From ae270656264da08afe911d3cd3ffa551a7ce117c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Fri, 19 May 2017 13:42:41 +0200 Subject: [PATCH 037/150] Group permissions select multiple -> checkboxes - Add handler for CheckboxSelectMultiple in form_field_snippet.html. - Add template filter "widget_type" to get widget class name. - Group permissions selection becomes easier. --- kfet/forms.py | 23 +++++++++++++++++---- kfet/static/kfet/css/index.css | 7 +++++++ kfet/templates/kfet/account_group_form.html | 10 --------- kfet/templates/kfet/form_field_snippet.html | 14 ++++++++++++- kfet/templatetags/kfet_tags.py | 7 +++++-- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/kfet/forms.py b/kfet/forms.py index f89b8f08..296ed4ae 100644 --- a/kfet/forms.py +++ b/kfet/forms.py @@ -8,7 +8,7 @@ from django.core.exceptions import ValidationError from django.core.validators import MinLengthValidator from django.contrib.auth.models import User, Group, Permission from django.contrib.contenttypes.models import ContentType -from django.forms import modelformset_factory +from django.forms import modelformset_factory, widgets from django.utils import timezone from djconfig.forms import ConfigForm @@ -151,10 +151,25 @@ class UserGroupForm(forms.ModelForm): model = User fields = ['groups'] + +class KFetPermissionsField(forms.ModelMultipleChoiceField): + + def __init__(self, *args, **kwargs): + queryset = Permission.objects.filter( + content_type__in=ContentType.objects.filter(app_label="kfet"), + ) + super().__init__( + queryset=queryset, + widget=widgets.CheckboxSelectMultiple, + *args, **kwargs + ) + + def label_from_instance(self, obj): + return obj.name + + class GroupForm(forms.ModelForm): - permissions = forms.ModelMultipleChoiceField( - queryset= Permission.objects.filter(content_type__in= - ContentType.objects.filter(app_label='kfet'))) + permissions = KFetPermissionsField() def clean_name(self): name = self.cleaned_data['name'] diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css index 4fc02014..036e725e 100644 --- a/kfet/static/kfet/css/index.css +++ b/kfet/static/kfet/css/index.css @@ -608,3 +608,10 @@ thead .tooltip { .ms-choice > div { top: 4px !important; } + +/* Checkbox select multiple */ + +.checkbox-select-multiple label { + font-weight: normal; + margin-bottom: 0; +} diff --git a/kfet/templates/kfet/account_group_form.html b/kfet/templates/kfet/account_group_form.html index 00e7809b..52b99934 100644 --- a/kfet/templates/kfet/account_group_form.html +++ b/kfet/templates/kfet/account_group_form.html @@ -42,16 +42,6 @@ {% endblock %} -{% block content-header-title %}Création d'un compte{% endblock %} +{% block main-class %}content-form{% endblock %} -{% block content %} +{% block main-content %} -{% include 'kfet/base_messages.html' %} - -
-
-
- - {% csrf_token %} -
- {{ trigramme_form.trigramme.errors }} - {{ trigramme_form.trigramme }} -
-
-

Les mots contenant des caractères non alphanumériques seront ignorés

- -
-
-
-
-
- {% include 'kfet/account_create_form.html' %} -
- {% if not perms.kfet.add_account %} - {% include 'kfet/form_authentication_snippet.html' %} - {% endif %} -
- -
+
+
+

Les mots contenant des caractères non alphanumériques seront ignorés

+ +
+
+
+
+
+ {% include 'kfet/account_create_form.html' %} +
+ {% if not perms.kfet.add_account %} + {% include 'kfet/form_authentication_snippet.html' %} + {% endif %} +
+ + {% endblock %} -{% block content-header-title %}Création d'un compte{% endblock %} +{% block main-class %}content-form{% endblock %} -{% block content %} +{% block main-content %} -
-
- {% include 'kfet/base_messages.html' %} -
- -
+
+
+ +
+
+
+
+
+ {% include 'kfet/account_create_form.html' %} +
+ {% if not perms.kfet.add_account %} + {% include 'kfet/form_authentication_snippet.html' %} + {% endif %} +
+ {% endblock %} -{% block title %}Informations sur l'article {{ article }}{% endblock %} -{% block content-header-title %}Article - {{ article.name }}{% endblock %} +{% block title %}Article - {{ article.name }}{% endblock %} +{% block header-title %}Informations sur l'article {{ article.name }}{% endblock %} -{% block content %} +{% block fixed-content %} -
-
-
-
-
{{ article.name }}
-
{{ article.category }}
-
-
Prix (hors réduc.): {{ article.price }}€
-
Stock: {{ article.stock }}
-
En vente: {{ article.is_sold | yesno:"Oui,Non" }}
-
Affiché: {{ article.hidden | yesno:"Non,Oui" }}
-
-
- -
+
+
{{ article.name }}
+
{{ article.category }}
+
+
Prix (hors réduc.): {{ article.price }}€
+
Stock: {{ article.stock }}
+
En vente: {{ article.is_sold | yesno:"Oui,Non" }}
+
Affiché: {{ article.hidden | yesno:"Non,Oui" }}
-
- {% include 'kfet/base_messages.html' %} -
-
-

Historique

-
-
-

Inventaires

- - - - - - - - - - {% for inventoryart in inventoryarts %} - - - - - - {% endfor %} - -
DateStockErreur
{{ inventoryart.inventory.at }}{{ inventoryart.stock_new }}{{ inventoryart.stock_error }}
-
-
-

Prix fournisseurs

- - - - - - - - - - - - {% for supplierart in supplierarts %} - - - - - - - - {% endfor %} - -
DateFournisseurHTTVADroits
{{ supplierart.at }}{{ supplierart.supplier.name }}{{ supplierart.price_HT }}{{ supplierart.TVA }}{{ supplierart.rights }}
-
-
-
-
-

Statistiques

-
-
-
-

Ventes de {{ article.name }}

-
-
-
-
+
+ + +{% endblock %} + +{% block main-content %} + +
+

Historique

+
+
+

Inventaires

+ + + + + + + + + + {% for inventoryart in inventoryarts %} + + + + + + {% endfor %} + +
DateStockErreur
{{ inventoryart.inventory.at }}{{ inventoryart.stock_new }}{{ inventoryart.stock_error }}
+
+
+

Prix fournisseurs

+
+ + + + + + + + + + + + {% for supplierart in supplierarts %} + + + + + + + + {% endfor %} + +
DateFournisseurHTTVADroits
{{ supplierart.at }}{{ supplierart.supplier.name }}{{ supplierart.price_HT }}{{ supplierart.TVA }}{{ supplierart.rights }}
+
+
+
+

Statistiques

+
+

Ventes

+
diff --git a/kfet/templates/kfet/article_update.html b/kfet/templates/kfet/article_update.html index 65ccec3b..d451df94 100644 --- a/kfet/templates/kfet/article_update.html +++ b/kfet/templates/kfet/article_update.html @@ -1,9 +1,11 @@ -{% extends 'kfet/base.html' %} +{% extends "kfet/base_col_1.html" %} -{% block title %}Édition de l'article {{ article.name }}{% endblock %} -{% block content-header-title %}Article {{ article.name }} - Édition{% endblock %} +{% block title %}{{ article.name }} - Édition{% endblock %} +{% block header-title %}Édition de l'article {{ article.name }}{% endblock %} -{% block content %} +{% block main-class %}content-form{% endblock %} + +{% block main-content %} {% include "kfet/base_form.html" with authz=perms.kfet.change_article submit_text="Mettre à jour"%} diff --git a/kfet/templates/kfet/base.html b/kfet/templates/kfet/base.html index 173a5fb7..da37abae 100644 --- a/kfet/templates/kfet/base.html +++ b/kfet/templates/kfet/base.html @@ -30,12 +30,12 @@ {% include "kfet/base_nav.html" %}
- {% block content-header %} -
-
-

{% block content-header-title %}{% endblock %}

-
+ {% block header %} +
+
+

{% block header-title %}{% endblock %}

+
{% endblock %} {% block content %}{% endblock %} {% include "kfet/base_footer.html" %} diff --git a/kfet/templates/kfet/base_col_1.html b/kfet/templates/kfet/base_col_1.html new file mode 100644 index 00000000..a4c26b82 --- /dev/null +++ b/kfet/templates/kfet/base_col_1.html @@ -0,0 +1,14 @@ +{% extends "kfet/base.html" %} + +{% block content %} + +
+
+ {% include "kfet/base_messages.html" %} +
+ {% block main-content %}{% endblock %} +
+
+
+ +{% endblock %} diff --git a/kfet/templates/kfet/base_col_2.html b/kfet/templates/kfet/base_col_2.html new file mode 100644 index 00000000..58c36d14 --- /dev/null +++ b/kfet/templates/kfet/base_col_2.html @@ -0,0 +1,19 @@ +{% extends "kfet/base.html" %} + +{% block content %} + +
+
+
+ {% block fixed-content %}{% endblock %} +
+
+
+ {% include "kfet/base_messages.html" %} +
+ {% block main-content %}{% endblock %} +
+
+
+ +{% endblock %} diff --git a/kfet/templates/kfet/base_form.html b/kfet/templates/kfet/base_form.html index 9fe79e32..1ac4c81b 100644 --- a/kfet/templates/kfet/base_form.html +++ b/kfet/templates/kfet/base_form.html @@ -1,17 +1,10 @@ {% load kfet_tags %} -
-
- {% include "kfet/base_messages.html" %} -
-
- {% csrf_token %} - {% include "kfet/form_snippet.html" %} - {% if not authz %} - {% include "kfet/form_authentication_snippet.html" %} - {% endif %} - {% include "kfet/form_submit_snippet.html" with value=submit_text %} -
-
-
-
+
+ {% csrf_token %} + {% include "kfet/form_snippet.html" %} + {% if not authz %} + {% include "kfet/form_authentication_snippet.html" %} + {% endif %} + {% include "kfet/form_submit_snippet.html" with value=submit_text %} +
diff --git a/kfet/templates/kfet/category.html b/kfet/templates/kfet/category.html index 5393bf59..b7797c49 100644 --- a/kfet/templates/kfet/category.html +++ b/kfet/templates/kfet/category.html @@ -1,52 +1,46 @@ -{% extends 'kfet/base.html' %} +{% extends "kfet/base_col_2.html" %} {% block title %}Categories d'articles{% endblock %} -{% block content-header-title %}Categories d'articles{% endblock %} +{% block header-title %}Categories d'articles{% endblock %} -{% block content %} +{% block fixed-content %} -
-
-
-
-
{{ categories|length }}
-
catégorie{{ categories|length|pluralize }}
-
-
-
-
- {% include 'kfet/base_messages.html' %} -
-
-

Liste des catégories

-
- - - - - - - - - - - {% for category in categories %} - - - - - - - {% endfor %} - -
NomNombre d'articlesPeut être majorée
- - - - {{ category.name }}{{ category.articles.all|length }}{{ category.has_addcost | yesno:"Oui,Non"}}
-
-
-
+
+
{{ categories|length }}
+
catégorie{{ categories|length|pluralize }}
+
+ +{% endblock %} + +{% block main-content %} + +
+

Liste des catégories

+
+ + + + + + + + + + + {% for category in categories %} + + + + + + + {% endfor %} + +
NomNombre d'articlesPeut être majorée
+ + + + {{ category.name }}{{ category.articles.all|length }}{{ category.has_addcost | yesno:"Oui,Non"}}
diff --git a/kfet/templates/kfet/category_update.html b/kfet/templates/kfet/category_update.html index af213e71..c535a31d 100644 --- a/kfet/templates/kfet/category_update.html +++ b/kfet/templates/kfet/category_update.html @@ -1,9 +1,11 @@ -{% extends 'kfet/base.html' %} +{% extends "kfet/base_col_1.html" %} -{% block title %}Édition de la catégorie {{ category.name }}{% endblock %} -{% block content-header-title %}Catégorie {{ category.name }} - Édition{% endblock %} +{% block title %}{{ articlecategory.name }} - Édition{% endblock %} +{% block header-title %}Édition de la catégorie {{ articlecategory.name }}{% endblock %} -{% block content %} +{% block main-class %}content-form{% endblock %} + +{% block main-content %} {% include "kfet/base_form.html" with authz=perms.kfet.edit_articlecategory submit_text="Enregistrer"%} diff --git a/kfet/templates/kfet/checkout.html b/kfet/templates/kfet/checkout.html index fb2d10a7..329b8bef 100644 --- a/kfet/templates/kfet/checkout.html +++ b/kfet/templates/kfet/checkout.html @@ -1,59 +1,53 @@ -{% extends "kfet/base.html" %} +{% extends "kfet/base_col_2.html" %} -{% block title %}Liste des caisses{% endblock %} -{% block content-header-title %}Caisses{% endblock %} +{% block title %}Caisses{% endblock %} +{% block header-title %}Caisses{% endblock %} -{% block content %} +{% block fixed-content %} -
-
-
-
-
{{ checkouts|length }}
-
caisse{{ checkouts|length|pluralize }}
-
- -
-
-
- {% include 'kfet/base_messages.html' %} -
-
-

Liste des caisses

-
- - - - - - - - - - - - - {% for checkout in checkouts %} - - - - - - - - - {% endfor %} - -
NomBalanceDéb. valid.Fin valid.Protégée
- - - - {{ checkout.name }}{{ checkout.balance}}€{{ checkout.valid_from }}{{ checkout.valid_to }}{{ checkout.is_protected }}
-
-
-
+
+
{{ checkouts|length }}
+
caisse{{ checkouts|length|pluralize }}
+
+ + +{% endblock %} + +{% block main-content %} + +
+

Liste des caisses

+
+ + + + + + + + + + + + + {% for checkout in checkouts %} + + + + + + + + + {% endfor %} + +
NomBalanceDéb. valid.Fin valid.Protégée
+ + + + {{ checkout.name }}{{ checkout.balance}}€{{ checkout.valid_from }}{{ checkout.valid_to }}{{ checkout.is_protected }}
diff --git a/kfet/templates/kfet/checkout_create.html b/kfet/templates/kfet/checkout_create.html index 0f254f65..bed1b6ef 100644 --- a/kfet/templates/kfet/checkout_create.html +++ b/kfet/templates/kfet/checkout_create.html @@ -1,28 +1,13 @@ -{% extends "kfet/base.html" %} +{% extends "kfet/base_col_1.html" %} {% block extra_head %}{{ form.media }}{% endblock %} {% block title %}Nouvelle caisse{% endblock %} -{% block content-header-title %}Création d'une caisse{% endblock %} +{% block header-title %}Création d'une caisse{% endblock %} -{% block content %} +{% block main-class %}content-form{% endblock %} +{% block main-content %} -{% include 'kfet/base_messages.html' %} -
- {% csrf_token %} - {{ form.non_field_errors}} - {% for field in form %} - {{ field.errors }} - {{ field.label_tag }} -
{{ field }}
- {% if field.help_text %} -

{{ field.help_text|safe }}

- {% endif %} - {% endfor %} - {% if not perms.kfet.add_checkout %} - - {% endif %} - -
+{% include "kfet/base_form.html" with authz=perms.kfet.add_checkout submit_text="Enregistrer" %} {% block extra_head %}{% endblock %} diff --git a/gestioncof/templates/gestioncof/banner_update.html b/gestioncof/templates/gestioncof/banner_update.html new file mode 100644 index 00000000..b2432eae --- /dev/null +++ b/gestioncof/templates/gestioncof/banner_update.html @@ -0,0 +1,23 @@ +{% extends "base_title.html" %} +{% load bootstrap %} +{% load i18n %} + +{% block page_size %}col-sm-8{%endblock%} + +{% block realcontent %} +

{% trans "Global configuration" %}

+
+
+ {% csrf_token %} + + {% for field in form %} + {{ field | bootstrap }} + {% endfor %} + +
+
+ +
+
+{% endblock %} diff --git a/gestioncof/templates/gestioncof/base_header.html b/gestioncof/templates/gestioncof/base_header.html index a7e29eb7..21441875 100644 --- a/gestioncof/templates/gestioncof/base_header.html +++ b/gestioncof/templates/gestioncof/base_header.html @@ -16,6 +16,14 @@

{% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}, {% if user.profile.is_cof %}au COF{% else %}non-COF{% endif %}

+ +{% if config.gestion_banner %} + +{% endif %} + {% if messages %} {% for message in messages %}
diff --git a/gestioncof/views.py b/gestioncof/views.py index 6a728ea6..f98c51df 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -10,6 +10,8 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.views import login as django_login_view from django.contrib.auth.models import User from django.contrib.sites.models import Site +from django.core.urlresolvers import reverse_lazy +from django.views.generic import FormView from django.utils import timezone from django.contrib import messages @@ -21,10 +23,11 @@ from gestioncof.models import EventCommentField, EventCommentValue, \ CalendarSubscription from gestioncof.models import CofProfile, Club from gestioncof.decorators import buro_required, cof_required -from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \ - SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \ - RegistrationProfileForm, EventForm, CalendarForm, EventFormset, \ - RegistrationPassUserForm, ClubsForm +from gestioncof.forms import ( + UserProfileForm, EventStatusFilterForm, SurveyForm, SurveyStatusFilterForm, + RegistrationUserForm, RegistrationProfileForm, EventForm, CalendarForm, + EventFormset, RegistrationPassUserForm, ClubsForm, GestioncofConfigForm +) from bda.models import Tirage, Spectacle @@ -758,3 +761,18 @@ def calendar_ics(request, token): response = HttpResponse(content=vcal.to_ical()) response['Content-Type'] = "text/calendar" return response + + +class ConfigUpdate(FormView): + form_class = GestioncofConfigForm + template_name = "gestioncof/banner_update.html" + success_url = reverse_lazy("home") + + def dispatch(self, request, *args, **kwargs): + if request.user is None or not request.user.is_superuser: + raise Http404 + return super().dispatch(request, *args, **kwargs) + + def form_valid(self, form): + form.save() + return super().form_valid(form) diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index ba88e433..da1cffa1 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -18,6 +18,17 @@ input[type=number]::-webkit-outer-spin-button { 100% { background: yellow; } } +/* Announcements banner */ + +#banner { + background-color: #d86b01; + width: 100%; + text-align: center; + padding: 10px; + color: white; + font-size: larger; +} + /* * Top row */ diff --git a/kfet/templates/kfet/base_messages.html b/kfet/templates/kfet/base_messages.html index 440b8c10..3af19b31 100644 --- a/kfet/templates/kfet/base_messages.html +++ b/kfet/templates/kfet/base_messages.html @@ -1,3 +1,10 @@ +{% if config.gestion_banner %} + +{% endif %} + {% if messages %}
{% for message in messages %} From 8c6d56b27c405bf4cf81140a55fb1550b26cc030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Delobelle?= Date: Tue, 30 May 2017 20:44:30 +0200 Subject: [PATCH 057/150] Add Wagtail CMS for kfet app. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit K-Fêt - Integrate wagtail to serve "static" pages of old K-Fêt website - Fixture "kfetcms/kfet_wagtail_17_05" contains a copy of old website (as in May 2017). - Media files can be got until end of June 17 at http://partage.eleves.ens.fr//files/604e6dea2ceebc66b1936c6b3f911744/kfet_media.tar.gz Login/logout - Update package django_cas_ng to last version. - Clean COFCASBackend. - Change CAS version to 3 (version used on eleves.ens). This enables the logout redirection (for CAS ofc). - Add messages and clean existing ones on login/logout (for both outsider and cas users). Misc - Update settings to bypass an incompability between debug-toolbar and wagtailmenus packages. - Better management of dev/test-specific urls (if debug-toolbar wasn't in INSTALLED_APPS, media files were not served). - UI improvements. --- README.md | 2 +- cof/settings/common.py | 28 + cof/settings/dev.py | 20 + cof/urls.py | 14 +- gestioncof/__init__.py | 1 + gestioncof/apps.py | 8 + gestioncof/shared.py | 58 +- gestioncof/signals.py | 23 + gestioncof/templates/home.html | 4 +- gestioncof/views.py | 29 +- kfet/cms/__init__.py | 1 + kfet/cms/apps.py | 7 + kfet/cms/context_processors.py | 20 + kfet/cms/fixtures/kfet_wagtail_17_05.json | 1565 +++++++++++++++++ .../management/commands/kfet_loadwagtail.py | 35 + kfet/cms/migrations/0001_initial.py | 75 + kfet/cms/migrations/__init__.py | 0 kfet/cms/models.py | 165 ++ kfet/cms/static/kfetcms/css/index.css | 155 ++ kfet/cms/templates/kfetcms/base.html | 68 + kfet/cms/templates/kfetcms/carte.html | 46 + kfet/cms/templates/kfetcms/equipe.html | 67 + kfet/management/commands/loadkfetdevdata.py | 6 + kfet/models.py | 10 +- kfet/signals.py | 12 +- kfet/static/kfet/css/footer.css | 19 + kfet/static/kfet/css/history.css | 5 +- kfet/static/kfet/css/home.css | 74 +- kfet/static/kfet/css/index.css | 274 ++- kfet/static/kfet/css/jconfirm-kfet.css | 5 +- kfet/static/kfet/css/kpsul.css | 33 +- kfet/static/kfet/css/nav.css | 117 +- kfet/static/kfet/img/favicon.png | Bin 0 -> 3606 bytes kfet/static/kfet/js/statistic.js | 1 - kfet/templates/kfet/account.html | 33 +- kfet/templates/kfet/account_group.html | 8 +- kfet/templates/kfet/account_negative.html | 14 +- kfet/templates/kfet/account_read.html | 4 + kfet/templates/kfet/account_update.html | 6 + kfet/templates/kfet/article.html | 19 +- kfet/templates/kfet/article_read.html | 57 +- kfet/templates/kfet/base.html | 27 +- kfet/templates/kfet/base_col_1.html | 4 +- kfet/templates/kfet/base_col_2.html | 4 +- kfet/templates/kfet/base_footer.html | 17 + kfet/templates/kfet/base_messages.html | 18 +- kfet/templates/kfet/base_nav.html | 147 +- kfet/templates/kfet/category.html | 8 +- kfet/templates/kfet/checkout.html | 15 +- kfet/templates/kfet/checkout_read.html | 13 +- kfet/templates/kfet/home.html | 59 - kfet/templates/kfet/inventory.html | 13 +- kfet/templates/kfet/inventory_create.html | 4 +- kfet/templates/kfet/inventory_read.html | 6 +- kfet/templates/kfet/kpsul.html | 32 +- kfet/templates/kfet/left_account.html | 39 +- kfet/templates/kfet/left_checkout.html | 17 +- kfet/templates/kfet/nav_item.html | 18 + kfet/templates/kfet/order.html | 14 +- kfet/templates/kfet/order_create.html | 4 +- kfet/templates/kfet/order_read.html | 23 +- kfet/templates/kfet/order_to_inventory.html | 10 +- kfet/templates/kfet/settings.html | 4 +- kfet/templates/kfet/transfers.html | 4 +- kfet/urls.py | 7 +- kfet/views.py | 57 +- requirements.txt | 4 +- 67 files changed, 3038 insertions(+), 618 deletions(-) create mode 100644 gestioncof/apps.py create mode 100644 gestioncof/signals.py create mode 100644 kfet/cms/__init__.py create mode 100644 kfet/cms/apps.py create mode 100644 kfet/cms/context_processors.py create mode 100644 kfet/cms/fixtures/kfet_wagtail_17_05.json create mode 100644 kfet/cms/management/commands/kfet_loadwagtail.py create mode 100644 kfet/cms/migrations/0001_initial.py create mode 100644 kfet/cms/migrations/__init__.py create mode 100644 kfet/cms/models.py create mode 100644 kfet/cms/static/kfetcms/css/index.css create mode 100644 kfet/cms/templates/kfetcms/base.html create mode 100644 kfet/cms/templates/kfetcms/carte.html create mode 100644 kfet/cms/templates/kfetcms/equipe.html create mode 100644 kfet/static/kfet/css/footer.css create mode 100644 kfet/static/kfet/img/favicon.png delete mode 100644 kfet/templates/kfet/home.html create mode 100644 kfet/templates/kfet/nav_item.html diff --git a/README.md b/README.md index 1a3d575e..b6017577 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,7 @@ Charger les mails indispensables au bon fonctionnement de GestioCOF : Une base de donnée pré-remplie est disponible en lançant les commandes : - python manage.py loaddata gestion sites accounts groups articles + python manage.py loaddata gestion sites articles python manage.py loaddevdata Vous êtes prêts à développer ! Lancer GestioCOF en faisant diff --git a/cof/settings/common.py b/cof/settings/common.py index 261760d6..f7c7bba6 100644 --- a/cof/settings/common.py +++ b/cof/settings/common.py @@ -56,6 +56,22 @@ INSTALLED_APPS = [ 'widget_tweaks', 'custommail', 'djconfig', + 'wagtail.wagtailforms', + 'wagtail.wagtailredirects', + 'wagtail.wagtailembeds', + 'wagtail.wagtailsites', + 'wagtail.wagtailusers', + 'wagtail.wagtailsnippets', + 'wagtail.wagtaildocs', + 'wagtail.wagtailimages', + 'wagtail.wagtailsearch', + 'wagtail.wagtailadmin', + 'wagtail.wagtailcore', + 'wagtail.contrib.modeladmin', + 'wagtailmenus', + 'modelcluster', + 'taggit', + 'kfet.cms', ] MIDDLEWARE_CLASSES = [ @@ -69,6 +85,8 @@ MIDDLEWARE_CLASSES = [ 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', 'djconfig.middleware.DjConfigMiddleware', + 'wagtail.wagtailcore.middleware.SiteMiddleware', + 'wagtail.wagtailredirects.middleware.RedirectMiddleware', ] ROOT_URLCONF = 'cof.urls' @@ -87,6 +105,7 @@ TEMPLATES = [ 'django.core.context_processors.i18n', 'django.core.context_processors.media', 'django.core.context_processors.static', + 'wagtailmenus.context_processors.wagtailmenus', 'djconfig.context_processors.config', 'gestioncof.shared.context_processor', 'kfet.context_processors.auth', @@ -143,9 +162,12 @@ LOGIN_URL = "cof-login" LOGIN_REDIRECT_URL = "home" CAS_SERVER_URL = 'https://cas.eleves.ens.fr/' +CAS_VERSION = '3' +CAS_LOGIN_MSG = None CAS_IGNORE_REFERER = True CAS_REDIRECT_URL = '/' CAS_EMAIL_FORMAT = "%s@clipper.ens.fr" + AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', 'gestioncof.shared.COFCASBackend', @@ -171,3 +193,9 @@ CHANNEL_LAYERS = { } FORMAT_MODULE_PATH = 'cof.locale' + +# Wagtail settings + +WAGTAIL_SITE_NAME = 'GestioCOF' +WAGTAIL_ENABLE_UPDATE_CHECK = False +TAGGIT_CASE_INSENSITIVE = True diff --git a/cof/settings/dev.py b/cof/settings/dev.py index a3a17f99..ffd34c7d 100644 --- a/cof/settings/dev.py +++ b/cof/settings/dev.py @@ -28,6 +28,26 @@ MEDIA_URL = '/media/' # Debug tool bar # --- +# "Versions" panel of django-debug-toolbar <=1.8 is not compatible with +# wagtailmenus. +# See https://github.com/jazzband/django-debug-toolbar/issues/922 +# TODO: Bug should be fixed in ddt 1.9 (not released yet). When fixed, this +# declaration may be removed. +DEBUG_TOOLBAR_PANELS = [ + 'debug_toolbar.panels.timer.TimerPanel', + 'debug_toolbar.panels.settings.SettingsPanel', + 'debug_toolbar.panels.headers.HeadersPanel', + 'debug_toolbar.panels.request.RequestPanel', + 'debug_toolbar.panels.sql.SQLPanel', + 'debug_toolbar.panels.staticfiles.StaticFilesPanel', + 'debug_toolbar.panels.templates.TemplatesPanel', + 'debug_toolbar.panels.cache.CachePanel', + 'debug_toolbar.panels.signals.SignalsPanel', + 'debug_toolbar.panels.logging.LoggingPanel', + 'debug_toolbar.panels.redirects.RedirectsPanel', +] + + def show_toolbar(request): """ On ne veut pas la vérification de INTERNAL_IPS faite par la debug-toolbar diff --git a/cof/urls.py b/cof/urls.py index 06b1087a..886070e9 100644 --- a/cof/urls.py +++ b/cof/urls.py @@ -14,6 +14,10 @@ from django.views.generic.base import TemplateView from django.contrib.auth import views as django_views from django_cas_ng import views as django_cas_views +from wagtail.wagtailadmin import urls as wagtailadmin_urls +from wagtail.wagtailcore import urls as wagtail_urls +from wagtail.wagtaildocs import urls as wagtaildocs_urls + from gestioncof import views as gestioncof_views, csv_views from gestioncof.urls import export_patterns, petitcours_patterns, \ surveys_patterns, events_patterns, calendar_patterns, \ @@ -48,7 +52,7 @@ urlpatterns = [ url(r'^outsider/login$', gestioncof_views.login_ext), url(r'^outsider/logout$', django_views.logout, {'next_page': 'home'}), url(r'^login$', gestioncof_views.login, name="cof-login"), - url(r'^logout$', gestioncof_views.logout), + url(r'^logout$', gestioncof_views.logout, name="cof-logout"), # Infos persos url(r'^profile$', gestioncof_views.profile), url(r'^outsider/password-change$', django_views.password_change), @@ -82,6 +86,8 @@ urlpatterns = [ url(r'^utile_cof/diff_cof$', gestioncof_views.liste_diffcof), url(r'^utile_bda/bda_revente$', gestioncof_views.liste_bdarevente), url(r'^k-fet/', include('kfet.urls')), + url(r'^cms/', include(wagtailadmin_urls)), + url(r'^documents/', include(wagtaildocs_urls)), ] if 'debug_toolbar' in settings.INSTALLED_APPS: @@ -90,7 +96,13 @@ if 'debug_toolbar' in settings.INSTALLED_APPS: url(r'^__debug__/', include(debug_toolbar.urls)), ] +if settings.DEBUG: # Si on est en production, MEDIA_ROOT est servi par Apache. # Il faut dire à Django de servir MEDIA_ROOT lui-même en développement. urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + +# Wagtail for uncatched +urlpatterns += [ + url(r'', include(wagtail_urls)), +] diff --git a/gestioncof/__init__.py b/gestioncof/__init__.py index e69de29b..b77fdb94 100644 --- a/gestioncof/__init__.py +++ b/gestioncof/__init__.py @@ -0,0 +1 @@ +default_app_config = 'gestioncof.apps.GestioncofConfig' diff --git a/gestioncof/apps.py b/gestioncof/apps.py new file mode 100644 index 00000000..6e24b050 --- /dev/null +++ b/gestioncof/apps.py @@ -0,0 +1,8 @@ +from django.apps import AppConfig + + +class GestioncofConfig(AppConfig): + name = 'gestioncof' + + def ready(self): + import gestioncof.signals diff --git a/gestioncof/shared.py b/gestioncof/shared.py index e4180b49..fabcacb9 100644 --- a/gestioncof/shared.py +++ b/gestioncof/shared.py @@ -1,62 +1,26 @@ -from django.contrib.sites.models import Site from django.conf import settings +from django.contrib.sites.models import Site + from django_cas_ng.backends import CASBackend -from django_cas_ng.utils import get_cas_client -from django.contrib.auth import get_user_model from gestioncof.models import CofProfile -User = get_user_model() - class COFCASBackend(CASBackend): - def authenticate_cas(self, ticket, service, request): - """Verifies CAS ticket and gets or creates User object""" - - client = get_cas_client(service_url=service) - username, attributes, _ = client.verify_ticket(ticket) - if attributes: - request.session['attributes'] = attributes - if not username: - return None + def clean_username(self, username): # Le CAS de l'ENS accepte les logins avec des espaces au début # et à la fin, ainsi qu’avec une casse variable. On normalise pour # éviter les doublons. - username = username.strip().lower() + return username.strip().lower() - profiles = CofProfile.objects.filter(login_clipper=username) - if len(profiles) > 0: - profile = profiles.order_by('-is_cof')[0] - user = profile.user - return user - try: - user = User.objects.get(username=username) - except User.DoesNotExist: - # user will have an "unusable" password - user = User.objects.create_user(username, '') - user.save() - return user - - def authenticate(self, ticket, service, request): - """Authenticates CAS ticket and retrieves user data""" - user = self.authenticate_cas(ticket, service, request) - if user is None: - return user - try: - profile = user.profile - except CofProfile.DoesNotExist: - profile, created = CofProfile.objects.get_or_create(user=user) - profile.save() - if not profile.login_clipper: - profile.login_clipper = user.username - profile.save() - if not user.email: - user.email = settings.CAS_EMAIL_FORMAT % profile.login_clipper - user.save() - if profile.is_buro and not user.is_staff: - user.is_staff = True - user.save() + def configure_user(self, user): + # cannot use "defaults" arg + profile, _ = CofProfile.objects.get_or_create(user=user) + profile.login_clipper = user.username + profile.save() + user.email = settings.CAS_EMAIL_FORMAT % profile.login_clipper + user.save() return user diff --git a/gestioncof/signals.py b/gestioncof/signals.py new file mode 100644 index 00000000..11cb55fc --- /dev/null +++ b/gestioncof/signals.py @@ -0,0 +1,23 @@ +from django.contrib import messages +from django.contrib.auth.signals import user_logged_in +from django.dispatch import receiver +from django.utils.translation import ugettext_lazy as _ + +from django_cas_ng.signals import cas_user_authenticated + + +@receiver(user_logged_in) +def messages_on_out_login(request, user, **kwargs): + if user.backend.startswith('django.contrib.auth'): + msg = _('Connexion à GestioCOF réussie. Bienvenue {}.').format( + user.get_short_name(), + ) + messages.success(request, msg) + + +@receiver(cas_user_authenticated) +def mesagges_on_cas_login(request, user, **kwargs): + msg = _('Connexion à GestioCOF par CAS réussie. Bienvenue {}.').format( + user.get_short_name(), + ) + messages.success(request, msg) diff --git a/gestioncof/templates/home.html b/gestioncof/templates/home.html index 5f783a48..acc04f30 100644 --- a/gestioncof/templates/home.html +++ b/gestioncof/templates/home.html @@ -1,4 +1,5 @@ {% extends "gestioncof/base_header.html" %} +{% load wagtailcore_tags %} {% block homelink %} {% endblock %} @@ -55,7 +56,8 @@

K-Fêt

    -
  • Page d'accueil
  • + {# TODO: Since Django 1.9, we can store result with "as", allowing proper value management (if None) #} +
  • Page d'accueil
  • Calendrier
  • {% if perms.kfet.is_team %}
  • K-Psul
  • diff --git a/gestioncof/views.py b/gestioncof/views.py index 6a728ea6..11b1c5ba 100644 --- a/gestioncof/views.py +++ b/gestioncof/views.py @@ -7,12 +7,17 @@ from custommail.shortcuts import send_custom_mail from django.shortcuts import redirect, get_object_or_404, render from django.http import Http404, HttpResponse, HttpResponseForbidden from django.contrib.auth.decorators import login_required -from django.contrib.auth.views import login as django_login_view +from django.contrib.auth.views import ( + login as django_login_view, logout as django_logout_view, +) from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.utils import timezone +from django.utils.translation import ugettext_lazy as _ from django.contrib import messages +from django_cas_ng.views import logout as cas_logout_view + from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \ SurveyQuestionAnswer from gestioncof.models import Event, EventRegistration, EventOption, \ @@ -78,15 +83,21 @@ def login_ext(request): @login_required -def logout(request): - try: - profile = request.user.profile - except CofProfile.DoesNotExist: - profile, created = CofProfile.objects.get_or_create(user=request.user) - if profile.login_clipper: - return redirect("django_cas_ng.views.logout") +def logout(request, next_page=None): + if next_page is None: + next_page = request.GET.get('next', None) + + profile = getattr(request.user, 'profile', None) + + if profile and profile.login_clipper: + msg = _('Déconnexion de GestioCOF et CAS réussie. À bientôt {}.') + logout_view = cas_logout_view else: - return redirect("django.contrib.auth.views.logout") + msg = _('Déconnexion de GestioCOF réussie. À bientôt {}.') + logout_view = django_logout_view + + messages.success(request, msg.format(request.user.get_short_name())) + return logout_view(request, next_page=next_page) @login_required diff --git a/kfet/cms/__init__.py b/kfet/cms/__init__.py new file mode 100644 index 00000000..0f6cab45 --- /dev/null +++ b/kfet/cms/__init__.py @@ -0,0 +1 @@ +default_app_config = 'kfet.cms.apps.KFetCMSAppConfig' diff --git a/kfet/cms/apps.py b/kfet/cms/apps.py new file mode 100644 index 00000000..f7276ae8 --- /dev/null +++ b/kfet/cms/apps.py @@ -0,0 +1,7 @@ +from django.apps import AppConfig + + +class KFetCMSAppConfig(AppConfig): + name = 'kfet.cms' + label = 'kfetcms' + verbose_name = 'CMS K-Fêt' diff --git a/kfet/cms/context_processors.py b/kfet/cms/context_processors.py new file mode 100644 index 00000000..0cf7a649 --- /dev/null +++ b/kfet/cms/context_processors.py @@ -0,0 +1,20 @@ +from kfet.models import Article + + +def get_articles(request): + articles = ( + Article.objects + .filter(is_sold=True, hidden=False) + .select_related('category') + .order_by('category__name', 'name') + ) + pressions, others = [], [] + for article in articles: + if article.category.name == 'Pression': + pressions.append(article) + else: + others.append(article) + return { + 'pressions': pressions, + 'articles': others, + } diff --git a/kfet/cms/fixtures/kfet_wagtail_17_05.json b/kfet/cms/fixtures/kfet_wagtail_17_05.json new file mode 100644 index 00000000..a0651c79 --- /dev/null +++ b/kfet/cms/fixtures/kfet_wagtail_17_05.json @@ -0,0 +1,1565 @@ +[ +{ + "fields": { + "root_page": 9, + "port": 8000, + "site_name": "Global", + "hostname": "localhost", + "is_default_site": true + }, + "pk": 2, + "model": "wagtailcore.site" +}, +{ + "fields": { + "live": true, + "show_in_menus": false, + "numchild": 1, + "title": "Root", + "slug": "root", + "depth": 1, + "expire_at": null, + "search_description": "", + "content_type": [ + "wagtailcore", + "page" + ], + "owner": null, + "expired": false, + "first_published_at": null, + "has_unpublished_changes": false, + "go_live_at": null, + "path": "0001", + "latest_revision_created_at": null, + "url_path": "/", + "locked": false, + "seo_title": "" + }, + "pk": 1, + "model": "wagtailcore.page" +}, +{ + "fields": { + "live": true, + "show_in_menus": true, + "numchild": 5, + "title": "Bienvenue en K-Fêt", + "slug": "k-fet", + "depth": 3, + "expire_at": null, + "search_description": "", + "content_type": [ + "kfetcms", + "kfetpage" + ], + "owner": [ + "root" + ], + "expired": false, + "first_published_at": "2017-05-28T04:20:00.000Z", + "has_unpublished_changes": false, + "go_live_at": null, + "path": "000100010001", + "latest_revision_created_at": null, + "url_path": "/global/k-fet/", + "locked": false, + "seo_title": "Accueil" + }, + "pk": 3, + "model": "wagtailcore.page" +}, +{ + "fields": { + "live": true, + "show_in_menus": true, + "numchild": 0, + "title": "Mode d'emploi", + "slug": "mode-demploi", + "depth": 4, + "expire_at": null, + "search_description": "", + "content_type": [ + "kfetcms", + "kfetpage" + ], + "owner": [ + "root" + ], + "expired": false, + "first_published_at": "2017-05-28T04:20:00.000Z", + "has_unpublished_changes": false, + "go_live_at": null, + "path": "0001000100010001", + "latest_revision_created_at": null, + "url_path": "/global/k-fet/mode-demploi/", + "locked": false, + "seo_title": "" + }, + "pk": 4, + "model": "wagtailcore.page" +}, +{ + "fields": { + "live": true, + "show_in_menus": true, + "numchild": 0, + "title": "L'\u00e9quipe", + "slug": "equipe", + "depth": 4, + "expire_at": null, + "search_description": "", + "content_type": [ + "kfetcms", + "kfetpage" + ], + "owner": [ + "root" + ], + "expired": false, + "first_published_at": "2017-05-28T04:20:00.000Z", + "has_unpublished_changes": false, + "go_live_at": null, + "path": "0001000100010002", + "latest_revision_created_at": null, + "url_path": "/global/k-fet/equipe/", + "locked": false, + "seo_title": "" + }, + "pk": 5, + "model": "wagtailcore.page" +}, +{ + "fields": { + "live": true, + "show_in_menus": true, + "numchild": 0, + "title": "La carte", + "slug": "carte", + "depth": 4, + "expire_at": null, + "search_description": "", + "content_type": [ + "kfetcms", + "kfetpage" + ], + "owner": [ + "root" + ], + "expired": false, + "first_published_at": "2017-05-28T04:20:00.000Z", + "has_unpublished_changes": false, + "go_live_at": null, + "path": "0001000100010003", + "latest_revision_created_at": null, + "url_path": "/global/k-fet/carte/", + "locked": false, + "seo_title": "" + }, + "pk": 6, + "model": "wagtailcore.page" +}, +{ + "fields": { + "live": true, + "show_in_menus": true, + "numchild": 0, + "title": "Les soir\u00e9es", + "slug": "soirees", + "depth": 4, + "expire_at": null, + "search_description": "", + "content_type": [ + "kfetcms", + "kfetpage" + ], + "owner": [ + "root" + ], + "expired": false, + "first_published_at": "2017-05-28T04:20:00.000Z", + "has_unpublished_changes": false, + "go_live_at": null, + "path": "0001000100010004", + "latest_revision_created_at": null, + "url_path": "/global/k-fet/soirees/", + "locked": false, + "seo_title": "" + }, + "pk": 7, + "model": "wagtailcore.page" +}, +{ + "fields": { + "live": true, + "show_in_menus": true, + "numchild": 0, + "title": "Le flipper", + "slug": "flipper", + "depth": 4, + "expire_at": null, + "search_description": "", + "content_type": [ + "kfetcms", + "kfetpage" + ], + "owner": [ + "root" + ], + "expired": false, + "first_published_at": "2017-05-28T04:20:00.000Z", + "has_unpublished_changes": false, + "go_live_at": null, + "path": "0001000100010005", + "latest_revision_created_at": null, + "url_path": "/global/k-fet/flipper/", + "locked": false, + "seo_title": "" + }, + "pk": 8, + "model": "wagtailcore.page" +}, +{ + "fields": { + "live": true, + "show_in_menus": true, + "numchild": 1, + "title": "Global", + "slug": "global", + "depth": 2, + "expire_at": null, + "search_description": "", + "content_type": [ + "wagtailcore", + "page" + ], + "owner": [ + "root" + ], + "expired": false, + "first_published_at": "2017-05-28T04:20:00.000Z", + "has_unpublished_changes": false, + "go_live_at": null, + "path": "00010001", + "latest_revision_created_at": null, + "url_path": "/global/", + "locked": false, + "seo_title": "" + }, + "pk": 9, + "model": "wagtailcore.page" +}, +{ + "fields": { + "live": true, + "show_in_menus": false, + "numchild": 0, + "title": "Mentions l\u00e9gales", + "slug": "mentions-legales", + "depth": 4, + "expire_at": null, + "search_description": "", + "content_type": [ + "kfetcms", + "kfetpage" + ], + "owner": [ + "root" + ], + "expired": false, + "first_published_at": "2017-05-28T04:20:00.000Z", + "has_unpublished_changes": false, + "go_live_at": null, + "path": "0001000100010006", + "latest_revision_created_at": null, + "url_path": "/global/k-fet/mentions-legales/", + "locked": false, + "seo_title": "" + }, + "pk": 10, + "model": "wagtailcore.page" +}, +{ + "fields": { + "name": "Root", + "numchild": 0, + "path": "0001", + "depth": 1 + }, + "pk": 1, + "model": "wagtailcore.collection" +}, +{ + "model": "kfetcms.kfetpage", + "fields": { + "custom_template": "", + "no_header": false, + "content": "

    La K-F\u00eat, c'est quoi ?

    \n\n

    \n Eh bien la K-F\u00eat, c'est le bar des \u00e9l\u00e8ves de l'\u00c9cole normale\n sup\u00e9rieure. Elle est situ\u00e9e dans les locaux de l'\u00c9cole, au pied de\n l'escalier C (plan). On y trouve \u00e0 boire, bien s\u00fbr,\n des bi\u00e8res en nombre pl\u00e9thorique mais aussi caf\u00e9s, th\u00e9s, softs et de quoi\n grignoter. Ah oui un point important, on ne va pas \u00e0 la K-F\u00eat, on va EN K-F\u00eat.\n

    \n\n

    Mais on n'y fait que boire et manger ?

    \n\n

    \n Que nenni, \u00f4 jeune et innocent conscrit-e ! La K-F\u00eat n'est pas un bouge\n sordide o\u00f9 des piliers de bar passent leurs journ\u00e9es \u00e0 picoler. Enfin pas\n uniquement. C'est aussi un lieu de divertissement avec\n son flipper (la mythique, la seule, l'unique,\n la g\u00e9niale Amazon Hunt), son baby-foot et le lieu d'\u00e9lection des \nbridgeur-se-s, du club jeux, des joueur-se-s de poker voire des quelques\n irr\u00e9ductibles du boulot qui y viennent bosser en profitant du point \nd'acc\u00e8s wifi. \n

    \n\n

    Ah \u00e7a a l'air bien mais... qui s'en occupe ? C'est ouvert quand ?

    \n\n

    \n L'\u00e9quipe d'\u00e9l\u00e8ves motiv\u00e9-e-s qui s'occupent de la K-F\u00eat s'appelle, en toute logique, l'\u00e9quipe K-F\u00eat.\n Elle est men\u00e9e par un-e leader charismatique et bien-aim\u00e9-e, \naccompagn\u00e9-e de ses troupes de fid\u00e8les, les K-F\u00eat wo-men, boys et girls.\n Le local de la K-F\u00eat n'est ouvert que si un-e K-F\u00eat wo-man est \npr\u00e9sente. \u00c0 savoir la plupart du temps entre 12h et 3h du matin.\n

    \n\n

    Et je peux y faire ce que je veux ?

    \n\n

    \n Oui et non. Nous ne sommes pas ta grand-m\u00e8re et nous n'allons\n certainement pas t'emp\u00eacher de faire la f\u00eate, ni de d\u00e9guster des pintes\n jusqu'au petit p\u00f4t. Par contre nous attendons de toi que tu ne sois pas\n un-e gros-se con-ne. A priori pas de raison de le croire, mais jette tout de m\u00eame\n un \u0153il sur le mode d'emploi de la K-F\u00eat, \u00e7a\n pourrait t'\u00e9viter de perdre un genoux ou deux...\n

    \n\n

    J'adore la K-F\u00eat, j'aimerais y organiser une soir\u00e9e, c'est possible ?

    \n\n

    \n Bien s\u00fbr\u00a0! Pour cela commence par lire ce petit\n guide histoire de savoir dans quoi tu t'engages puis contacte ton-ta chef-fe K-F\u00eat ador\u00e9-e pour v\u00e9rifier que la date de ta\n soir\u00e9e n'est pas d\u00e9j\u00e0 prise par une autre f\u00eate et obtenir son\n accord.\n

    \n\n

    J'ai une question \u00e0 vous poser. O\u00f9 puis-je vous contacter ?

    \n\n

    \n Commence d\u00e9j\u00e0 par jeter un oeil sur le mode\n d'emploi de la K-F\u00eat. Si la r\u00e9ponse \u00e0 tes interrogations ne s'y\n trouve pas, rien n'est perdu. En effet le service informatique de \nl'\u00c9cole, dans sa grande mansu\u00e9tude, a mis \u00e0 disposition de l'\u00e9quipe \nK-F\u00eat une adresse e-mail, k-fet@ens.fr. Mais sinon, passe en K-F\u00eat, il y aura sans doute un K-F\u00eat wo-man qui saura r\u00e9pondre \u00e0 ta question.\n

    " + }, + "pk": 3 +}, +{ + "model": "kfetcms.kfetpage", + "fields": { + "custom_template": "", + "no_header": false, + "content": "

    Article 0 : La K-F\u00eat n'existe pas.

    La K-F\u00eat, c'est magique, comment \u00e7a marche ?

    La K-F\u00eat n'a rien de magique, il n'y a pas de petits d\u00e9mons qui font le m\u00e9nage, pas plus que d'arbustes g\u00e9n\u00e9tiquement modifi\u00e9s aux OGM sur lesquels poussent les bouteilles de bi\u00e8res. La K-F\u00eat c'est avant tout une \u00e9quipe qui sacrifie une partie de son temps libre pour que tout se passe pour le mieux.

    Que puis-je faire pour vous aider un peu ?

    D\u00e9j\u00e0 ne pas poser de probl\u00e8mes, c'est \u00e0 dire ne pas r\u00e9veiller tout l'internat en sortant, essayer de ne pas finir dans un \u00e9tat trop avanc\u00e9 d'alcoolisation, etc... Mine de rien \u00e7a nous \u00e9viterait quelques probl\u00e8mes.

    Ensuite, comme tu le sais s\u00fbrement les bi\u00e8res sont consign\u00e9es, il est donc pr\u00e9f\u00e9rable pour nous que tu n'embarques pas les bouteilles en souvenir dans ta thurne. Mieux, tu peux nous faire gagner du temps de rangement en les ramenant au bar en partant. Et encore mieux, tu peux jeter tes d\u00e9chets (gobelets, boite de pringles, etc...). Si tu fais d\u00e9j\u00e0 tout \u00e7a tu nous simplifieras grandement la vie.

    Le syst\u00e8me mon\u00e9taire de la K-F\u00eat

    En bon \u00e9tat souverain et ind\u00e9pendant, la K-F\u00eat a sa propre monnaie : l'unit\u00e9 K-F\u00eat (UKF). Elle vaut 10 centimes d'euro. La K-F\u00eat ne battant pas monnaie, les UKF que tu poss\u00e8des sont not\u00e9es sur ton compte, identifi\u00e9 par un trigramme (une suite de trois caract\u00e8res) et que tu peux recharger en liquide ou par ch\u00e8que. Note que si tu y tiens vraiment, tu peux payer en liquide, mais poss\u00e9der un compte est bien plus pratique.

    Comment commander \u00e0 boire ou \u00e0 manger ?

    Pour commander \u00e0 boire ou \u00e0 manger, il suffit de demander \u00e0 un membre de l'\u00e9quipe K-F\u00eat. Et \u00e7a marche encore mieux si la demande est effectu\u00e9e avec le sourire au d\u00e9but et un merci \u00e0 la fin : l'\u00e9quipe est constitu\u00e9e de volontaires b\u00e9n\u00e9voles, et mieux vaut ne pas les prendre pour des chiens. EN AUCUN CAS on ne passe derri\u00e8re le bar si on n'est pas membre de l'\u00e9quipe K-F\u00eat.

    Puis-je fumer en K-F\u00eat ?

    Non ! Imagine-toi les jours de soir\u00e9es, la K-F\u00eat remplie et tout le monde qui fume... On finirait tous avec des poumons aussi crades que le sol de la K-F\u00eat. Ce serait quand m\u00eame dommage pour la recherche fran\u00e7aise qu'on cr\u00e8ve tous avant 30 ans, non ?

    Par contre tu peux fumer dehors, il y a m\u00eame des cendriers juste pour toi, par contre tu remarqueras que les chambres de l'internat se trouvent juste au dessus de toi. T\u00e2che donc de ne pas faire trop de bruit.

    Et amener ma propre bouteille ?

    D\u00e9j\u00e0 c'est apporter, enfin en tout cas avant de la boire. Ensuite la K-F\u00eat est un lieu de convivialit\u00e9 o\u00f9 les bi\u00e8res te sont vendues au prix co\u00fbtant,\n franchement ce serait pas fair-play de te la jouer solo. Alors \u00e9videment il y a des exceptions, par exemple si tu reviens de Belgique et que tu veux faire go\u00fbter de la Wesvleteren \u00e0 tes amis de l'\u00e9quipe K-F\u00eat, ou si tu veux organiser une d\u00e9gustation de vins avec la charcuterie qui va bien. Tu comprendras qu'un pack de Kro c'est quand m\u00eame pas la m\u00eame classe...

    Je peux passer ma musique ?

    Bien s\u00fbr, nous sommes tr\u00e8s loin de penser tout conna\u00eetre en mati\u00e8re de musique. Mais comme nous sommes entre gens civilis\u00e9s, et que je te rappelle que tu n'as pas le droit de passer derri\u00e8re le bar, il convient de demander \u00e0 un-e membre de l'\u00e9quipe K-F\u00eat afin qu'ille t'indique qui est \u00e0 l'origine de ces chansons que tu n'appr\u00e9cies apparemment pas. Apr\u00e8s avoir obtenu son accord tu peux demander \u00e0 quelqu'un de mettre ta playlist, qui peut-\u00eatre sur un lecteur mp3, sur Deezer ou juste sur l'ordi, mais dans ce dernier cas ce sera plus dur puisque tu n'y aura pas acc\u00e8s directement.

    Le plus simple pour toi (et pour nous) est donc de pr\u00e9voir des playlists sur Deezer d'avance et de nous les proposer. Par contre, sois gentil-le, n'insiste pas si nous ne voulons pas de ta musique traditionnelle hongroise. Par ailleurs, si un trop grand nombre de personnes nous demande de passer de la musique, l'\u00e9quipe K-F\u00eat peut ne pas acc\u00e9der \u00e0 ta requ\u00eate.

    Comment organiser une soir\u00e9e en K-F\u00eat ?

    Tout membre du COF peut organiser une soir\u00e9e en K-F\u00eat \u00e0 la condition qu'elle soit publique et annonc\u00e9e une semaine \u00e0 l'avance par des affiches dans l'\u00e9cole et un mot dans le BOcal. Il faut bien sur aussi l'accord du COF qui s'occupe de voir si \u00e7a ne pose pas de probl\u00e8me \u00e0 l'admin, celui de la K-F\u00eat team pour qu'il y ait des K-F\u00eat wo-men pour servir et s\u00fbrement du BOUM pour qu'il s'occupe de la musique. Nous t'avons tout r\u00e9sum\u00e9 ici ; merci qui ? Une fois que tu as accompli ces formalit\u00e9s, il ne te reste plus qu'\u00e0 imprimer et coller des affiches pour que ta soir\u00e9e soit un succ\u00e8s !

    D'autres remarques ?

    Des tonnes, en voici quelques unes :

    • Ce n'est pas caf\u00e8t, ni kfet, ni caf\u00e9t\u00e9ria, c'est K-F\u00eat, avec les majuscules.
    • On dit \"en K-F\u00eat\".
    • On ne passe pas derri\u00e8re le bar, je sais je l'ai d\u00e9j\u00e0 dit, mais \u00e7a a du mal \u00e0 rentrer. S'il n'y a personne pour servir c'est que les K-F\u00eat people sont soit occup\u00e9-e-s quelque chose d'important en arri\u00e8re-K-F\u00eat, soit sont pos\u00e9-e-s dans le canap\u00e9 \u00e0 c\u00f4t\u00e9 du bar, soit sont en train de jouer \u00e0 l'Amazon. Demande-leur, ou prends ton mal en patience.
    • La K-F\u00eat n'est pas une porcherie, tu n'es pas oblig\u00e9-e de laisser tout ton bordel quand tu pars.
    • Merci d'avoir lu jusque l\u00e0.
    " + }, + "pk": 4 +}, +{ + "model": "kfetcms.kfetpage", + "fields": { + "custom_template": "kfetcms/equipe.html", + "no_header": false, + "content": "

    Les K-F\u00eat boys et girls

    \n\n

    Les K-F\u00eat boys and girls font de main d'\u0153uvre bon march\u00e9 pour la \nK-F\u00eat, illes peuvent passer derri\u00e8re le bar, prendre vos commandes et \nrecharger votre compte si par malheur il est \u00e0 sec. La liste de \ncelleux-ci est trop longue pour tou-te-s les citer, pour les reconna\u00eetre\n regarde les gens qui passent derri\u00e8re le bar tout en conservant leur \nint\u00e9grit\u00e9 physique.

    \n\n

    Comment devient-on K-F\u00eat people ?

    \n\n

    Grande question que tout le monde se pose un jour ou l'autre. Pour \nacc\u00e9der au titre prestigieux de K-F\u00eat boy-girl, il est n\u00e9cessaire mais \npas suffisant d'\u00eatre assid\u00fbment pr\u00e9sent-e en K-F\u00eat, et d'\u00eatre pr\u00eat-e \u00e0 \ntrimer pour elle. Si tu es souvent en K-F\u00eat, que tu es sympathique et \nmotiv\u00e9-e, et surtout en fin de compte si le-la chef-fe le veut bien, tu \npourras devenir K-F\u00eat boy-girl et passer derri\u00e8re le bar pour servir. \nEnsuite, si tu es motiv\u00e9-e et efficace, ou simplement si t'es un-e pote \ndu-de la chef-fe et qu'ille n'a aucun scrupule, tu pourras devenir K-F\u00eat\n wo-man et avoir la cl\u00e9.

    \n\n

    Et comme la K-F\u00eat c'est avant tout beaucoup d'emmerdes on a pas envie\n de te forcer la main, on veut que cela vienne de toi. Donc si tu te \nsens pr\u00eat-e \u00e0 participer \u00e0 la vie mouvement\u00e9e de la K-F\u00eat fais-en part \nau-\u00e0 la chef-fe. Ille ne va pas te manger.

    " + }, + "pk": 5 +}, +{ + "model": "kfetcms.kfetpage", + "fields": { + "custom_template": "kfetcms/carte.html", + "no_header": false, + "content": "

    \n\tLe service de la bi\u00e8re est, historiquement, la mission et le sacerdoce \ndu K-F\u00eat people. Ille y est d\u00e9vou\u00e9-e corps et \u00e2me, et accomplit sa t\u00e2che\n avec ardeur et passion. Voyons comment se d\u00e9clinent les occasions \nd'approcher du nirvana brassicole. Les prix donn\u00e9s sont en UKF. Si tu \nn'as pas compris, va voir par ici.

    " + }, + "pk": 6 +}, +{ + "model": "kfetcms.kfetpage", + "fields": { + "custom_template": "", + "no_header": false, + "content": "

    \n Tu veux organiser une soir\u00e9e en K-F\u00eat ? Pas de probl\u00e8me !\n

    \n\n

    Quand puis-je organiser une soir\u00e9e ?

    \n\n

    \n Tu peux organiser une soir\u00e9e le jour que tu souhaites, \u00e0 condition que la\n date ne soit pas d\u00e9j\u00e0 prise par quelqu'un d'autre. Sache par contre que la\n K-F\u00eat ne te sera pas enti\u00e8rement d\u00e9di\u00e9e et que les utilisateur-rice-s habituel-le-s\n continueront de la fr\u00e9quenter (et risquent fortement de squatter ta\n soir\u00e9e). Donc si tu veux un peu d'intimit\u00e9 les soir\u00e9es du week-end sont plus\n conseill\u00e9es (mais l'\u00e9quipe risque de ne pas \u00eatre pr\u00e9sente), mais aussi\n plus pris\u00e9es, d\u00e9p\u00eache-toi de r\u00e9server la tienne.\n

    \n\n

    Quelles d\u00e9marches dois-je effectuer ?

    \n

    \n D\u00e9j\u00e0 pr\u00e9venir poliment l'\u00e9quipe K-F\u00eat, et\n surtout le-la chef-fe pour v\u00e9rifier que la date est encore libre, et qu'il y\n aura au moins quelqu'un pour t'ouvrir la K-F\u00eat. Ensuite, si ta soir\u00e9e\n n'est pas une simple bouffe qui finit avant minuit il faut pr\u00e9venir les\n vigiles via l'administration au moyen d'une demande d'autorisation de\n soir\u00e9e qui se trouve sur la section du p\u00f4le Pr\u00e9vention et S\u00e9curit\u00e9 sur l'intranet : demande d'autorisation de soir\u00e9e.\n \u00c0 faire au moins une semaine avant ta soir\u00e9e.\n

    \n

    \n Si en plus tu as besoin que le BOUM s'occupe de la musique et/ou PLS des\n lumi\u00e8res c'est elleux qu'il faut contacter. Histoire de t'\u00e9viter\n d'avoir \u00e0 chercher voici leur adresse\u00a0: boum (at) ens (point) fr\n et pls (at) ens (point) fr.\n

    \n\n

    C'est enfin le grand jour, je fais quoi ?

    \n

    \n D\u00e9j\u00e0 le m\u00e9nage, oui je sais c'est chiant mais c'est le prix \u00e0 payer pour\n profiter du local. Demande \u00e0 ce qu'un-e K-F\u00eat wo-man t'ouvre et tu devrais avoir\n \u00e0 ta disposition tout ce qu'il faut pour faire briller la K-F\u00eat (ou au moins on essaiera de\n trouver ce qu'il faut). Fais par\n contre attention aux bouteilles de bi\u00e8re qui sont consign\u00e9es, s'il n'y a\n personne pour les ranger contente-toi de les mettre sur le bar, quelqu'un\n s'en chargera plus tard. Les meubles peuvent \u00eatre d\u00e9plac\u00e9s dans une salle\n voisine si tu le souhaites, il faudra juste penser \u00e0 les remettre en place.\n

    \n

    \n Ensuite dans l'id\u00e9al tu connais tous tes potes, donc en donner une liste \u00e0\n la loge permet d'\u00e9viter quelques probl\u00e8mes et quelques aller-retours.\n Au-del\u00e0 de 21h, les ext\u00e9rieur-e-s ne peuvent rentrer qu'avec un-e Ulmien-ne ayant sa carte\n sur lui-elle.\n

    \n\n

    Je pourrai passer ma musique ?

    \n\n

    \n Si le BOUM est pr\u00e9sent, faut voir avec elleux : boum (at) ens (point) fr
    \n Sinon, pr\u00e9pare ta musique sur un lecteur mp3 ou une playlist\n Deezer. Lors de la soir\u00e9e,\n demande \u00e0 un-e K-F\u00eat wo-man de passer ce que tu as pr\u00e9par\u00e9.\n

    \n\n\n

    Et pour ce qui est de la nourriture, des boissons ?

    \n

    \n Tu peux apporter toute la nourriture que tu souhaites\u00a0; pr\u00e9vois assez\n large, il y a beaucoup de K-F\u00eat people \u00e0 nourrir. Pour ce qui est de la\n boisson, il faut te limiter aux boissons de cat\u00e9gorie 2, c'est \u00e0 dire\n bi\u00e8res, vins et boissons \u00e0 base de vin, champagne et bien s\u00fbr les boissons sans alcool.\n

    \n\n

    Et pendant la soir\u00e9e ?

    \n

    \n Ce soir c'est ton soir, il est donc bien s\u00fbr \u00e9vident que tu dois\n rester pr\u00e9sent-e et joignable du d\u00e9but \u00e0 la fin de la soir\u00e9e. Id\u00e9alement ce\n doit aussi \u00eatre le cas de tes \"Responsables ordre et discipline\". Vous ne serez pas\n trop de deux ou trois pour r\u00e9gler les probl\u00e8mes qui pourraient survenir,\n tes potes bourr\u00e9-e-s, tes potes qui fument, tes potes qui font du bordel dans la cage d'escalier,\n etc... Tous les probl\u00e8mes qui pourraient survenir te seront imput\u00e9s donc\n pr\u00e9viens-les, c'est tes potes apr\u00e8s tout, non ?\n

    \n\n

    Apr\u00e8s c'est bon ?

    \n

    \n Eh non, pas encore, apr\u00e8s (ou le lendemain de) ta soir\u00e9e il te faudra encore ranger,\n faire le m\u00e9nage et passer un coup de javel. Oui encore, mais bon, pense \u00e0 toutes les fois o\u00f9\n c'est nous qui le faisons pour le bien de tou-te-s. Une fois n'est pas\n coutume demande \u00e0 un-e K-F\u00eat wo-man de t'ouvrir et de te fournir tout le\n mat\u00e9riel dont tu pourrais avoir besoin, et l\u00e0 o\u00f9 c'est vraiment classe\n c'est que tu peux m\u00eame faire \u00e7a en musique si tu le souhaites. N'oublie\n pas non plus de rapporter les meubles que tu pourrais avoir sortis et que\n les poubelles ne disparaissent pas toutes seules.\n

    \n\n

    Une derni\u00e8re remarque ?

    \n\n

    \n Ouais, la K-F\u00eat c'est pas chez m\u00e9m\u00e9, alors c'est peut-\u00eatre ta soir\u00e9e mais\n si un-e membre de l'\u00e9quipe K-F\u00eat te dit quelque\n chose (de baisser le son, de virer telle ou telle personne...) tu acceptes avec le sourire.\n En particulier tu ne passes pas derri\u00e8re le bar.\n

    \n\n

    Je ne parle pas bien fran\u00e7ais, vous pourriez me faire un r\u00e9sum\u00e9 ?

    \n

    \n Organiser ta soir\u00e9e c'est facile :\n

    \n
    • Envoie un mail \u00e0 la K-F\u00eat pour demander l'autorisation\n : k-fet (at) ens (point) fr.
    • Lorsque c'est bon, remplis\n le papier de l'admin, et\n donne-le au-\u00e0 la chef-fe K-F\u00eat.
    • Pour la musique, l'alcool, contacte la K-F\u00eat.
    • Le jour de la soir\u00e9e, viens faire le m\u00e9nage et donne une liste des\n ext\u00e9rieur-e-s \u00e0 la loge.
    • Pendant la soir\u00e9e, surveille tes invit\u00e9s (pas trop de bruit \u00e0\n l'ext\u00e9rieur de la K-F\u00eat, pas de gens trop bourr\u00e9s qui font des b\u00eatises\n avec les alarmes ou les sorties de secours...)
    • Apr\u00e8s la soir\u00e9e (le lendemain si tu veux) reviens faire le m\u00e9nage.
    \n

    \n Voila, facile, non ?\n

    " + }, + "pk": 7 +}, +{ + "model": "kfetcms.kfetpage", + "fields": { + "custom_template": "", + "no_header": false, + "content": "

    Et le baby-foot

    \n\n

    LE flipper

    \n\n\n\n

    \n\tIl existe en K-F\u00eat une machine unique, inimitable, tout droit venue des\n ann\u00e9es folles et b\u00e9nies o\u00f9 les concepteurs de flippers connaissaient \nencore leur m\u00e9tier, o\u00f9 les tilts \u00e9taient m\u00e9rit\u00e9s et le jeu un art de \nvivre. L'esth\u00e8te appr\u00e9cie et reconna\u00eet imm\u00e9diatement la beaut\u00e9 sobre et \nsauvage de l'Amazon Hunt II. D'admirateur, il se m\u00e9tamorphose \nin\u00e9luctablement en joueur-se, puis en amant-e. Car l'Amazon est une \nfemme, fatale \u00e0 bien des \u00e9gards, tou-te-s les grand-e-s joueur-euse-s \nvous le diront. Dans la pr\u00e9histoire de la K-F\u00eat, des demi-dieux-d\u00e9esses \ndu flipper d\u00e9sormais pass\u00e9-e-s dans la l\u00e9gende ont r\u00e9dig\u00e9 un trait\u00e9 \n(certain-e-s diront une bible, voire la Bible) disponible ici (en pdf).

    Le baby-foot

    \n\n

    \n\t\n

    \n\n\n

    La d\u00e9funte fun machine

    \n\n\n\nCette machine n'est plus. Mais elle reste dans le coeur de ceux qui \nl'ont connue. C'est pourquoi cette section n'a pas \u00e9t\u00e9 retir\u00e9e.

    Pour attaquer le cas \u00e9trange de la machine bizarre qui tra\u00eene \u00e0 c\u00f4t\u00e9, \ndisons simplement qu'elle s'appelle Monster Bash. On me souffle en r\u00e9gie\n que pour une fun machine, elle n'est pas si mal. De fait, elle t\u00e9moigne\n d'un humour d\u00e9cal\u00e9, absurde et parfois involontaire : ainsi, la \ntraduction oscille entre le path\u00e9tique et l'ignoble, en passant par le \nburlesque. Le but est de r\u00e9veiller et vaincre six monstres, parmi \nlesquels Dracula et Frankenstein, pour les asservir et les rassembler \ndans le plus grand groupe de rock de l'histoire : les \u00abmonsters of rock\u00bb\n (traduction : \u00abmonstres du rocher\u00bb). Il n'y a pas pour le moment de \ntrait\u00e9 th\u00e9orique de la Monster Bash, la jeu se r\u00e9sumant de toute fa\u00e7on \u00e0\n \u00abmoi voir, moi actionner flip\u00bb. Ce qui n'emp\u00eache pas la machine en \nquestion d'avoir son public d'habitu\u00e9-e-s, bien au contraire. \n

    " + }, + "pk": 8 +}, +{ + "model": "kfetcms.kfetpage", + "fields": { + "custom_template": "", + "no_header": false, + "content": "

    Responsable de la publication

    • Il s'agit de la pr\u00e9sidence du COF :
      Association des \u00c9l\u00e8ves de l'\u00c9cole Normale Sup\u00e9rieure
      45 rue d'Ulm
      75005 Paris

    Informations prestataires

    • L'h\u00e9bergement est fourni \u00e0 titre gracieux par le CRI :
      \u00c9cole Normale Sup\u00e9rieure

      Centre de Ressources Informatiques
      45 rue d'Ulm
      75005 Paris
    • Le d\u00e9veloppement est assur\u00e9 par COF-Geek.
    " + }, + "pk": 10 +}, +{ + "model": "kfetcms.kfetpagegroupteam", + "fields": { + "content": "

    Les ancien-ne-s Chef-fe-s K-F\u00eat doivent bien \u00eatre pr\u00e9sent\u00e9-e-s avant \nl'\u00e9quipe actuelle. C'est gr\u00e2ce \u00e0 elleux qu'elle tourne encore, gr\u00e2ce \u00e0 \nelleux qu'elle a bien tourn\u00e9, et puis, de pr\u00e8s comme de loin, illes \nveillent encore sur nous. Ce sont les diff\u00e9rentes facettes de la K-F\u00eat \nhistorique, bien que d'un certain point de vue, illes se ressemblent \ntou-te-s : les Chef-fe-s K-F\u00eat sont une dynastie, ils n'ont pas \u00e9t\u00e9 \nChef-fe-s apr\u00e8s avoir prouv\u00e9 quoi que ce soit, illes l'ont \u00e9t\u00e9 parce que\n ce r\u00f4le leur revenait de droit. On na\u00eet Chef-fe K-F\u00eat, on ne le devient\n pas. Et on le reste toujours, dans l'\u00e2me.

    ", + "sort_order": 0, + "page": 5, + "title": "Les ancien-ne-s Chef-fe-s K-F\u00eat", + "group": 3, + "show_only": 12 + }, + "pk": 1 +}, +{ + "model": "kfetcms.kfetpagegroupteam", + "fields": { + "content": "

    Le-la chef-fe K-F\u00eat, celui-celle qui a le droit de vie et de mort sur les \u00e2mes \u00e9gar\u00e9es qui fr\u00e9quentent la K-F\u00eat.

    ", + "sort_order": 1, + "page": 5, + "title": "Le chef", + "group": 1, + "show_only": null + }, + "pk": 2 +}, +{ + "model": "kfetcms.kfetpagegroupteam", + "fields": { + "content": "

    Les K-F\u00eat wo-men poss\u00e8dent les cl\u00e9s de la K-F\u00eat. Ce sont elleux qui peuvent d\u00e9cider ou non d'ouvrir la K-F\u00eat.

    ", + "sort_order": 2, + "page": 5, + "title": "Les K-F\u00eat Wo-Men", + "group": 2, + "show_only": null + }, + "pk": 3 +}, +{ + "model": "kfetcms.kfetpagegroupteam", + "fields": { + "content": "

    Les vieux-illes sont d'ancien-ne-s K-F\u00eat wo-men qui ne viennent plus \naussi souvent qu'avant, illes servent toujours, mais n'ont en g\u00e9n\u00e9ral \nplus les cl\u00e9s. Illes existent n\u00e9anmoins, et on les garde (pour \ncertain-e-s) parce qu'au fond, on les aime quand m\u00eame, et qu'en plus, \nilles en savent plus que n'importe qui sur la K-F\u00eat.

    ", + "sort_order": 3, + "page": 5, + "title": "Les Vieux-illes", + "group": 4, + "show_only": 12 + }, + "pk": 4 +}, +{ + "model": "kfetcms.groupteam", + "fields": { + "name": "Chef-fe-s" + }, + "pk": 1 +}, +{ + "model": "kfetcms.groupteam", + "fields": { + "name": "Wo-Men" + }, + "pk": 2 +}, +{ + "model": "kfetcms.groupteam", + "fields": { + "name": "Ancien-ne-s chef-fe-s" + }, + "pk": 3 +}, +{ + "model": "kfetcms.groupteam", + "fields": { + "name": "Ancien-ne-s wo-men" + }, + "pk": 4 +}, +{ + "pk": 1, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 0, + "first_name": "Hugo", + "group": 1, + "nick_name": "", + "photo": 3, + "last_name": "Manet" + } +}, +{ + "pk": 2, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 1, + "first_name": "Lisa", + "group": 1, + "nick_name": "", + "photo": 4, + "last_name": "Gourdon" + } +}, +{ + "pk": 3, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 0, + "first_name": "Pierre", + "group": 2, + "nick_name": "", + "photo": 5, + "last_name": "Quesselaire" + } +}, +{ + "pk": 4, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 1, + "first_name": "Thibault", + "group": 2, + "nick_name": "", + "photo": 6, + "last_name": "Scoquard" + } +}, +{ + "pk": 5, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 2, + "first_name": "Arnaud", + "group": 2, + "nick_name": "", + "photo": 7, + "last_name": "Fanthomme" + } +}, +{ + "pk": 6, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 3, + "first_name": "Vincent", + "group": 2, + "nick_name": "", + "photo": 8, + "last_name": "Balerdi" + } +}, +{ + "pk": 7, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 4, + "first_name": "Nathana\u00ebl", + "group": 2, + "nick_name": "", + "photo": 9, + "last_name": "Willaime" + } +}, +{ + "pk": 8, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 5, + "first_name": "\u00c9lisabeth", + "group": 2, + "nick_name": "", + "photo": 10, + "last_name": "Miller" + } +}, +{ + "pk": 9, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 6, + "first_name": "Arthur", + "group": 2, + "nick_name": "B2O", + "photo": 11, + "last_name": "Lesage" + } +}, +{ + "pk": 10, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 7, + "first_name": "Sarah", + "group": 2, + "nick_name": "", + "photo": 12, + "last_name": "Asset" + } +}, +{ + "pk": 11, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 8, + "first_name": "Alexandre", + "group": 2, + "nick_name": "", + "photo": 13, + "last_name": "Legrand" + } +}, +{ + "pk": 12, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 9, + "first_name": "\u00c9tienne", + "group": 2, + "nick_name": "", + "photo": 14, + "last_name": "Baudel" + } +}, +{ + "pk": 13, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 0, + "first_name": "Marine", + "group": 3, + "nick_name": "", + "photo": 15, + "last_name": "Snape" + } +}, +{ + "pk": 14, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 1, + "first_name": "Anatole", + "group": 3, + "nick_name": "", + "photo": 16, + "last_name": "Gosset" + } +}, +{ + "pk": 15, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 2, + "first_name": "Jacko", + "group": 3, + "nick_name": "", + "photo": 17, + "last_name": "Rastikian" + } +}, +{ + "pk": 16, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 3, + "first_name": "Alexandre", + "group": 3, + "nick_name": "", + "photo": 18, + "last_name": "Jannaud" + } +}, +{ + "pk": 17, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 4, + "first_name": "Aur\u00e9lien", + "group": 3, + "nick_name": "", + "photo": 19, + "last_name": "Delobelle" + } +}, +{ + "pk": 18, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 5, + "first_name": "Sylvain", + "group": 3, + "nick_name": "", + "photo": 20, + "last_name": "Douteau" + } +}, +{ + "pk": 19, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 6, + "first_name": "Rapha\u00ebl", + "group": 3, + "nick_name": "", + "photo": 21, + "last_name": "Lescanne" + } +}, +{ + "pk": 20, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 7, + "first_name": "Romain", + "group": 3, + "nick_name": "", + "photo": 22, + "last_name": "Gourvil" + } +}, +{ + "pk": 21, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 8, + "first_name": "Marie", + "group": 3, + "nick_name": "", + "photo": 23, + "last_name": "Labeye" + } +}, +{ + "pk": 22, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 9, + "first_name": "Oscar", + "group": 3, + "nick_name": "", + "photo": 24, + "last_name": "Blumberg" + } +}, +{ + "pk": 23, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 10, + "first_name": "Za\u00efd", + "group": 3, + "nick_name": "", + "photo": 25, + "last_name": "Allybokus" + } +}, +{ + "pk": 24, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 11, + "first_name": "Damien", + "group": 3, + "nick_name": "", + "photo": 26, + "last_name": "Garreau" + } +}, +{ + "pk": 25, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 12, + "first_name": "Andr\u00e9a", + "group": 3, + "nick_name": "", + "photo": 27, + "last_name": "Londonez-Lopez" + } +}, +{ + "pk": 26, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 13, + "first_name": "Tristan", + "group": 3, + "nick_name": "", + "photo": 28, + "last_name": "Roussel" + } +}, +{ + "pk": 27, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 14, + "first_name": "Guillaume", + "group": 3, + "nick_name": "", + "photo": 29, + "last_name": "Vernade" + } +}, +{ + "pk": 28, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 15, + "first_name": "Lucas", + "group": 3, + "nick_name": "", + "photo": 30, + "last_name": "Mercier" + } +}, +{ + "pk": 29, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 16, + "first_name": "Fran\u00e7ois", + "group": 3, + "nick_name": "M\u00e9talleux", + "photo": 31, + "last_name": "Maillot" + } +}, +{ + "pk": 30, + "model": "kfetcms.memberteam", + "fields": { + "sort_order": 17, + "first_name": "Fabrice", + "group": 3, + "nick_name": "", + "photo": 32, + "last_name": "Catoire" + } +}, +{ + "model": "wagtaildocs.document", + "pk": 1, + "fields": { + "created_at": "2017-05-30T04:20:00.000Z", + "uploaded_by_user": [ + "root" + ], + "collection": 1, + "title": "K-F\u00eat - Plan d'acc\u00e8s", + "file": "documents/kfet_acces.pdf" + } +}, +{ + "model": "wagtaildocs.document", + "pk": 2, + "fields": { + "created_at": "2017-05-30T04:20:00.000Z", + "uploaded_by_user": [ + "root" + ], + "collection": 1, + "title": "K-F\u00eat - Demande d'autorisation", + "file": "documents/kfet_autorisation.pdf" + } +}, +{ + "model": "wagtaildocs.document", + "pk": 3, + "fields": { + "created_at": "2017-05-30T04:20:00.000Z", + "uploaded_by_user": [ + "root" + ], + "collection": 1, + "title": "K-F\u00eat - Trait\u00e9 de Flipper Th\u00e9orique", + "file": "documents/kfet_flipper.pdf" + } +}, +{ + "model": "wagtailimages.image", + "pk": 1, + "fields": { + "created_at": "2017-05-30T04:20:00.000Z", + "focal_point_width": null, + "height": 300, + "file": "original_images/kfet_amazon.jpg", + "collection": 1, + "focal_point_x": null, + "file_size": null, + "focal_point_height": null, + "focal_point_y": null, + "title": "K-F\u00eat - Amazon Hunt", + "width": 200, + "uploaded_by_user": [ + "root" + ] + } +}, +{ + "model": "wagtailimages.image", + "pk": 2, + "fields": { + "created_at": "2017-05-30T04:20:00.000Z", + "focal_point_width": null, + "height": 300, + "file": "original_images/kfet_funmachine.jpg", + "collection": 1, + "focal_point_x": null, + "file_size": null, + "focal_point_height": null, + "focal_point_y": null, + "title": "K-F\u00eat - Fun Machine", + "width": 200, + "uploaded_by_user": [ + "root" + ] + } +}, +{ + "fields": { + "width": 3020, + "file_size": null, + "file": "original_images/hugo_manet.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 3020, + "focal_point_width": null, + "focal_point_y": null, + "title": "Hugo Manet", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 3 +}, +{ + "fields": { + "width": 1566, + "file_size": null, + "file": "original_images/lisa_gourdon.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 1634, + "focal_point_width": null, + "focal_point_y": null, + "title": "Lisa Gourdon", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 4 +}, +{ + "fields": { + "width": 117, + "file_size": null, + "file": "original_images/pierre_quesselaire.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 153, + "focal_point_width": null, + "focal_point_y": null, + "title": "Pierre Quesselaire", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 5 +}, +{ + "fields": { + "width": 606, + "file_size": null, + "file": "original_images/thibault_scoquart.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 487, + "focal_point_width": null, + "focal_point_y": null, + "title": "Thibault Scoquard", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 6 +}, +{ + "fields": { + "width": 640, + "file_size": null, + "file": "original_images/arnaud_fanthomme.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 320, + "focal_point_width": null, + "focal_point_y": null, + "title": "Arnaud Fanthomme", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 7 +}, +{ + "fields": { + "width": 125, + "file_size": null, + "file": "original_images/vincent_balerdi.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 163, + "focal_point_width": null, + "focal_point_y": null, + "title": "Vincent Balerdi", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 8 +}, +{ + "fields": { + "width": 125, + "file_size": null, + "file": "original_images/nathanel_willaime.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 176, + "focal_point_width": null, + "focal_point_y": null, + "title": "Nathana\u00ebl Willaime", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 9 +}, +{ + "fields": { + "width": 125, + "file_size": null, + "file": "original_images/elisabeth_miller.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 146, + "focal_point_width": null, + "focal_point_y": null, + "title": "\u00c9lisabeth Miller", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 10 +}, +{ + "fields": { + "width": 720, + "file_size": null, + "file": "original_images/arthur_lesage.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 720, + "focal_point_width": null, + "focal_point_y": null, + "title": "Arthur Lesage", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 11 +}, +{ + "fields": { + "width": 445, + "file_size": null, + "file": "original_images/sarah_asset.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 436, + "focal_point_width": null, + "focal_point_y": null, + "title": "Sarah Asset", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 12 +}, +{ + "fields": { + "width": 480, + "file_size": null, + "file": "original_images/alexandre_legrand.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 360, + "focal_point_width": null, + "focal_point_y": null, + "title": "Alexandre Legrand", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 13 +}, +{ + "fields": { + "width": 4608, + "file_size": null, + "file": "original_images/etienne_baudel.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 3456, + "focal_point_width": null, + "focal_point_y": null, + "title": "\u00c9tienne Baudel", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 14 +}, +{ + "fields": { + "width": 358, + "file_size": null, + "file": "original_images/marine_snape.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 435, + "focal_point_width": null, + "focal_point_y": null, + "title": "Marine Snape", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 15 +}, +{ + "fields": { + "width": 121, + "file_size": null, + "file": "original_images/anatole_gosset.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 200, + "focal_point_width": null, + "focal_point_y": null, + "title": "Anatole Gosset", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 16 +}, +{ + "fields": { + "width": 253, + "file_size": null, + "file": "original_images/jacko_rastikian.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 338, + "focal_point_width": null, + "focal_point_y": null, + "title": "Jacko Rastikian", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 17 +}, +{ + "fields": { + "width": 285, + "file_size": null, + "file": "original_images/alexandre_jannaud.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 380, + "focal_point_width": null, + "focal_point_y": null, + "title": "Alexandre Jannaud", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 18 +}, +{ + "fields": { + "width": 283, + "file_size": null, + "file": "original_images/aurelien_delobelle.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 371, + "focal_point_width": null, + "focal_point_y": null, + "title": "Aur\u00e9lien Delobelle", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 19 +}, +{ + "fields": { + "width": 125, + "file_size": null, + "file": "original_images/sylvain_douteau.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 161, + "focal_point_width": null, + "focal_point_y": null, + "title": "Sylvain Douteau", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 20 +}, +{ + "fields": { + "width": 125, + "file_size": null, + "file": "original_images/raphael_lescanne.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 176, + "focal_point_width": null, + "focal_point_y": null, + "title": "Rapha\u00ebl Lescanne", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 21 +}, +{ + "fields": { + "width": 124, + "file_size": null, + "file": "original_images/romain_gourvil.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 157, + "focal_point_width": null, + "focal_point_y": null, + "title": "Romain Gourvil", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 22 +}, +{ + "fields": { + "width": 133, + "file_size": null, + "file": "original_images/marie_labeye.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 163, + "focal_point_width": null, + "focal_point_y": null, + "title": "Marie Labeye", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 23 +}, +{ + "fields": { + "width": 127, + "file_size": null, + "file": "original_images/oscar_blumberg.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 159, + "focal_point_width": null, + "focal_point_y": null, + "title": "Oscar Blumberg", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 24 +}, +{ + "fields": { + "width": 210, + "file_size": null, + "file": "original_images/zaid_allybokus.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 311, + "focal_point_width": null, + "focal_point_y": null, + "title": "Za\u00efd Allybokus", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 25 +}, +{ + "fields": { + "width": 495, + "file_size": null, + "file": "original_images/damien_garreau.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 548, + "focal_point_width": null, + "focal_point_y": null, + "title": "Damien Garreau", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 26 +}, +{ + "fields": { + "width": 323, + "file_size": null, + "file": "original_images/andrea_londono.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 458, + "focal_point_width": null, + "focal_point_y": null, + "title": "Andr\u00e9a Londono-Lopez", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 27 +}, +{ + "fields": { + "width": 120, + "file_size": null, + "file": "original_images/tristan_roussel.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 155, + "focal_point_width": null, + "focal_point_y": null, + "title": "Tristan Roussel", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 28 +}, +{ + "fields": { + "width": 427, + "file_size": null, + "file": "original_images/guillaume_vernade.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 640, + "focal_point_width": null, + "focal_point_y": null, + "title": "Guillaume Vernade", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 29 +}, +{ + "fields": { + "width": 2304, + "file_size": null, + "file": "original_images/lucas_mercier.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 3020, + "focal_point_width": null, + "focal_point_y": null, + "title": "Lucas Mercier", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 30 +}, +{ + "fields": { + "width": 199, + "file_size": null, + "file": "original_images/francois_maillot.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 240, + "focal_point_width": null, + "focal_point_y": null, + "title": "Fran\u00e7ois Maillot", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 31 +}, +{ + "fields": { + "width": 965, + "file_size": null, + "file": "original_images/fabrice_catoire.jpg", + "focal_point_height": null, + "focal_point_x": null, + "height": 1255, + "focal_point_width": null, + "focal_point_y": null, + "title": "Fabrice Catoire", + "collection": 1, + "uploaded_by_user": [ + "root" + ], + "created_at": "2017-05-30T04:20:00.000Z" + }, + "model": "wagtailimages.image", + "pk": 32 +}, +{ + "pk": 1, + "fields": { + "site": [ + "localhost", + 8000 + ], + "use_specific": 1, + "max_levels": 2 + }, + "model": "wagtailmenus.mainmenu" +}, +{ + "pk": 1, + "fields": { + "link_page": 3, + "menu": 1, + "allow_subnav": true, + "handle": "", + "link_text": "Accueil", + "link_url": "", + "sort_order": 0, + "url_append": "" + }, + "model": "wagtailmenus.mainmenuitem" +}, +{ + "pk": 2, + "fields": { + "link_page": 4, + "menu": 1, + "allow_subnav": true, + "handle": "", + "link_text": "", + "link_url": "", + "sort_order": 1, + "url_append": "" + }, + "model": "wagtailmenus.mainmenuitem" +}, +{ + "pk": 3, + "fields": { + "link_page": 5, + "menu": 1, + "allow_subnav": true, + "handle": "", + "link_text": "", + "link_url": "", + "sort_order": 2, + "url_append": "" + }, + "model": "wagtailmenus.mainmenuitem" +}, +{ + "pk": 4, + "fields": { + "link_page": 6, + "menu": 1, + "allow_subnav": true, + "handle": "", + "link_text": "", + "link_url": "", + "sort_order": 3, + "url_append": "" + }, + "model": "wagtailmenus.mainmenuitem" +}, +{ + "pk": 5, + "fields": { + "link_page": 7, + "menu": 1, + "allow_subnav": true, + "handle": "", + "link_text": "", + "link_url": "", + "sort_order": 4, + "url_append": "" + }, + "model": "wagtailmenus.mainmenuitem" +}, +{ + "pk": 6, + "fields": { + "link_page": 8, + "menu": 1, + "allow_subnav": true, + "handle": "", + "link_text": "", + "link_url": "", + "sort_order": 5, + "url_append": "" + }, + "model": "wagtailmenus.mainmenuitem" +} +] diff --git a/kfet/cms/management/commands/kfet_loadwagtail.py b/kfet/cms/management/commands/kfet_loadwagtail.py new file mode 100644 index 00000000..86b94d3e --- /dev/null +++ b/kfet/cms/management/commands/kfet_loadwagtail.py @@ -0,0 +1,35 @@ +from django.contrib.auth.models import Group +from django.core.management import call_command +from django.core.management.base import BaseCommand + +from wagtail.wagtailcore.models import Page, Site + + +class Command(BaseCommand): + help = "Importe des données pour Wagtail" + + def add_arguments(self, parser): + parser.add_argument('--file', default='kfet_wagtail_17_05') + + def handle(self, *args, **options): + + self.stdout.write("Import des données wagtail") + + # Nettoyage des données initiales posées par Wagtail dans la migration + # wagtailcore/0002 + + Group.objects.filter(name__in=('Moderators', 'Editors')).delete() + + try: + homepage = Page.objects.get( + title="Welcome to your new Wagtail site!" + ) + homepage.delete() + Site.objects.filter(root_page=homepage).delete() + except Page.DoesNotExist: + pass + + # Import des données + # Par défaut, il s'agit d'une copie du site K-Fêt (17-05) + + call_command('loaddata', options['file']) diff --git a/kfet/cms/migrations/0001_initial.py b/kfet/cms/migrations/0001_initial.py new file mode 100644 index 00000000..6798aecc --- /dev/null +++ b/kfet/cms/migrations/0001_initial.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models +import modelcluster.fields +import wagtail.wagtailcore.fields +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0033_remove_golive_expiry_help_text'), + ('wagtailimages', '0019_delete_filter'), + ] + + operations = [ + migrations.CreateModel( + name='GroupTeam', + fields=[ + ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), + ('name', models.CharField(max_length=255, verbose_name='Nom')), + ], + options={ + 'verbose_name': 'Groupe de K-Fêt-eux-ses', + 'verbose_name_plural': 'Groupes de K-Fêt-eux-ses', + }, + ), + migrations.CreateModel( + name='KFetPage', + fields=[ + ('page_ptr', models.OneToOneField(primary_key=True, to='wagtailcore.Page', parent_link=True, auto_created=True, serialize=False)), + ('no_header', models.BooleanField(verbose_name='Sans en-tête', help_text="Coché, l'en-tête (avec le titre) de la page n'est pas affiché.", default=False)), + ('content', wagtail.wagtailcore.fields.RichTextField(verbose_name='Contenu')), + ('custom_template', models.CharField(max_length=255, verbose_name='Template personnalisé', blank=True)), + ], + options={ + 'verbose_name': 'page K-Fêt', + 'verbose_name_plural': 'pages K-Fêt', + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='KFetPageGroupTeam', + fields=[ + ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), + ('sort_order', models.IntegerField(editable=False, null=True, blank=True)), + ('title', models.CharField(max_length=255, verbose_name='Titre du groupe', blank=True)), + ('content', wagtail.wagtailcore.fields.RichTextField(verbose_name='Texte de présentation du groupe')), + ('group', models.ForeignKey(related_name='+', verbose_name='Groupe de K-Fêt-eux-ses', to='kfetcms.GroupTeam')), + ('page', modelcluster.fields.ParentalKey(related_name='team_groups', to='kfetcms.KFetPage')), + ('show_only', models.IntegerField(default=None, verbose_name='Montrer seulement', blank=True, null=True, help_text='Nombre de membres du groupe affichés initialement. Laisser vide pour tou-te-s les afficher.')), + + ], + options={ + 'abstract': False, + 'ordering': ['sort_order'], + }, + ), + migrations.CreateModel( + name='MemberTeam', + fields=[ + ('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)), + ('sort_order', models.IntegerField(editable=False, null=True, blank=True)), + ('first_name', models.CharField(max_length=255, verbose_name='Prénom', blank=True, default='')), + ('last_name', models.CharField(max_length=255, verbose_name='Nom', blank=True, default='')), + ('nick_name', models.CharField(max_length=255, verbose_name='Alias', blank=True, default='')), + ('group', modelcluster.fields.ParentalKey(related_name='members', verbose_name='Groupe de K-Fêt-eux-ses', to='kfetcms.GroupTeam')), + ('photo', models.ForeignKey(related_name='+', on_delete=django.db.models.deletion.SET_NULL, blank=True, verbose_name='Photo', to='wagtailimages.Image', null=True)), + ], + options={ + 'verbose_name': 'K-Fêt-eux-se', + }, + ), + ] diff --git a/kfet/cms/migrations/__init__.py b/kfet/cms/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/kfet/cms/models.py b/kfet/cms/models.py new file mode 100644 index 00000000..8b80f175 --- /dev/null +++ b/kfet/cms/models.py @@ -0,0 +1,165 @@ +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from modelcluster.models import ClusterableModel, ParentalKey +from wagtail.wagtailadmin.edit_handlers import FieldPanel, InlinePanel +from wagtail.wagtailcore.fields import RichTextField +from wagtail.wagtailcore.models import Orderable, Page +from wagtail.wagtailimages.edit_handlers import ImageChooserPanel +from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel +from wagtail.wagtailsnippets.models import register_snippet + +from kfet.cms.context_processors import get_articles + + +class KFetPage(Page): + no_header = models.BooleanField( + verbose_name=_('Sans en-tête'), + default=False, + help_text=_( + "Coché, l'en-tête (avec le titre) de la page n'est pas affiché." + ), + ) + content = RichTextField(verbose_name=_('Contenu')) + custom_template = models.CharField( + verbose_name=_('Template personnalisé'), + max_length=255, + blank=True, + ) + + content_panels = Page.content_panels + [ + FieldPanel('no_header'), + FieldPanel('content', classname='full'), + InlinePanel('team_groups', label=_("Groupes de K-Fêt-eux-ses")), + ] + + settings_panels = Page.settings_panels + [ + FieldPanel('custom_template'), + ] + + class Meta: + verbose_name = _('page K-Fêt') + verbose_name_plural = _('pages K-Fêt') + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.template = "kfetcms/base.html" + + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + page = context['page'] + + if not page.seo_title: + page.seo_title = page.title + + if self.slug == "carte": + context.update(get_articles(request)) + + return context + + def get_template(self, request, *args, **kwargs): + return self.custom_template or ( + super().get_template(request, *args, **kwargs)) + + +class KFetPageGroupTeam(Orderable, models.Model): + page = ParentalKey(KFetPage, related_name='team_groups') + group = models.ForeignKey( + 'kfetcms.GroupTeam', + verbose_name=_('Groupe de K-Fêt-eux-ses'), + related_name='+', + ) + title = models.CharField( + verbose_name=_('Titre du groupe'), + max_length=255, + blank=True, + ) + content = RichTextField( + verbose_name=_('Texte de présentation du groupe'), + ) + show_only = models.IntegerField( + verbose_name=_('Montrer seulement'), + blank=True, null=True, default=None, + help_text=_( + 'Nombre de membres du groupe affichés initialement. Laisser vide ' + 'pour tou-te-s les afficher.' + ), + ) + + panels = [ + FieldPanel('title', classname='full'), + FieldPanel('show_only', classname='full'), + FieldPanel('content', classname='full'), + SnippetChooserPanel('group'), + ] + + +@register_snippet +class GroupTeam(ClusterableModel): + name = models.CharField( + verbose_name=_('Nom'), + max_length=255, + ) + + class Meta: + verbose_name = _('Groupe de K-Fêt-eux-ses') + verbose_name_plural = _('Groupes de K-Fêt-eux-ses') + + def __str__(self): + return self.name + + panels = [ + FieldPanel('name', classname='full'), + InlinePanel('members', label=_('Membres du groupe')), + ] + + +@register_snippet +class MemberTeam(Orderable, models.Model): + group = ParentalKey( + GroupTeam, + verbose_name=_("Groupe de K-Fêt-eux-ses"), + on_delete=models.CASCADE, + related_name='members', + ) + first_name = models.CharField( + verbose_name=_('Prénom'), + max_length=255, + blank=True, default='', + ) + last_name = models.CharField( + verbose_name=_('Nom'), + max_length=255, + blank=True, default='', + ) + nick_name = models.CharField( + verbose_name=_('Alias'), + max_length=255, + blank=True, default='', + ) + photo = models.ForeignKey( + 'wagtailimages.Image', + verbose_name=_('Photo'), + on_delete=models.SET_NULL, + null=True, blank=True, + related_name='+', + ) + + class Meta: + verbose_name = _('K-Fêt-eux-se') + + def __str__(self): + return self.get_full_name() + + panels = [ + FieldPanel('first_name'), + FieldPanel('last_name'), + FieldPanel('nick_name'), + FieldPanel('group'), + ImageChooserPanel('photo'), + ] + + def get_full_name(self): + full_name = '{} {}'.format(self.first_name, self.last_name) + return full_name.strip() diff --git a/kfet/cms/static/kfetcms/css/index.css b/kfet/cms/static/kfetcms/css/index.css new file mode 100644 index 00000000..ff175df6 --- /dev/null +++ b/kfet/cms/static/kfetcms/css/index.css @@ -0,0 +1,155 @@ +.cms-content { + text-align: justify; + font-size: 1.1em; +} + +@media (min-width:768px) { + .cms-content { + font-size: 1.2em; + line-height: 1.6em; + } +} + +.cms-column { + column-gap: 45px; + + padding: 20px 15px; + background: white; +} + +@media (min-width: 768px) { + .cms-column { + padding: 35px 30px; + } +} + +@media (min-width: 992px) { + .cms-column { + margin: 0 15px; + } +} + + +/* Titles */ + +.cms-content h2, .cms-content h3 { + clear: both; + margin: 0 0 15px; + padding-bottom: 10px; + border-bottom: 1px solid #c8102e; + text-align: left; + font-weight: bold; +} + +@media (min-width: 768px) { + .cms-content h2, .cms-content h3 { + padding-bottom: 15px; + } +} + +/* Paragraphs */ + +.cms-content p { + margin-bottom: 20px; + text-indent: 2em; +} + +.cms-content p + :not(h2):not(h3):not(div) { + margin-top: -10px; +} + +@media (min-width: 768px) { + .cms-content p { + padding-bottom: 15px; + } + + .cms-content p + :not(h2):not(h3):not(div) { + margin-top: -30px; + } +} + + +/* Lists */ + +.cms-content ol, .cms-content ul { + padding: 0 0 0 15px; + margin: 0 0 10px; +} + +.cms-content ul { + list-style-type: square; +} + +.cms-content ol > li, .cms-content ul > li { + padding-left: 5px; +} + + +/* Images */ + +.cms-content .richtext-image { + max-height: 100%; + margin: 5px 0 15px; +} + +.cms-content .richtext-image.left { + float: left; + margin-right: 30px; +} + +.cms-content .richtext-image.right { + float: right; + margin-left: 30px; +} + + +/* Team groups & members */ + +.team-group { + margin-bottom: 20px; +} + +.team-group .col-btn { + margin-bottom: 20px; +} + +.team-group .member-more { + display: none; +} + +.team-member { + padding: 0; + margin-bottom: 20px; + min-height: 190px; + background-color: inherit; + border: 0; +} + +.team-member img { + max-width: 100%; + max-height: 125px; + width: auto; + height: auto; + display: block; +} + +.team-member .infos { + height: 50px; + margin-top: 15px; +} + +@media (min-width: 768px) { + .team-group { + margin-left: 20px; + margin-right: 20px; + } + + .team-member { + min-height: 215px; + } + + .team-member img { + max-height: 150px; + } +} + diff --git a/kfet/cms/templates/kfetcms/base.html b/kfet/cms/templates/kfetcms/base.html new file mode 100644 index 00000000..043c9ba5 --- /dev/null +++ b/kfet/cms/templates/kfetcms/base.html @@ -0,0 +1,68 @@ +{% extends "kfet/base.html" %} +{% load static %} +{% load wagtailuserbar %} +{% load wagtailcore_tags %} + +{% block extra_head %} + +{% endblock %} + +{% block title %}{{ page.seo_title }}{% endblock %} + +{% block header-class %}text-center{% endblock %} +{% block header-title %}{{ page.title }}{% endblock %} + +{% block content %} + +
    + {% include "kfet/base_messages.html" %} +
    + +
    +
    +
    + {% block block1-content %} + {% endblock %} + + {% block block2-content %} + {{ page.content|richtext }} + {% endblock %} + + {% block block3-content %} + {% endblock %} +
    +
    +
    + +{% wagtailuserbar %} + + + +{% endblock %} + +{% block footer %} +{% include "kfet/base_footer.html" %} +{% endblock %} diff --git a/kfet/cms/templates/kfetcms/carte.html b/kfet/cms/templates/kfetcms/carte.html new file mode 100644 index 00000000..3a32624b --- /dev/null +++ b/kfet/cms/templates/kfetcms/carte.html @@ -0,0 +1,46 @@ +{% extends "kfetcms/base.html" %} +{% load static %} +{% load kfet_tags %} + +{% block extra_head %} +{{ block.super }} + +{% endblock %} + +{% block col-size %}column-sm-2 column-md-3{% endblock %} + +{% block block3-content %} + +{% if pressions %} +
    +

    Pressions du moment

    +
      + {% for article in pressions %} +
    • +
      + {{ article.name }} + {{ article.price | ukf:False}} UKF +
    • + {% endfor %} +
    +
    +{% endif %} + +{% regroup articles by category as categories %} + +{% for category in categories %} +
    +

    {{ category.grouper.name }}

    +
      + {% for article in category.list %} +
    • +
      + {{ article.name }} + {{ article.price | ukf:False}} UKF +
    • + {% endfor %} +
    +
    +{% endfor %} + +{% endblock %} diff --git a/kfet/cms/templates/kfetcms/equipe.html b/kfet/cms/templates/kfetcms/equipe.html new file mode 100644 index 00000000..2295957f --- /dev/null +++ b/kfet/cms/templates/kfetcms/equipe.html @@ -0,0 +1,67 @@ +{% extends "kfetcms/base.html" %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} + +{% block block1-content %} + +{% for group_block in page.team_groups.all %} +

    {{ group_block.title }}

    +
    + {{ group_block.content|richtext }} +
    + +{% with members=group_block.group.members.all %} +{% with len=members|length %} + +{% if len > 0 %} +
    + + {% if len == 2 %} +
    + {% endif %} + + {% for member in members %} +
    +
    + {% image member.photo max-200x500 %} +
    + {{ member.get_full_name }} +
    + {% if member.nick_name %} + alias {{ member.nick_name }} + {% endif %} +
    +
    +
    + {% endfor %} + + {% if group_block.show_only != None and len > group_block.show_only %} +
    + +
    + {% endif %} + +
    +{% endif %} + +{% endwith %} +{% endwith %} + +{% endfor %} + + + +{% endblock %} diff --git a/kfet/management/commands/loadkfetdevdata.py b/kfet/management/commands/loadkfetdevdata.py index 7f2ec9a3..6dd25f29 100644 --- a/kfet/management/commands/loadkfetdevdata.py +++ b/kfet/management/commands/loadkfetdevdata.py @@ -147,3 +147,9 @@ class Command(MyBaseCommand): # --- call_command('createopes', '100', '7', '--transfers=20') + + # --- + # Wagtail CMS + # --- + + call_command('kfet_loadwagtail') diff --git a/kfet/models.py b/kfet/models.py index d218dd2d..eb33daf7 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -78,7 +78,7 @@ class Account(models.Model): def __str__(self): return '%s (%s)' % (self.trigramme, self.name) - # Propriétés pour accéder aux attributs de user et cofprofile et user + # Propriétés pour accéder aux attributs de cofprofile et user @property def user(self): return self.cofprofile.user @@ -120,6 +120,14 @@ class Account(models.Model): def need_comment(self): return self.trigramme == '#13' + @property + def readable(self): + return self.trigramme != 'GNR' + + @property + def is_team(self): + return self.has_perm('kfet.is_team') + @staticmethod def is_validandfree(trigramme): data = { 'is_valid' : False, 'is_free' : False } diff --git a/kfet/signals.py b/kfet/signals.py index e81f264a..6bbbbbb0 100644 --- a/kfet/signals.py +++ b/kfet/signals.py @@ -4,6 +4,7 @@ from django.contrib import messages from django.contrib.auth.signals import user_logged_in from django.core.urlresolvers import reverse from django.dispatch import receiver +from django.utils.html import mark_safe @receiver(user_logged_in) @@ -11,8 +12,9 @@ def messages_on_login(sender, request, user, **kwargs): if (not user.username == 'kfet_genericteam' and user.has_perm('kfet.is_team') and 'k-fet' in request.GET.get('next', '')): - messages.info( - request, - ('Connexion en utilisateur partagé ?' - .format(reverse('kfet.login.genericteam'))), - extra_tags='safe') + messages.info(request, mark_safe( + '' + ' Connexion en utilisateur partagé ?' + '' + .format(reverse('kfet.login.genericteam')) + )) diff --git a/kfet/static/kfet/css/footer.css b/kfet/static/kfet/css/footer.css new file mode 100644 index 00000000..5e8d1474 --- /dev/null +++ b/kfet/static/kfet/css/footer.css @@ -0,0 +1,19 @@ +.footer { + line-height: 40px; + + background: #c63b52; + color: white; + + text-align: center; + font-size: 14px; + font-family: Roboto; +} + +.footer a { + color: inherit; +} + +.footer a:hover, .footer a:focus { + color: inherit; + text-decoration: underline; +} diff --git a/kfet/static/kfet/css/history.css b/kfet/static/kfet/css/history.css index dff7a455..9cd4cd28 100644 --- a/kfet/static/kfet/css/history.css +++ b/kfet/static/kfet/css/history.css @@ -9,9 +9,10 @@ #history .day { height:40px; line-height:40px; - background-color:rgba(200,16,46,0.9); + background-color:rgba(200,16,46,1); color:#fff; padding-left:20px; + font-family:"Roboto Slab"; font-size:16px; font-weight:bold; position:sticky; @@ -22,7 +23,7 @@ #history .opegroup { height:30px; line-height:30px; - background-color:rgba(200,16,46,0.75); + background-color: #c63b52; color:#fff; font-weight:bold; padding-left:20px; diff --git a/kfet/static/kfet/css/home.css b/kfet/static/kfet/css/home.css index 718159c3..f1952c69 100644 --- a/kfet/static/kfet/css/home.css +++ b/kfet/static/kfet/css/home.css @@ -1,54 +1,58 @@ -ul.carte { +.carte { + margin-bottom: 15px; + font-family: "Roboto Slab"; +} + +.carte .carte-title { + padding-top: 0; + margin-top: 0; + margin-bottom: 0; +} + +.carte .carte-list { width: 100%; + padding: 15px; list-style-type: none; - padding-left: 15px; - padding-right: 15px; - display: inline-block; - *display: inline; - zoom: 1; - position: relative; - clip: auto; - overflow: hidden; } -/* -ul.carte > li { - border-style: none none solid none; - border-width: 1px; - border-color: #DDD; -} -*/ -li.carte-line { + +.carte .carte-item { position: relative; text-align: right; white-space: nowrap; + padding: 0; } -.filler { + +.carte .carte-item .filler { position: absolute; left: 0; right: 0; - border-bottom: 3px dotted #333; - height: 70%; + border-bottom: 2px dotted #333; + height: 75%; } -.carte-label { + +.carte .carte-item > span { + position: relative; +} + +.carte .carte-item .carte-label { background: white; float: left; - padding-right: 4px; - position: relative; - max-width: calc(100% - 40px); - overflow: hidden; + padding-right: 10px; text-overflow: ellipsis; + overflow: hidden; white-space: nowrap; } -.carte-ukf { +.carte .carte-item .carte-ukf { + padding: 0 10px; + background: #ffdbc7; +} + +.carte-inverted .carte-list, +.carte-inverted .carte-item .carte-label { + background: #ffdbc7; +} + +.carte-inverted .carte-item .carte-ukf { background: white; - padding-left: 4px; - position: relative; -} - - -.unbreakable.carte-inverted .carte-ukf, -.unbreakable.carte-inverted .carte-label, -.unbreakable.carte-inverted { - background: #FFDBC7; } diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css index 15b425e2..04fbaeb1 100644 --- a/kfet/static/kfet/css/index.css +++ b/kfet/static/kfet/css/index.css @@ -1,4 +1,5 @@ @import url("nav.css"); +@import url("footer.css"); @import url("kpsul.css"); @import url("jconfirm-kfet.css"); @import url("history.css"); @@ -10,11 +11,11 @@ body { } h1,h2,h3,h4,h5,h6 { - font-family:Oswald; + font-family:"Roboto Slab"; } a { - color:#333; + color:#C8202E; } a:focus, a:hover { @@ -30,6 +31,10 @@ textarea { border-radius:0 !important; } +.glyphicon + span, span + .glyphicon { + margin-left: 10px; +} + .table { margin-bottom:0; border-bottom:1px solid #ddd; @@ -57,7 +62,7 @@ textarea { } .table tr.section { - background:rgba(200,16,46,0.9); + background:#c8102e; color:#fff; font-weight:bold; } @@ -68,14 +73,26 @@ textarea { padding:8px 30px; } +.table-hover > tbody > tr.section:hover { + background:#c8102e; +} + .table-responsive { border: 0; margin-bottom: 0; } .btn { + border: 0; + transition: background-color, color; transition-duration: 0.15s; + + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + + font-family: "Roboto Slab"; } .btn, .btn-lg, .btn-group-lg>.btn { @@ -83,8 +100,7 @@ textarea { } .btn-primary { - font-family:Oswald; - background-color:rgba(200,16,46,0.9); + background-color:#c63b52; color:#FFF; border:0; } @@ -95,7 +111,8 @@ textarea { .btn-primary:active.focus, .btn-primary:active:focus, .btn-primary:active:hover, .nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover { outline: 0; - background-color:rgba(200,16,46,1); + background-color:#bf0f2c; + background-color:#c8102e; color:#FFF; } @@ -115,17 +132,15 @@ textarea { color:#FFF; } -.row-page-header { +.header-row { background-color:rgba(200,16,46,1); color:#FFF; - border-bottom:3px solid #000; } .page-header { border:0; padding:0; margin:15px 20px; - text-transform:uppercase; font-weight:bold; } @@ -137,41 +152,49 @@ textarea { padding:0; } + @media (min-width: 768px) { .col-content-left { position: sticky; top:50px; + margin-bottom: 15px; } } .content-left-top { background:#fff; - padding:10px 30px; + padding:15px; } -.content-left .buttons { - background:#fff; +@media (min-width: 1200px) { + .content-left-top { + padding: 30px; + } } -.content-left .buttons .btn { - display:block; +.content-left .btn-lg { + font-size: 16px; } -.content-left .buttons ul.nav-pills { - margin-bottom:5px; +.btn-actions { + margin: 0 -15px; } -.content-left .buttons ul.nav-pills li { - margin:0 0 -5px; +.btn-actions .btn { + color: inherit; +} + +.btn-actions .btn:not([disabled]):hover, .btn-actions .btn:not([disabled]):focus { + color: #c8102e; } .content-left-top.frozen-account { - background:#000FBA; + background:#5072e0; color:#fff; } .content-left .block { - padding-top:25px; + padding-top:15px; } .content-left .block .line { @@ -180,10 +203,11 @@ textarea { } .content-left .line.line-big { - font-family:Oswald; + font-family:"Roboto Slab"; font-size:60px; font-weight:bold; text-align:center; + overflow:hidden; } .content-left .line.line-bigsub { @@ -197,6 +221,12 @@ textarea { text-align:center; } +@media (min-width: 1200px) { + .content-left .line.line-big { + margin-top: -15px; + } +} + @media (min-width: 768px) { .content-right { margin: 15px; @@ -204,6 +234,7 @@ textarea { } .content-right-block { + margin-top: 15px; position:relative; } @@ -239,6 +270,15 @@ textarea { font-size:25px; } +.content-right-block a:not(.btn) { + color:#000; +} + +.content-right-block a:not(.btn):focus , +.content-right-block a:not(.btn):hover { + color:#C81022; +} + /* * Pages tableaux seuls */ @@ -251,6 +291,11 @@ textarea { .content-center { margin: 15px 0; } + + .column-row { + margin-top: 15px; + margin-bottom: 15px; + } } .content-center tbody tr:not(.section) td { @@ -261,6 +306,11 @@ textarea { padding: 1px 12px ; height:28px; margin:3px 0px; + background: transparent; +} + +.table .form-control[disabled], .table .form-control[readonly] { + background: #f5f5f5; } .table-condensed input.form-control { @@ -349,10 +399,6 @@ textarea { * Messages */ -.messages { - margin: 0; -} - .messages .alert { padding:10px 15px; margin:0; @@ -360,10 +406,6 @@ textarea { border-radius:0; } -.messages .alert-dismissible { - padding-right:35px; -} - .messages .alert .close { top:0; right:0; @@ -375,12 +417,18 @@ textarea { } .messages .alert-error { - color:inherit; - background-color:rgba(200,16,46,0.2); + color: white; + background-color: #c63b52; } .messages .alert-success { - color:#333; + color: white; + background: #3d9947; +} + +.messages a { + font-weight: bold; + text-decoration: none; } /* @@ -403,7 +451,7 @@ textarea { margin-top:30px; padding-top:1px; padding-bottom:15px; - background:rgba(51,51,51,0.7); + background:rgba(51,51,51,0.9); color:#fff; } @@ -449,145 +497,43 @@ thead .tooltip { width: 100%; } - -.column-row { - padding: 15px 20px; -} - -.column-xs-1, -.column-sm-1, -.column-md-1, -.column-lg-1, -.column-xs-2, -.column-sm-2, -.column-md-2, -.column-lg-2, -.column-xs-3, -.column-sm-3, -.column-md-3, -.column-lg-3, -.column-xs-4, -.column-sm-4, -.column-md-4, -.column-lg-4, -.column-xs-5, -.column-sm-5, -.column-md-5, -.column-lg-5 { - -webkit-column-count: 1; /* Chrome, Safari, Opera */ - -moz-column-count: 1; /* Firefox */ +.column-xs-1, .column-sm-1, .column-md-1, .column-lg-1, +.column-xs-2, .column-sm-2, .column-md-2, .column-lg-2, +.column-xs-3, .column-sm-3, .column-md-3, .column-lg-3, +.column-xs-4, .column-sm-4, .column-md-4, .column-lg-4, +.column-xs-5, .column-sm-5, .column-md-5, .column-lg-5 { column-count: 1; + column-gap: 0; } - -.column-xs-1 { - -webkit-column-count: 1; /* Chrome, Safari, Opera */ - -moz-column-count: 1; /* Firefox */ - column-count: 1; -} -.column-xs-2 { - -webkit-column-count: 2; /* Chrome, Safari, Opera */ - -moz-column-count: 2; /* Firefox */ - column-count: 2; -} -.column-xs-3 { - -webkit-column-count: 3; /* Chrome, Safari, Opera */ - -moz-column-count: 3; /* Firefox */ - column-count: 3; -} -.column-xs-4 { - -webkit-column-count: 4; /* Chrome, Safari, Opera */ - -moz-column-count: 4; /* Firefox */ - column-count: 4; -} -.column-xs-5 { - -webkit-column-count: 5; /* Chrome, Safari, Opera */ - -moz-column-count: 5; /* Firefox */ - column-count: 5; -} - -@media (min-width: 576px) { - .column-sm-1 { - -webkit-column-count: 1; /* Chrome, Safari, Opera */ - -moz-column-count: 1; /* Firefox */ - column-count: 1; - } - .column-sm-2 { - -webkit-column-count: 2; /* Chrome, Safari, Opera */ - -moz-column-count: 2; /* Firefox */ - column-count: 2; - } - .column-sm-3 { - -webkit-column-count: 3; /* Chrome, Safari, Opera */ - -moz-column-count: 3; /* Firefox */ - column-count: 3; - } - .column-sm-4 { - -webkit-column-count: 4; /* Chrome, Safari, Opera */ - -moz-column-count: 4; /* Firefox */ - column-count: 4; - } - .column-sm-5 { - -webkit-column-count: 5; /* Chrome, Safari, Opera */ - -moz-column-count: 5; /* Firefox */ - column-count: 5; - } -} +.column-xs-1 { column-count: 1; } +.column-xs-2 { column-count: 2; } +.column-xs-3 { column-count: 3; } +.column-xs-4 { column-count: 4; } +.column-xs-5 { column-count: 5; } @media (min-width: 768px) { - .column-md-1 { - -webkit-column-count: 1; /* Chrome, Safari, Opera */ - -moz-column-count: 1; /* Firefox */ - column-count: 1; - } - .column-md-2 { - -webkit-column-count: 2; /* Chrome, Safari, Opera */ - -moz-column-count: 2; /* Firefox */ - column-count: 2; - } - .column-md-3 { - -webkit-column-count: 3; /* Chrome, Safari, Opera */ - -moz-column-count: 3; /* Firefox */ - column-count: 3; - } - .column-md-4 { - -webkit-column-count: 4; /* Chrome, Safari, Opera */ - -moz-column-count: 4; /* Firefox */ - column-count: 4; - } - .column-md-5 { - -webkit-column-count: 5; /* Chrome, Safari, Opera */ - -moz-column-count: 5; /* Firefox */ - column-count: 5; - } + .column-sm-1 { column-count: 1; } + .column-sm-2 { column-count: 2; } + .column-sm-3 { column-count: 3; } + .column-sm-4 { column-count: 4; } + .column-sm-5 { column-count: 5; } } @media (min-width: 992px) { - .column-lg-1 { - -webkit-column-count: 1; /* Chrome, Safari, Opera */ - -moz-column-count: 1; /* Firefox */ - column-count: 1; - } - .column-lg-2 { - -webkit-column-count: 2; /* Chrome, Safari, Opera */ - -moz-column-count: 2; /* Firefox */ - column-count: 2; - } - .column-lg-3 { - -webkit-column-count: 3; /* Chrome, Safari, Opera */ - -moz-column-count: 3; /* Firefox */ - column-count: 3; - } - .column-lg-4 { - -webkit-column-count: 4; /* Chrome, Safari, Opera */ - -moz-column-count: 4; /* Firefox */ - column-count: 4; - } - .column-lg-5 { - -webkit-column-count: 5; /* Chrome, Safari, Opera */ - -moz-column-count: 5; /* Firefox */ - column-count: 5; - } + .column-md-1 { column-count: 1; } + .column-md-2 { column-count: 2; } + .column-md-3 { column-count: 3; } + .column-md-4 { column-count: 4; } + .column-md-5 { column-count: 5; } +} + +@media (min-width: 1200px) { + .column-lg-1 { column-count: 1; } + .column-lg-2 { column-count: 2; } + .column-lg-3 { column-count: 3; } + .column-lg-4 { column-count: 4; } + .column-lg-5 { column-count: 5; } } /* Inventaires */ diff --git a/kfet/static/kfet/css/jconfirm-kfet.css b/kfet/static/kfet/css/jconfirm-kfet.css index 1aee70f1..1e05a816 100644 --- a/kfet/static/kfet/css/jconfirm-kfet.css +++ b/kfet/static/kfet/css/jconfirm-kfet.css @@ -5,7 +5,7 @@ .jconfirm .jconfirm-box { padding:0; border-radius:0 !important; - font-family:"Roboto Mono"; + font-family:Roboto; } .jconfirm .jconfirm-box div.title-c .title { @@ -28,7 +28,6 @@ .jconfirm .jconfirm-box .content { border-bottom:1px solid #ddd; - padding:5px 10px; } .jconfirm .jconfirm-box input { @@ -37,6 +36,7 @@ border:0; + font-family:"Roboto Mono"; font-size:40px; text-align:center; @@ -49,6 +49,7 @@ } .jconfirm .jconfirm-box .buttons button { + width:40px; height:100%; margin:0; margin:0 !important; diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index 4b60aa7b..351ac0aa 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -143,9 +143,10 @@ input[type=number]::-webkit-outer-spin-button { height:50px; padding:0 15px; - background:rgba(200,16,46,0.9); + background:rgba(200,16,46,1); color:#fff; + font-family:"Roboto Slab"; font-weight:bold; font-size:18px; } @@ -226,16 +227,10 @@ input[type=number]::-webkit-outer-spin-button { height:40px; } -#special_operations button { - height:100%; - width:25%; +#special_operations .btn { + height:40px; - float:left; - - background: rgba(200,16,46,0.9); - color:#FFF; - - font-size:18px; + font-size:15px; font-weight:bold; text-overflow: ellipsis; @@ -243,12 +238,6 @@ input[type=number]::-webkit-outer-spin-button { overflow: hidden; } -#special_operations button:focus, -#special_operations button:hover { - outline:none; - background: rgba(200,16,46,1); - color:#fff; -} /* Article autocomplete */ @@ -317,16 +306,22 @@ input[type=number]::-webkit-outer-spin-button { font-size:14px; } -#articles_data table tr.article>td:first-child { +#articles_data table tr.article td:first-child { padding-left:10px; } +#articles_data table tr.article td + td { + padding-right:10px; + text-align:right; +} + #articles_data table tr.category { height:35px; - background-color:rgba(200,16,46,0.9); + background-color:#c8102e; + font-family:"Roboto Slab"; font-size:16px; - color:#FFF; font-weight:bold; + color:#FFF; } #articles_data table tr.category>td:first-child { diff --git a/kfet/static/kfet/css/nav.css b/kfet/static/kfet/css/nav.css index a4dabed2..0efc2873 100644 --- a/kfet/static/kfet/css/nav.css +++ b/kfet/static/kfet/css/nav.css @@ -1,54 +1,98 @@ .navbar { background: #000; color: #DDD; - font-family: Oswald; border: 0; + font-family: Roboto; +} + +.navbar .navbar-header { + float: left; + display: none; + margin-left: -15px; + margin-right: 0; } .navbar .navbar-brand { - padding: 3px 25px; + padding: 3px 0; + margin: 0 15px !important; } .navbar .navbar-brand img { height: 44px; } +.navbar .navbar-toggle { + border: 0; + border-radius: 0; + padding: 18px 15px; + margin: 0; + min-width: auto; +} + .navbar .navbar-toggle .icon-bar { - background-color: #FFF; + background: #fff; } .navbar-nav { - font-weight: bold; font-size: 14px; - text-transform: uppercase; - margin: 0 -15px; + margin: 0 0 0 -15px; + float: left; } -@media (min-width: 768px) { +@media (min-width: 460px) { + .navbar .navbar-header { + display: block; + } + .navbar-nav { - margin: 0px; + margin-left: 0; } - .navbar-right { - margin-right: -15px; + + .navbar-nav .nav-pages.dropdown .dropdown-menu > li:first-child { + display: none; } } +.navbar-right { + float: right !important; + margin: 0 -15px 0 0; +} + .navbar-nav a { transition: background-color, box-shadow, color; transition-duration: 0.15s; } +.navbar-nav > li { + float: left; + text-align: center; +} + .navbar-nav > li > a { + min-width: 50px; + padding: 15px 10px; color: #FFF; } -.navbar-nav > li:hover > a, -.navbar-nav > li > a:focus, -.nav .open > a:hover, -.nav .open > a:focus { +.navbar-nav > .divider { + height: 1px; + background: rgba(255, 255, 255, 0.1); +} + +@media (min-width: 1200px) { + .navbar-nav > li > a { + padding-left: 15px; + padding-right: 15px; + } +} + +.navbar-nav > li > a:hover, .navbar-nav > li > a:focus, +.nav .open > a:hover, .nav .open > a:focus, +.navbar-nav > li.active > a, +.navbar-nav .dropdown:hover > a, .navbar-nav .dropdown:focus > a { background-color: #C8102E; color: #FFF; - box-shadow: inset 0 5px 5px -5px #000; + box-shadow: inset 0 3px 3px -4px #000; } .navbar-nav .dropdown .dropdown-menu { @@ -56,15 +100,22 @@ border: 0; border-radius: 0; background-color: #FFF; + font-size: 14px; + + /* override max-width: 767px of bs */ + position: absolute; + float: left; + box-shadow: 0 6px 12px rgba(0,0,0,.175); } .navbar-nav .dropdown .dropdown-menu > li > a { - padding: 8px 20px; + padding: 8px 10px; + line-height: inherit; color: #000; } .navbar-nav .dropdown .dropdown-menu > li > a:hover, -.navbar-nav .dropdown .dropdown-meny > li > a:focus { +.navbar-nav .dropdown .dropdown-menu > li > a:focus { color: #c8102e; background-color: transparent; } @@ -73,16 +124,28 @@ margin: 0; } -@media (min-width: 768px) { - .navbar-nav .dropdown .dropdown-menu { - display: block; - visibility: hidden; - opacity: 0; - transition: opacity 0.15s; - } +.navbar-nav .dropdown .dropdown-menu { + display: block; + visibility: hidden; + opacity: 0; + transition: opacity 0.15s; +} - .nav .dropdown:hover .dropdown-menu { - visibility: visible; - opacity: 1; +.navbar-nav .dropdown:hover > .dropdown-menu, +.navbar-nav .dropdown:focus > .dropdown-menu, +.navbar-nav .dropdown.open > .dropdown-menu { + visibility: visible; + opacity: 1; +} + +@media (min-width: 992px) { + .navbar-nav .dropdown .dropdown-menu > li > a { + padding-left: 20px; + padding-right: 20px; } } + +.nav-app .dropdown-menu { + right: 0; + left: auto; +} diff --git a/kfet/static/kfet/img/favicon.png b/kfet/static/kfet/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..56fb42995770e3b66dcb1d383c634ebfb81fa8d4 GIT binary patch literal 3606 zcmV+x4(aiUP)9NB^z?L`GiT0&C4lG!3y==~ z*s_IlzNhl@vAeq)Nnkdc(QG!O$z(#EPKR2p7Be$5F(xJk)6&xL_U+sEgolW@`(H`o z7eFshPfSTkA*z6r`KLMKE0@c$uC5N9iLS0L@d{wh+_`w>>{&G3*J9{UT3X5(|JK%4 zbT-UpGx`r1Vw1nCkhA}{X=(8MbI%FFTOyIbl`B`k)6fK)1l zmfu@I>7``#e_Ka~!+F@aX%mbXF@m=;2L=R)XCIK9oXooN0RZyyPCCSYa%d=guw@Is zYkfrV2p~2#)}jAT96#pJ{}~w>k9We3w4{r_{>u9QMQ^?dzJmsdraZ)Rz^IWU;mXyk zoG@LqXc6q+zn`@LIvkh-)~#DdoYrJAL3VaFR8&+zMMVYNxN!qQLPB6>WF!Ox1VHBZ z-@}?UYe1n;(9$Zsa)rGr!q?Xq5fM{TQaD@wWo2ixTGFK+IKY~xzrQ~*pR~h=iD*hB z68tDRnUa>tWMaP$m_B0$Ha0dQBBIe~L{CpoP6XiP<;A%2jYcE(@7Iqt&z#&`VqP8! z1tZ$~zx>iJt(KM+b^_S3V}}*7gv3Nn1fWu>7z^M(-+bc`&)V8rB0fz`O^j)~xw)Z6 zqp?Zv=+UFh1+aeodb=6qLMzB*I6y=^ecEyLgTY`R;+2z=!wcA5tt>xR5mui9~{hg@u0%nI;ns4-RH7fTW}($_)DX`8iY(3J(wB z%D8Z$h?B}^(&M<`=kD%KI#O7^aB*>=RZ#VDP#?c^=~Cj#2n-D5q(TCNf{6GvHa7CD zknGVq6$&(&OipVda=Dzi@^f-?IVIJ5~{v2rDG+P}Z> z0%to;qsc^+POH@ltBR0HsbzBVRK7zD|G8}&QMw&FcS3V>GiL?$@bDl?$0bj8x*&;! zdP`k;nKiT2)KqYFrPqG6wY5R~h7Ft+w5hR?Ox4}iCaeG?GW)CGLB}C~qz4sodFJ2T}0D|`bs%2RXaF=NKi zrb|mths1;gQJhfKH#CTM4#@u>`6f)MRKi(;$+W$_9o~5Tb*C4UbnepLzRkPPEw;wq z-YN^TI<_i^ix)2vZTX#>3Wsri@tsP+RR){O$|}zG<9`$hp<0& z{1*hVL+$MBq|DcU^YU!|H*elNT(xQyexH?v20{z!`w<=5NCO*Hf#aD=I8n`JO#{I5EzpIb*gS!)zfVBZIPV_J*#W7(95eU;=1vZl=xOhaY~3 z)z#I)nWx(mKzw|>T_PTYM~ssuO%l`;zOB6-g@D;?#=xON9XpUID=)YE?Wdm#X#bx* zdp7+1^Us2AvLrOBc4zV(5gbgm5%cr+x0&$9_3Jj@zqNQVgoKQv%)r)d+aND5Pw-u? zf>0ys41|V;l5NDMgoWAM1N5|nkVqsrVZsF3?)UlUpNql;>MzecgF+%JD~oInh>DK3 z`njW{17$LqrB7F{Uf4misyKJg($T6+l8lBAJU)-@bjVx`uwW>-BK!)-BM~)cTV88$X062K?AlVSKdd(Uu>0K_dbdLVvhaV`VeVL^*bx~2# z9~+m52u@nQQmG_1N2Ei0dpq8`bqlv`-_AH6qsNXVUxseqzMaxmGA=HTa=BGiRpqd; z?)mfQIZ=wO->`v`%6I1S*_GrxK&kx0pKC*WJZw!&wA+=`B_%K+B!pF$UbbwR#frgQ zE{9IN9>T)IVOC_M%|rUy+FD3WO|?sN+t#hD^5Ws)0ZOG3%w{vRwY7m>ujfx4?dRub za}qvz@)Tt&DK9T~s3m;y#TTqvXY$7%+cc1kjg4hR@6e$`;x|p~3B6wLa7Om+-OH-N zjvqg6litmnH(Ak(Ua&w|(?p}u$oSmXQLje;fW4o6#_GT7ni{KjqehJaUteDU0MOLc z!K&4(K_Zb58C{)qf=LXcAxP=%O{-4siOkGQPFh1~=oHM!$-!TK`30|CyN1mzE%%%p zDk>^atyZI2t;TEDuVX_)1FA2nQ6ZPxq_twj3Y;~2w#B=OiV9v#(;XUu>?z}@U@#a& z8FQ%TQ&m+ZIssS>L4iYuGVVe$nGE)^976bno0}Ua2lr03im(^cfDW&|@(Oqm_{$23 zmfwG;{@&6eyZ}@xl~tl2kI{z)aCdiyNs}gtS^)Mmy7#MGgn-4Ev}WyEt8www*Iu*f zvf2~p&z~3d91vzh)7ukLsZ`iWc!Q1Y`}pzWi5;uC@SqgZGGfKbmBLQKw&EV#ym=E^ zTU%lE+O@RZY5DTy@E~JS=oDe+fX>cNt3*vrO#lFpoRmZxC}ZQsjl{P2e8ZC<=BS&C zR9FGr-9g%d$z+0$Kly}~=z^FSQ3{}qXXgu60`RwUCVUrh@4joZm)wtaadDy)fVYhm zp4AA@)g`O|da9!}8jaOY2M>KqNi-xRM3hTXSDB1xQz@tbdMe^Fcq%P}=>^#F?Mg}cHzna2GiDI`=JJJLJGMFZ!@$xBkuw1pdbI4| z;lpkIn3zcK(ejzd^h0H3WwdErgzf=d1_N1lZfb&EyLM5gnLBr`=!T(7mo8C$4+;tr zRuy5(xdJGnMA0E8CPq{{;UAA3qYaBDs4Bw8$A^)QeEIU_wB{U6io1`4hYZ2u;$m!U zY{bf{Dpd9EP5aNXWy{2NCP42W05rk(=uXgHc=1I}GyT`7D4X%w?&x&1<}8u3W{Fz> zJ)PNTY}*k4@THetqAXBnXQ!2EBirY5PdyGvkks__bm*ek zLAtxULsV3hLlae0R1_eh-BlR?z~#&Ikz7a&4%~S@ShA2vpFVw<#Jv2|{BHDUr?srj z@4rtJQj#E9VJ$&)Dyr)zCx9EWq%s8O^&SWIZrc}xE7`RBzEw6DFr-KI8_3PnXluxHO6 zyWhP$J)xLE`1y#bPeXBWG3Df$l9IwGk95(vHXsxNsq3gQ~jvdKgL(!OPcg(1YCr002jf9O-nwt0ha8IOXnwufF<9 zyn$Ou@!Qp_u!~|Ya1;p%39xV9K34zc&_sS@+6zV50{{T!3I$_JYZ7eQw8^1-g-1kC z(!WSCKk>Q@<>Gnr$tO9j{1-V;?0M5%9-+}_9v%Sz00smE(1wbkLUnZwCL|={=+UEj zv5?bhwGWp7?mihA8N?yvGmad=m2a=YC!To1DS0_?-~ih@UpRdv!1I;nzP`Q?A0H2a zK|$almqT~A5wy3pP+3_C7YYmE*s)`jnpLi_WXTfPyLYe6Z(Utoyju6+qxj5!_F0-+ zLi``>WvJLudE*AkB~CQm`cd7p&E0);{W4Gj(V!Z7rN zUa#lHvhR`Y0eZcj(kZWbJn z?(S|Yp9q7&0PgPYkB1;#x7&G-lmn c0f-#`2L&H@H(bT$kN^Mx07*qoM6N<$f@V$TK>z>% literal 0 HcmV?d00001 diff --git a/kfet/static/kfet/js/statistic.js b/kfet/static/kfet/js/statistic.js index db31e0e8..d185b604 100644 --- a/kfet/static/kfet/js/statistic.js +++ b/kfet/static/kfet/js/statistic.js @@ -67,7 +67,6 @@ { label: chart.label, borderColor: chart.color, - backgroundColor: chart.color, fill: is_time_chart, lineTension: 0, data: chart_data, diff --git a/kfet/templates/kfet/account.html b/kfet/templates/kfet/account.html index c8d9b4f9..81a7f4ed 100644 --- a/kfet/templates/kfet/account.html +++ b/kfet/templates/kfet/account.html @@ -10,14 +10,27 @@
    compte{{ accounts|length|add:-1|pluralize }}
+{% if perms.kfet.manage_perms or perms.kfet.view_negs %} +
{% if perms.kfet.manage_perms %} + {% endif %} {% if perms.kfet.view_negs %} + {% endif %}
+{% endif %} {% endblock %} @@ -26,16 +39,15 @@

Liste des comptes

- +
- - + - - + + - + @@ -43,15 +55,14 @@ - - + - + {% endfor %} diff --git a/kfet/templates/kfet/account_group.html b/kfet/templates/kfet/account_group.html index 96508aa4..e7243258 100644 --- a/kfet/templates/kfet/account_group.html +++ b/kfet/templates/kfet/account_group.html @@ -5,7 +5,7 @@ {% block fixed-content %} -
+ @@ -40,7 +40,11 @@

Comptes

diff --git a/kfet/templates/kfet/account_negative.html b/kfet/templates/kfet/account_negative.html index e92f3f70..741ad9dd 100644 --- a/kfet/templates/kfet/account_negative.html +++ b/kfet/templates/kfet/account_negative.html @@ -18,7 +18,7 @@ {% if perms.kfet.change_settings %} -
+ {% endif %} @@ -30,14 +30,13 @@

Liste des comptes en négatifs

-
TrigrammeTri. NomBalanceCOFBalanceCOF DptPromoPromo
- + {{ account.trigramme }} {{ account.trigramme }} {{ account.name }} {{ account.balance }}€{{ account.is_cof|yesno:"Oui,Non" }}{{ account.is_cof|yesno }} {{ account.departement }}{{ account.promo|default_if_none:'' }}{{ account.promo|default_if_none:'' }}
+
- - + - - + + @@ -49,10 +48,9 @@ -
TriTri. NomBalanceRéelleBalanceRéelle Début Découvert autorisé Jusqu'au
- + {{ neg.account.trigramme }} {{ neg.account.trigramme }} {{ neg.account.name }} {{ neg.account.balance|floatformat:2 }}€ diff --git a/kfet/templates/kfet/account_read.html b/kfet/templates/kfet/account_read.html index 282e035f..fc8babc5 100644 --- a/kfet/templates/kfet/account_read.html +++ b/kfet/templates/kfet/account_read.html @@ -44,6 +44,10 @@ $(document).ready(function() { {% endif %} {% endblock %} +{% block footer %} +{% include "kfet/base_footer.html" %} +{% endblock %} + {% block fixed-content %} {% include "kfet/left_account.html" %} {% endblock %} diff --git a/kfet/templates/kfet/account_update.html b/kfet/templates/kfet/account_update.html index 86c27b48..47a043a4 100644 --- a/kfet/templates/kfet/account_update.html +++ b/kfet/templates/kfet/account_update.html @@ -20,6 +20,12 @@ {% endif %} {% endblock %} +{% block footer %} +{% if not account.user.is_team %} +{% include "kfet/base_footer.html" %} +{% endif %} +{% endblock %} + {% block main-class %}content-form{% endblock %} {% block main-content %} diff --git a/kfet/templates/kfet/article.html b/kfet/templates/kfet/article.html index 398ef658..86bdc518 100644 --- a/kfet/templates/kfet/article.html +++ b/kfet/templates/kfet/article.html @@ -9,13 +9,18 @@
{{ articles|length }}
article{{ articles|length|pluralize }}
-
+ {% endblock %} @@ -24,10 +29,9 @@

Liste des articles

- +
- @@ -40,16 +44,15 @@ {% for article in articles %} {% ifchanged article.category %} - + {% endifchanged %} - - diff --git a/kfet/templates/kfet/article_read.html b/kfet/templates/kfet/article_read.html index 134fb104..8cd84ded 100644 --- a/kfet/templates/kfet/article_read.html +++ b/kfet/templates/kfet/article_read.html @@ -14,6 +14,14 @@
{{ article.name }}
{{ article.category }}
+
Prix (hors réduc.): {{ article.price }}€
Stock: {{ article.stock }}
@@ -21,11 +29,6 @@
Affiché: {{ article.hidden | yesno:"Non,Oui" }}
- {% endblock %} @@ -36,29 +39,35 @@

Inventaires

-
Nom Prix Stock
{{ article.category.name }}{{ article.category.name }}
+ - + {{ article.name }} {{ article.name }} {{ article.price }}€ {{ article.stock }} {{ article.is_sold | yesno:"En vente,Non vendu"}}
- - - - - - - - - {% for inventoryart in inventoryarts %} - - - - - - {% endfor %} - -
DateStockErreur
{{ inventoryart.inventory.at }}{{ inventoryart.stock_new }}{{ inventoryart.stock_error }}
+
+ + + + + + + + + + {% for inventoryart in inventoryarts %} + + + + + + {% endfor %} + +
DateStockErreur
+ + {{ inventoryart.inventory.at }} + + {{ inventoryart.stock_new }}{{ inventoryart.stock_error }}
+

Prix fournisseurs

- +
diff --git a/kfet/templates/kfet/base.html b/kfet/templates/kfet/base.html index da37abae..b18ee719 100644 --- a/kfet/templates/kfet/base.html +++ b/kfet/templates/kfet/base.html @@ -1,4 +1,5 @@ {% load staticfiles %} +{% load menu_tags %} @@ -7,9 +8,13 @@ {% block title %}{% endblock %} | K-Fêt - ENS Ulm + + + + {# CSS #} - + @@ -28,18 +33,26 @@ - {% include "kfet/base_nav.html" %} + {% main_menu template="kfet/base_nav.html" %}
{% block header %} -
-
-

{% block header-title %}{% endblock %}

+ {% if not page or not page.no_header %} +
+
+

+ {% block header-title %}{% endblock %} +

+
-
+ {% endif %} {% endblock %} + {% block content %}{% endblock %} - {% include "kfet/base_footer.html" %} + + {% block footer %} + {% endblock footer %}
+
diff --git a/kfet/templates/kfet/base_col_1.html b/kfet/templates/kfet/base_col_1.html index a4c26b82..6bd6dd5c 100644 --- a/kfet/templates/kfet/base_col_1.html +++ b/kfet/templates/kfet/base_col_1.html @@ -1,5 +1,7 @@ {% extends "kfet/base.html" %} +{% block header-class %}text-center{% endblock %} + {% block content %}
@@ -9,6 +11,6 @@ {% block main-content %}{% endblock %}
-
+
{% endblock %} diff --git a/kfet/templates/kfet/base_col_2.html b/kfet/templates/kfet/base_col_2.html index 58c36d14..2a1f8cd4 100644 --- a/kfet/templates/kfet/base_col_2.html +++ b/kfet/templates/kfet/base_col_2.html @@ -3,12 +3,12 @@ {% block content %}
-
+
{% block fixed-content %}{% endblock %}
-
+
{% include "kfet/base_messages.html" %}
{% block main-content %}{% endblock %} diff --git a/kfet/templates/kfet/base_footer.html b/kfet/templates/kfet/base_footer.html index e69de29b..be524139 100644 --- a/kfet/templates/kfet/base_footer.html +++ b/kfet/templates/kfet/base_footer.html @@ -0,0 +1,17 @@ +{% load wagtailcore_tags %} + +{% with "k-fet@ens.fr" as kfet_mail %} + + + +{% endwith %} diff --git a/kfet/templates/kfet/base_messages.html b/kfet/templates/kfet/base_messages.html index 66b67162..5dd68e69 100644 --- a/kfet/templates/kfet/base_messages.html +++ b/kfet/templates/kfet/base_messages.html @@ -1,16 +1,12 @@ {% if messages %} -
+
{% for message in messages %} -
-
- - {% if 'safe' in message.tags %} - {{ message|safe }} - {% else %} - {{ message }} - {% endif %} -
-
+
+ + {{ message }} +
{% endfor %}
{% endif %} diff --git a/kfet/templates/kfet/base_nav.html b/kfet/templates/kfet/base_nav.html index 273cdc0b..629b41da 100644 --- a/kfet/templates/kfet/base_nav.html +++ b/kfet/templates/kfet/base_nav.html @@ -1,70 +1,107 @@ -{% load staticfiles %} +{% load static %} +{% load wagtailcore_tags %} - {% endblock %} +{# Footer #} + {% block footer %} {% include "kfet/base_footer.html" %} {% endblock %} diff --git a/kfet/cms/templates/kfetcms/block_menu.html b/kfet/cms/templates/kfetcms/block_menu.html new file mode 100644 index 00000000..382a7770 --- /dev/null +++ b/kfet/cms/templates/kfetcms/block_menu.html @@ -0,0 +1,11 @@ +{% load static %} + +{% if pressions %} + {% include "kfetcms/block_menu_category.html" with title="Pressions du moment" articles=pressions class="carte-inverted" %} +{% endif %} + +{% regroup articles by category as categories %} + +{% for category in categories %} + {% include "kfetcms/block_menu_category.html" with title=category.grouper.name articles=category.list %} +{% endfor %} diff --git a/kfet/cms/templates/kfetcms/block_menu_category.html b/kfet/cms/templates/kfetcms/block_menu_category.html new file mode 100644 index 00000000..ef7d4ce0 --- /dev/null +++ b/kfet/cms/templates/kfetcms/block_menu_category.html @@ -0,0 +1,12 @@ +
+

{{ title }}

+
    + {% for article in articles %} +
  • +
    + {{ article.name }} + {{ article.price_ukf }} UKF +
  • + {% endfor %} +
+
diff --git a/kfet/cms/templates/kfetcms/equipe.html b/kfet/cms/templates/kfetcms/block_teamgroup.html similarity index 51% rename from kfet/cms/templates/kfetcms/equipe.html rename to kfet/cms/templates/kfetcms/block_teamgroup.html index 2295957f..fab43d68 100644 --- a/kfet/cms/templates/kfetcms/equipe.html +++ b/kfet/cms/templates/kfetcms/block_teamgroup.html @@ -1,27 +1,32 @@ -{% extends "kfetcms/base.html" %} -{% load wagtailcore_tags %} -{% load wagtailimages_tags %} +{% load wagtailcore_tags wagtailimages_tags %} -{% block block1-content %} -{% for group_block in page.team_groups.all %} -

{{ group_block.title }}

-
- {{ group_block.content|richtext }} -
+{% with groupteam=value len=value.members|length %} -{% with members=group_block.group.members.all %} -{% with len=members|length %} - -{% if len > 0 %}
{% if len == 2 %}
{% endif %} - {% for member in members %} -
+ {% for member in groupteam.members %} +
{% image member.photo max-200x500 %}
@@ -35,10 +40,10 @@
{% endfor %} - {% if group_block.show_only != None and len > group_block.show_only %} + {% if groupteam.show_only != None and len > groupteam.show_only %}
-{% endif %} {% endwith %} -{% endwith %} - -{% endfor %} - -{% endblock %} diff --git a/kfet/cms/templates/kfetcms/carte.html b/kfet/cms/templates/kfetcms/carte.html deleted file mode 100644 index 3a32624b..00000000 --- a/kfet/cms/templates/kfetcms/carte.html +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "kfetcms/base.html" %} -{% load static %} -{% load kfet_tags %} - -{% block extra_head %} -{{ block.super }} - -{% endblock %} - -{% block col-size %}column-sm-2 column-md-3{% endblock %} - -{% block block3-content %} - -{% if pressions %} -
-

Pressions du moment

-
    - {% for article in pressions %} -
  • -
    - {{ article.name }} - {{ article.price | ukf:False}} UKF -
  • - {% endfor %} -
-
-{% endif %} - -{% regroup articles by category as categories %} - -{% for category in categories %} -
-

{{ category.grouper.name }}

-
    - {% for article in category.list %} -
  • -
    - {{ article.name }} - {{ article.price | ukf:False}} UKF -
  • - {% endfor %} -
-
-{% endfor %} - -{% endblock %} diff --git a/kfet/forms.py b/kfet/forms.py index 95e97d56..85391992 100644 --- a/kfet/forms.py +++ b/kfet/forms.py @@ -25,18 +25,22 @@ from gestioncof.models import CofProfile # ----- class DateTimeWidget(forms.DateTimeInput): - def __init__(self, attrs = None): - super(DateTimeWidget, self).__init__(attrs) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) self.attrs['format'] = '%Y-%m-%d %H:%M' + class Media: css = { - 'all': ('kfet/css/bootstrap-datetimepicker.min.css',) - } - js = ( - 'kfet/js/moment.js', - 'kfet/js/moment-fr.js', - 'kfet/js/bootstrap-datetimepicker.min.js', - ) + 'all': ('kfet/css/bootstrap-datetimepicker.min.css',) + } + js = ( + 'kfet/js/moment.js', + 'kfet/js/moment-fr.js', + 'kfet/js/moment-timezone-with-data-2010-2020.js', + 'kfet/js/bootstrap-datetimepicker.min.js', + ) + + # ----- # Account forms # ----- @@ -459,8 +463,11 @@ class KFetConfigForm(ConfigForm): class FilterHistoryForm(forms.Form): - checkouts = forms.ModelMultipleChoiceField(queryset = Checkout.objects.all()) - accounts = forms.ModelMultipleChoiceField(queryset = Account.objects.all()) + checkouts = forms.ModelMultipleChoiceField(queryset=Checkout.objects.all()) + accounts = forms.ModelMultipleChoiceField(queryset=Account.objects.all()) + from_date = forms.DateTimeField(widget=DateTimeWidget) + to_date = forms.DateTimeField(widget=DateTimeWidget) + # ----- # Transfer forms diff --git a/kfet/models.py b/kfet/models.py index eb33daf7..162d1e90 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -14,7 +14,8 @@ from datetime import date import re import hashlib -from kfet.config import kfet_config +from .config import kfet_config +from .utils import to_ukf def choices_length(choices): return reduce(lambda m, choice: max(m, len(choice[0])), choices, 0) @@ -102,6 +103,10 @@ class Account(models.Model): return self.cofprofile.is_cof # Propriétés supplémentaires + @property + def balance_ukf(self): + return to_ukf(self.balance, is_cof=self.is_cof) + @property def real_balance(self): if hasattr(self, 'negative') and self.negative.balance_offset: @@ -309,6 +314,10 @@ class AccountNegative(models.Model): ('view_negs', 'Voir la liste des négatifs'), ) + @property + def until_default(self): + return self.start + kfet_config.overdraft_duration + class Checkout(models.Model): created_by = models.ForeignKey( @@ -461,6 +470,10 @@ class Article(models.Model): def get_absolute_url(self): return reverse('kfet.article.read', kwargs={'pk': self.pk}) + def price_ukf(self): + return to_ukf(self.price) + + class ArticleRule(models.Model): article_on = models.OneToOneField( Article, on_delete = models.PROTECT, diff --git a/kfet/signals.py b/kfet/signals.py index 6bbbbbb0..374e0dca 100644 --- a/kfet/signals.py +++ b/kfet/signals.py @@ -4,7 +4,7 @@ from django.contrib import messages from django.contrib.auth.signals import user_logged_in from django.core.urlresolvers import reverse from django.dispatch import receiver -from django.utils.html import mark_safe +from django.utils.safestring import mark_safe @receiver(user_logged_in) diff --git a/kfet/static/kfet/css/base/buttons.css b/kfet/static/kfet/css/base/buttons.css new file mode 100644 index 00000000..e7498022 --- /dev/null +++ b/kfet/static/kfet/css/base/buttons.css @@ -0,0 +1,88 @@ +/* General ------------------------- */ + +.btn { + border: 0; + outline: none !important; + + transition: background-color, border, color, opacity; + transition-duration: 0.15s; + + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + + font-family: "Roboto Slab"; +} + +.btn, .btn-lg, .btn-group-lg>.btn { + border-radius:0; +} + + +/* Default ------------------------- */ + +.btn-default { + background-color: transparent !important; + color: #555; +} + +.btn-default:hover, +.btn-default.focus, .btn-default:focus { + color: #c8102e; +} + +.btn-default[disabled]:hover, .btn-default.disabled:hover { + color: inherit !important; +} + + +/* Primary ------------------------- */ + +.btn-primary { + background-color:#c63b52; + color:#FFF; +} + +.btn-primary:hover, +.btn-primary.focus, .btn-primary:focus, +.btn-primary.active.focus, .btn-primary.active:focus, .btn-primary.active:hover, +.btn-primary:active.focus, .btn-primary:active:focus, .btn-primary:active:hover { + background-color:#c8102e; + color:#FFF; +} + + +/* Primary + White background ------ */ + +.btn-primary-w { + background: white; + color: black; +} + +.btn-primary-w:hover { + background: #c63b52; + color: white; +} + +.btn-primary-w.focus, .btn-primary-w:focus, +.btn-primary-w.active.focus, .btn-primary-w.active:focus, .btn-primary-w.active:hover, +.btn-primary-w:active.focus, .btn-primary-w:active:focus, .btn-primary-w:active:hover { + background: #c8102e; + color: white; +} + + +/* Nav ----------------------------- */ + +.btn-nav { + background-color: transparent !important; + color: inherit; + border-bottom: 1px solid #ddd; +} + +.btn-nav:hover, +.btn-nav.focus, .btn-nav:focus, +.btn-nav.active.focus, .btn-nav.active:focus, .btn-nav.active:hover, +.btn-nav:active.focus, .btn-nav:active:focus, .btn-nav:active:hover { + border-bottom: 1px solid #c8102e; +} diff --git a/kfet/static/kfet/css/base/fixed.css b/kfet/static/kfet/css/base/fixed.css new file mode 100644 index 00000000..d198c50f --- /dev/null +++ b/kfet/static/kfet/css/base/fixed.css @@ -0,0 +1,151 @@ +.fixed > * + * { + margin-top: 15px; +} + + +/* Aside --------------------------- */ + +/* Aside - Block */ + +aside { + background: white; + padding: 15px; +} + +aside > * + * { + margin-top: 15px; +} + +/* Aside - Misc */ + +aside .glyphicon-question-sign { + font-size: 0.8; +} + +aside h4 { + font-weight: bold; +} + +/* Aside - Heading */ + +aside .heading { + font-family: "Roboto Slab"; + font-size: 25px; + font-weight: bold; + line-height: 1.1; + text-align: center; +} + +aside .heading .big { + font-size: 2em; +} + +aside .heading .sub { + font-size: 0.7em; + font-weight: normal; +} + +@media (min-width: 992px) { + aside .heading { + font-size: 32px; + line-height: 1.3; + } +} + +/* Aside - Buttons */ + +aside .buttons { + margin-left: -15px; + margin-right: -15px; +} + +aside .buttons > * { + flex: 0 1 auto !important; +} + + +/* Aside - Text */ + +aside .text { + line-height: 1.3; + font-size: 14px; +} + +@media (min-width: 992px) { + aside .text { + line-height: 1.6; + font-size: 16px; + } +} + +aside .text ul { + margin-bottom: 0; +} + + +/* Buttons ------------------------- */ + +.fixed .buttons { + display: flex; + flex-flow: row wrap; + justify-content: center; + + text-align: center; +} + +.fixed .buttons > * { + flex: 0 1 auto; + overflow: hidden; +} + +.fixed .buttons > .solo { + flex: 1 100%; +} + +@media (min-width: 768px) { + .fixed .buttons > * { + flex: 1 auto; + } + + .fixed .buttons > .full > * { + width: 100%; + } +} + +.fixed .buttons .btn { + padding: 8px 12px; +} + +@media (min-width: 992px) { + .fixed .buttons .btn { + font-size: 16px; + } +} + + +/* Tabs ---------------------------- */ + +.fixed .tabs-buttons { + margin-bottom: -5px; +} + +.fixed .tabs-buttons > * { + margin-bottom: 5px; +} + +.fixed .tabs-buttons .glyphicon-chevron-right { + margin-left: 5px; + line-height: 1.4; + color: white; +} + +@media (min-width: 768px) { + .fixed .tabs-buttons { + text-align: right; + justify-content: flex-end; + } + + .fixed .tabs-buttons > * { + flex: 1 100%; + } +} diff --git a/kfet/static/kfet/css/footer.css b/kfet/static/kfet/css/base/footer.css similarity index 85% rename from kfet/static/kfet/css/footer.css rename to kfet/static/kfet/css/base/footer.css index 5e8d1474..abdf98ed 100644 --- a/kfet/static/kfet/css/footer.css +++ b/kfet/static/kfet/css/base/footer.css @@ -10,10 +10,9 @@ } .footer a { - color: inherit; + color: inherit !important; } .footer a:hover, .footer a:focus { - color: inherit; text-decoration: underline; } diff --git a/kfet/static/kfet/css/base/main.css b/kfet/static/kfet/css/base/main.css new file mode 100644 index 00000000..2ebc90d8 --- /dev/null +++ b/kfet/static/kfet/css/base/main.css @@ -0,0 +1,138 @@ +/* Global layout ------------------- */ + +.main-col, .fixed-col { + padding: 0 0 15px; +} + +@media (min-width: 768px) { + .fixed-col { + position: sticky; + top: 35px; + padding-top: 15px; + } + + .fixed-col + .main-col { + padding: 15px 0 15px 15px; + } +} + +@media (min-width: 992px) { + .main-col { + padding: 15px; + } +} + +.main-col-mult { + column-gap: 45px; +} + +.main-bg { + background: white; +} + +.main-padding { + padding: 15px; +} + +@media (min-width: 768px) { + .main-padding { + padding: 30px; + } +} + + +/* Section ------------------------- */ + +section { + margin-bottom: 15px; + position:relative; +} + +section:last-child { + margin-bottom: 0; +} + + +/* Section - Elements -------------- */ + +section > * { + background: white; + padding: 15px; +} + +section > .full, +section > table, +section > .table-responsive { + padding: 0 !important; + margin-left: 0 !important; + margin-right: 0 !important; +} + +section .full { + margin-left: -15px; + margin-right: -15px; +} + +@media (min-width: 992px) { + section > * { + padding: 30px; + } + + section .full { + margin-left: -30px; + margin-right: -30px; + } +} + +section .row > div:last-child { + margin-bottom: 0 !important; +} + +@media (max-width: 768px) { + section .row > div { + margin-bottom: 10px; + } +} + +@media (max-width: 1200px) { + section .row > div { + margin-bottom: 20px; + } +} + +section ul ul { + padding-left: 30px; +} + +/* Titles & Heading */ + +section h2, +section .heading { + background: transparent; + margin: 20px 15px 15px; + padding: 0; + border-bottom: 3px solid #c8102e; + font-family: "Roboto Slab"; + font-size: 40px; + line-height: 1.1; +} + +section h3 { + border-bottom: 2px solid #c8102e; + margin: 0 0 10px; + padding: 10px 0 10px; + font-size: 25px; + font-weight: bold; +} + +section .heading .buttons { + opacity: 0.7; + top: 10px; + float: right; +} + +section h2:first-child, +section h3:first-child { + padding-top: 0; + margin-top: 0; +} diff --git a/kfet/static/kfet/css/base/messages.css b/kfet/static/kfet/css/base/messages.css new file mode 100644 index 00000000..268f514d --- /dev/null +++ b/kfet/static/kfet/css/base/messages.css @@ -0,0 +1,36 @@ +.messages .alert { + padding:10px 15px; + margin:0; + border:0; + border-radius:0; +} + +.messages .alert:last-child { + margin-bottom: 15px; +} + +.messages .alert .close { + top:0; + right:0; +} + +.messages .alert-info { + color:inherit; + background-color:#ccc; +} + +.messages .alert-error { + color: white; + background-color: #c63b52; +} + +.messages .alert-success { + color: white; + background: #3d9947; +} + +.messages a { + font-weight: bold; + text-decoration: none; +} + diff --git a/kfet/static/kfet/css/base/misc.css b/kfet/static/kfet/css/base/misc.css new file mode 100644 index 00000000..9b09edae --- /dev/null +++ b/kfet/static/kfet/css/base/misc.css @@ -0,0 +1,107 @@ +/* General ------------------------- */ + +body { + margin-top:50px; + font-family:Roboto; + background:#ddd; +} + +.glyphicon + span, span + .glyphicon { + margin-left: 10px; +} + +/* Titles */ + +h1,h2,h3,h4,h5,h6 { + font-family:"Roboto Slab"; +} + +/* Links */ + +a { + color:#C8202E; +} + +a:focus, a:hover { + color:#C8102E; +} + +/* Inputs */ + +:focus { + outline:none; +} + +textarea { + font-family:'Roboto Mono'; + border-radius:0 !important; +} + +/* Lists */ + +ul, ol { + padding-left: 30px; +} + +ul { + list-style-type: square; +} + +/* Tables */ + +.table { + margin-bottom:0; + border-bottom:1px solid #ddd; + width:100%; + background-color: #FFF; +} + +.table td { + vertical-align:middle !important; +} + +.table td.no-padding { + padding:0; +} + +.table thead { + background:#c8102e; + color:#fff; + font-weight:bold; + font-size:16px; +} + +.table thead td { + padding:8px !important; +} + +.table tr.section { + background: #c63b52 !important; + color:#fff; + font-weight:bold; +} + +.table tr.section td { + border-top:0; + font-size:16px; + padding:8px 30px; +} + +.table tr.more td { + padding: 0; +} + +.table-responsive { + border: 0; + margin-bottom: 0; +} + +/* Toggle on hover ----------------- */ + +.toggle:not(:hover) .hover { + display: none; +} + +.toggle:hover .base { + display: none; +} diff --git a/kfet/static/kfet/css/nav.css b/kfet/static/kfet/css/base/nav.css similarity index 100% rename from kfet/static/kfet/css/nav.css rename to kfet/static/kfet/css/base/nav.css diff --git a/kfet/static/kfet/css/index.css b/kfet/static/kfet/css/index.css index 04fbaeb1..8e28cce0 100644 --- a/kfet/static/kfet/css/index.css +++ b/kfet/static/kfet/css/index.css @@ -1,306 +1,64 @@ -@import url("nav.css"); -@import url("footer.css"); +/* Libs */ +@import url("libs/columns.css"); + +/* Libs customizations */ +@import url("libs/jconfirm-kfet.css"); +@import url("libs/multiple-select-kfet.css"); + +/* Base */ +@import url("base/misc.css"); +@import url("base/buttons.css"); + +/* Blocks */ +@import url("base/main.css"); +@import url("base/nav.css"); +@import url("base/messages.css"); +@import url("base/fixed.css"); +@import url("base/footer.css"); + +/* Components */ @import url("kpsul.css"); -@import url("jconfirm-kfet.css"); @import url("history.css"); -body { - margin-top:50px; - font-family:Roboto; - background:#ddd; + + +.header { + padding: 15px 20px; + + background-color: rgba(200,16,46,1); + color: #FFF; } -h1,h2,h3,h4,h5,h6 { - font-family:"Roboto Slab"; -} - -a { - color:#C8202E; -} - -a:focus, a:hover { - color:#C8102E; -} - -:focus { - outline:none; -} - -textarea { - font-family:'Roboto Mono'; - border-radius:0 !important; -} - -.glyphicon + span, span + .glyphicon { - margin-left: 10px; -} - -.table { - margin-bottom:0; - border-bottom:1px solid #ddd; - width:100%; - background-color: #FFF; -} - -.table td { - vertical-align:middle !important; -} - -.table td.no-padding { - padding:0; -} - -.table thead { - background:#c8102e; - color:#fff; - font-weight:bold; - font-size:16px; -} - -.table thead td { - padding:8px !important; -} - -.table tr.section { - background:#c8102e; - color:#fff; - font-weight:bold; -} - -.table tr.section td { - border-top:0; - font-size:16px; - padding:8px 30px; -} - -.table-hover > tbody > tr.section:hover { - background:#c8102e; -} - -.table-responsive { - border: 0; - margin-bottom: 0; -} - -.btn { - border: 0; - - transition: background-color, color; - transition-duration: 0.15s; - - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - - font-family: "Roboto Slab"; -} - -.btn, .btn-lg, .btn-group-lg>.btn { - border-radius:0; -} - -.btn-primary { - background-color:#c63b52; - color:#FFF; - border:0; -} - -.btn-primary:hover, -.btn-primary.focus, .btn-primary:focus, -.btn-primary.active.focus, .btn-primary.active:focus, .btn-primary.active:hover, -.btn-primary:active.focus, .btn-primary:active:focus, .btn-primary:active:hover, -.nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover { - outline: 0; - background-color:#bf0f2c; - background-color:#c8102e; - color:#FFF; -} - -.btn-primary[disabled]:hover, -.btn-primary[disabled]:focus { - background-color: #000; - color: #666; -} - -.nav-pills>li>a { - border-radius:0; -} - -.nav-pills>li>a:focus, .nav-pills>li>a:hover { - outline: 0; - background-color:rgba(200,16,46,1); - color:#FFF; -} - -.header-row { - background-color:rgba(200,16,46,1); - color:#FFF; -} - -.page-header { - border:0; - padding:0; - margin:15px 20px; - font-weight:bold; +.header h1 { + padding: 0; + margin: 0; + font-weight: bold; } .nopadding { padding: 0 !important; } -.col-content-left, .col-content-right { - padding:0; -} - - -@media (min-width: 768px) { - .col-content-left { - position: sticky; - top:50px; - margin-bottom: 15px; - } -} - -.content-left-top { - background:#fff; - padding:15px; -} - -@media (min-width: 1200px) { - .content-left-top { - padding: 30px; - } -} - -.content-left .btn-lg { - font-size: 16px; -} - -.btn-actions { - margin: 0 -15px; -} - -.btn-actions .btn { - color: inherit; -} - -.btn-actions .btn:not([disabled]):hover, .btn-actions .btn:not([disabled]):focus { - color: #c8102e; -} - -.content-left-top.frozen-account { +.frozen-account { background:#5072e0; color:#fff; } -.content-left .block { - padding-top:15px; + +.main .table a:not(.btn) { + color: inherit; } -.content-left .block .line { - font-size:16px; - line-height:30px; +.main .table a:not(.btn):focus , +.main .table a:not(.btn):hover { + color: #C81022; } -.content-left .line.line-big { - font-family:"Roboto Slab"; - font-size:60px; - font-weight:bold; - text-align:center; - overflow:hidden; -} - -.content-left .line.line-bigsub { - font-size:25px; - font-weight:bold; - text-align:center; -} - -.content-left .line.balance { - font-size:45px; - text-align:center; -} - -@media (min-width: 1200px) { - .content-left .line.line-big { - margin-top: -15px; - } -} - -@media (min-width: 768px) { - .content-right { - margin: 15px; - } -} - -.content-right-block { - margin-top: 15px; - position:relative; -} - -.content-right-block > *:not(.buttons-title) { - background: #fff; -} - -.content-right-block > h2 { - background: transparent !important; -} - -.content-right-block .buttons-title { - position:absolute; - top:8px; - right:20px; -} - -.content-right-block > div.row { - margin:0; -} - -.content-right-block h2 { - margin:20px 20px 15px; - padding-bottom:5px; - border-bottom:3px solid #c8102e; - font-size:40px; -} - -.content-right-block h3 { - border-bottom: 1px solid #c8102e; - margin: 0px 15px 15px; - padding: 20px 20px 10px; - font-size:25px; -} - -.content-right-block a:not(.btn) { - color:#000; -} - -.content-right-block a:not(.btn):focus , -.content-right-block a:not(.btn):hover { - color:#C81022; -} /* * Pages tableaux seuls */ -.content-center > *:not(.content-right-block) { - background: #fff; -} - -@media (min-width: 992px) { - .content-center { - margin: 15px 0; - } - - .column-row { - margin-top: 15px; - margin-bottom: 15px; - } -} - -.content-center tbody tr:not(.section) td { - padding:0px 5px; -} .table .form-control { padding: 1px 12px ; @@ -313,6 +71,10 @@ textarea { background: #f5f5f5; } +.table-condensed-input tbody tr:not(.section) td { + padding:0px 5px; +} + .table-condensed input.form-control { margin: 0 !important; border-top: 0; @@ -320,19 +82,34 @@ textarea { border-radius: 0; } -.content-center .auth-form { - margin:15px; +.auth-form { + padding: 15px 0; + background: #d86c7e; + color: white; +} + +.auth-form.form-horizontal { + padding: 0; + margin: 0; +} + +.auth-form .form-group { + margin-bottom: 0; +} + +.auth-form input { + box-shadow: none !important; + background: transparent; + color: white; + border: 0 !important; + border-radius: 0; + border-bottom: 1px solid white !important; } /* * Pages formulaires seuls */ -.content-form { - background-color: #fff; - padding: 15px; -} - .account_create #id_trigramme { display:block; width:200px; @@ -395,40 +172,48 @@ textarea { padding:5px 20px; } -/* - * Messages +/* Account autocomplete window */ + +#account_results ul { + list-style-type:none; + background:rgba(255,255,255,0.9); + padding:0; +} + +#account_results li { + display:block; + padding:5px 20px; + height:100%; + width:100%; +} + +#account_results .hilight { + background:rgba(200,16,46,0.9); + color:#fff; + text-decoration:none; +} + +/** + * Stats (graphs) */ -.messages .alert { - padding:10px 15px; - margin:0; - border:0; - border-radius:0; +.stat-nav { + margin-bottom: 10px; + font-family: Roboto; } -.messages .alert .close { - top:0; - right:0; +.stat-nav li { + float: left; } -.messages .alert-info { - color:inherit; - background-color:#ccc; +.stat-nav a { + opacity: 0.6; + font-family: Roboto; } -.messages .alert-error { - color: white; - background-color: #c63b52; -} - -.messages .alert-success { - color: white; - background: #3d9947; -} - -.messages a { - font-weight: bold; - text-decoration: none; +.stat-nav a:hover, +.stat-nav a.focus, .stat-nav a:focus { + opacity: 1; } /* @@ -488,57 +273,10 @@ thead .tooltip { height: 100px; } -/* - * Responsive Columns - */ - -.unbreakable { - display:inline-block; - width: 100%; -} - -.column-xs-1, .column-sm-1, .column-md-1, .column-lg-1, -.column-xs-2, .column-sm-2, .column-md-2, .column-lg-2, -.column-xs-3, .column-sm-3, .column-md-3, .column-lg-3, -.column-xs-4, .column-sm-4, .column-md-4, .column-lg-4, -.column-xs-5, .column-sm-5, .column-md-5, .column-lg-5 { - column-count: 1; - column-gap: 0; -} - -.column-xs-1 { column-count: 1; } -.column-xs-2 { column-count: 2; } -.column-xs-3 { column-count: 3; } -.column-xs-4 { column-count: 4; } -.column-xs-5 { column-count: 5; } - -@media (min-width: 768px) { - .column-sm-1 { column-count: 1; } - .column-sm-2 { column-count: 2; } - .column-sm-3 { column-count: 3; } - .column-sm-4 { column-count: 4; } - .column-sm-5 { column-count: 5; } -} - -@media (min-width: 992px) { - .column-md-1 { column-count: 1; } - .column-md-2 { column-count: 2; } - .column-md-3 { column-count: 3; } - .column-md-4 { column-count: 4; } - .column-md-5 { column-count: 5; } -} - -@media (min-width: 1200px) { - .column-lg-1 { column-count: 1; } - .column-lg-2 { column-count: 2; } - .column-lg-3 { column-count: 3; } - .column-lg-4 { column-count: 4; } - .column-lg-5 { column-count: 5; } -} /* Inventaires */ -#inventoryform input[type=number] { +.table-condensed-input input[type=number] { text-align: center; } @@ -557,18 +295,6 @@ thead .tooltip { margin: 0 auto; } -/* Multiple select customizations */ - -.ms-choice { - height: 34px !important; - line-height: 34px !important; - border: 1px solid #ccc !important; - box-shadow: inset 0 1px 1px rgba(0,0,0,.075) !important; -} - -.ms-choice > div { - top: 4px !important; -} /* Checkbox select multiple */ diff --git a/kfet/static/kfet/css/libs/columns.css b/kfet/static/kfet/css/libs/columns.css new file mode 100644 index 00000000..34591061 --- /dev/null +++ b/kfet/static/kfet/css/libs/columns.css @@ -0,0 +1,43 @@ +.unbreakable { + display:inline-block; + width: 100%; +} + +.column-xs-1, .column-sm-1, .column-md-1, .column-lg-1, +.column-xs-2, .column-sm-2, .column-md-2, .column-lg-2, +.column-xs-3, .column-sm-3, .column-md-3, .column-lg-3, +.column-xs-4, .column-sm-4, .column-md-4, .column-lg-4, +.column-xs-5, .column-sm-5, .column-md-5, .column-lg-5 { + column-count: 1; +} + +.column-xs-1 { column-count: 1; } +.column-xs-2 { column-count: 2; } +.column-xs-3 { column-count: 3; } +.column-xs-4 { column-count: 4; } +.column-xs-5 { column-count: 5; } + +@media (min-width: 768px) { + .column-sm-1 { column-count: 1; } + .column-sm-2 { column-count: 2; } + .column-sm-3 { column-count: 3; } + .column-sm-4 { column-count: 4; } + .column-sm-5 { column-count: 5; } +} + +@media (min-width: 992px) { + .column-md-1 { column-count: 1; } + .column-md-2 { column-count: 2; } + .column-md-3 { column-count: 3; } + .column-md-4 { column-count: 4; } + .column-md-5 { column-count: 5; } +} + +@media (min-width: 1200px) { + .column-lg-1 { column-count: 1; } + .column-lg-2 { column-count: 2; } + .column-lg-3 { column-count: 3; } + .column-lg-4 { column-count: 4; } + .column-lg-5 { column-count: 5; } +} + diff --git a/kfet/static/kfet/css/jconfirm-kfet.css b/kfet/static/kfet/css/libs/jconfirm-kfet.css similarity index 81% rename from kfet/static/kfet/css/jconfirm-kfet.css rename to kfet/static/kfet/css/libs/jconfirm-kfet.css index 1e05a816..d2803434 100644 --- a/kfet/static/kfet/css/jconfirm-kfet.css +++ b/kfet/static/kfet/css/libs/jconfirm-kfet.css @@ -49,7 +49,7 @@ } .jconfirm .jconfirm-box .buttons button { - width:40px; + min-width:40px; height:100%; margin:0; margin:0 !important; @@ -85,24 +85,3 @@ padding-right: 50px; padding-left: 50px; } - -/* Account autocomplete window */ - -#account_results ul { - list-style-type:none; - background:rgba(255,255,255,0.9); - padding:0; -} - -#account_results li { - display:block; - padding:5px 20px; - height:100%; - width:100%; -} - -#account_results .hilight { - background:rgba(200,16,46,0.9); - color:#fff; - text-decoration:none; -} diff --git a/kfet/static/kfet/css/libs/multiple-select-kfet.css b/kfet/static/kfet/css/libs/multiple-select-kfet.css new file mode 100644 index 00000000..145968d3 --- /dev/null +++ b/kfet/static/kfet/css/libs/multiple-select-kfet.css @@ -0,0 +1,14 @@ +/** + * Multiple Select plugin customizations + */ + +.ms-choice { + height: 34px !important; + line-height: 34px !important; + border: 1px solid #ccc !important; + box-shadow: inset 0 1px 1px rgba(0,0,0,.075) !important; +} + +.ms-choice > div { + top: 4px !important; +} diff --git a/kfet/static/kfet/js/kfet.js b/kfet/static/kfet/js/kfet.js index 72ae675a..c977d534 100644 --- a/kfet/static/kfet/js/kfet.js +++ b/kfet/static/kfet/js/kfet.js @@ -30,7 +30,7 @@ class KfetWebsocket { constructor(data) { $.extend(this, this.constructor.defaults, data); } - + get url() { var websocket_protocol = window.location.protocol == 'https:' ? 'wss' : 'ws'; var location_host = window.location.host; @@ -184,3 +184,13 @@ function requestAuth(data, callback, focus_next = null) { }); } + + +/** + * Setup jquery-confirm + */ + +jconfirm.defaults = { + confirmButton: '', + cancelButton: '' +}; diff --git a/kfet/static/kfet/js/statistic.js b/kfet/static/kfet/js/statistic.js index d185b604..9baa08c4 100644 --- a/kfet/static/kfet/js/statistic.js +++ b/kfet/static/kfet/js/statistic.js @@ -7,7 +7,7 @@ var self = this; var element = $(target); - var content = $("
"); + var content = $("
"); var buttons; function dictToArray (dict, start) { @@ -153,9 +153,8 @@ // initialize the interface function initialize (data) { // creates the bar with the buttons - buttons = $("
", - {class: "btn-group btn-group-justified", - role: "group", + buttons = $("
Date
@@ -68,6 +66,6 @@
-
+ {% endblock %} diff --git a/kfet/templates/kfet/account_create.html b/kfet/templates/kfet/account_create.html index b9e050b4..59fc1d56 100644 --- a/kfet/templates/kfet/account_create.html +++ b/kfet/templates/kfet/account_create.html @@ -1,4 +1,4 @@ -{% extends "kfet/base_col_1.html" %} +{% extends "kfet/base_form.html" %} {% load staticfiles %} {% block title %}Nouveau compte{% endblock %} @@ -8,9 +8,7 @@ {% endblock %} -{% block main-class %}content-form{% endblock %} - -{% block main-content %} +{% block main %}
-

Les mots contenant des caractères non alphanumériques seront ignorés

@@ -62,7 +59,6 @@ // et de ladisponibilité du trigramme choisi $('#id_trigramme').on('input', function() { var trigramme = $('#id_trigramme').val().toUpperCase(); - var container = '#trigramme_valid'; var pattern = /^[^a-z]{3}$/; if (!(trigramme.match(pattern))) { diff --git a/kfet/templates/kfet/account_create_special.html b/kfet/templates/kfet/account_create_special.html index e7a14f87..ecd6ac22 100644 --- a/kfet/templates/kfet/account_create_special.html +++ b/kfet/templates/kfet/account_create_special.html @@ -10,7 +10,7 @@ {% block main-class %}content-form{% endblock %} -{% block main-content %} +{% block main %} {% csrf_token %} diff --git a/kfet/templates/kfet/account_group.html b/kfet/templates/kfet/account_group.html index e7243258..6663bc0e 100644 --- a/kfet/templates/kfet/account_group.html +++ b/kfet/templates/kfet/account_group.html @@ -3,53 +3,59 @@ {% block title %}Groupes de comptes{% endblock %} {% block header-title %}Groupes de comptes{% endblock %} -{% block fixed-content %} +{% block fixed %} -
- Créer un groupe + {% endblock %} -{% block main-content %} +{% block main %} {% for group in groups %} -
-
- - - +
+
+ {{ group.name }} +
-

{{ group.name }}

-
-
-

Permissions

+
+

Comptes

+
+ +
+

Permissions

+
{% regroup group.permissions.all by content_type as grouped_perms %}
    {% for perms_group in grouped_perms %} -
  • {{ perms_group.grouper|title }} -
      - {% for perm in perms_group.list %} -
    • {{ perm.name }}
    • - {% endfor %} +
    • + {{ perms_group.grouper|title }} +
        + {% for perm in perms_group.list %} +
      • {{ perm.name }}
      • + {% endfor %}
      - {% endfor %} -
    -
-
-

Comptes

-
-
+
{% endfor %} {% endblock %} diff --git a/kfet/templates/kfet/account_group_form.html b/kfet/templates/kfet/account_group_form.html index 45c3ac5b..90e3aa36 100644 --- a/kfet/templates/kfet/account_group_form.html +++ b/kfet/templates/kfet/account_group_form.html @@ -1,4 +1,4 @@ -{% extends 'kfet/base_col_1.html' %} +{% extends 'kfet/base_form.html' %} {% load staticfiles %} {% load widget_tweaks %} @@ -10,9 +10,7 @@ {% block title %}Permissions - Édition{% endblock %} {% block header-title %}Modification des permissions{% endblock %} -{% block main-class %}content-form{% endblock %} - -{% block main-content %} +{% block main %} {% csrf_token %} @@ -23,8 +21,12 @@ K-Fêt {{ form.name|add_class:"form-control" }}
- {% if form.name.errors %}{{ form.name.errors }}{% endif %} - {% if form.name.help_text %}{{ form.name.help_text }}{% endif %} + {% if form.name.errors %} + {{ form.name.errors }} + {% endif %} + {% if form.name.help_text %} + {{ form.name.help_text }} + {% endif %}
{% include "kfet/form_field_snippet.html" with field=form.permissions %} diff --git a/kfet/templates/kfet/account_negative.html b/kfet/templates/kfet/account_negative.html index 741ad9dd..066cb832 100644 --- a/kfet/templates/kfet/account_negative.html +++ b/kfet/templates/kfet/account_negative.html @@ -1,72 +1,76 @@ {% extends "kfet/base_col_2.html" %} {% block title %}Comptes - Négatifs{% endblock %} -{% block header-title %}Comptes en négatifs{% endblock %} +{% block header-title %}Comptes en négatif{% endblock %} -{% block fixed-content %} +{% block fixed %} -
-
{{ negatives|length }}
-
compte{{ negatives|length|pluralize }} en négatif
-
-
Total: {{ negatives_sum|floatformat:2 }}€
+ + {% if perms.kfet.change_settings %} -
- Modifier les valeurs par défaut +
+
+
{% endif %} {% endblock %} -{% block main-content %} +{% block main %} -
-

Liste des comptes en négatifs

-
- - - - - - - - - - - - - - - {% for neg in negatives %} - - - - - - - - - - - {% endfor %} - -
Tri.NomBalanceRéelleDébutDécouvert autoriséJusqu'auBalance offset
- - {{ neg.account.trigramme }} - - {{ neg.account.name }}{{ neg.account.balance|floatformat:2 }}€ - {% if neg.balance_offset %} - {{ neg.account.real_balance|floatformat:2 }}€ - {% endif %} - {{ neg.start|date:'d/m/Y H:i:s'}}{{ neg.authz_overdraft_amount|default_if_none:'' }}{{ neg.authz_overdrafy_until|default_if_none:'' }}{{ neg.balance_offset|default_if_none:'' }}
-
+
+ + + + + + + + + + + + + + + {% for neg in negatives %} + + + + + + + + + + + {% endfor %} + +
Tri.NomBalanceRéelleDébutDécouvert autoriséJusqu'auBalance offset
+ + {{ neg.account.trigramme }} + + {{ neg.account.name }}{{ neg.account.balance|floatformat:2 }}€ + {% if neg.balance_offset %} + {{ neg.account.real_balance|floatformat:2 }}€ + {% endif %} + {{ neg.start|date:'d/m/Y H:i:s'}}{{ neg.authz_overdraft_amount|default_if_none:'' }}{{ neg.authz_overdrafy_until|default_if_none:'' }}{{ neg.balance_offset|default_if_none:'' }}
{% endblock %} diff --git a/kfet/templates/kfet/account_read.html b/kfet/templates/kfet/account_read.html index fc8babc5..15238b64 100644 --- a/kfet/templates/kfet/account_read.html +++ b/kfet/templates/kfet/account_read.html @@ -48,38 +48,43 @@ $(document).ready(function() { {% include "kfet/base_footer.html" %} {% endblock %} -{% block fixed-content %} +{% block fixed %} {% include "kfet/left_account.html" %} {% endblock %} -{% block main-content %} +{% block main %}
+ {% if account.user == request.user %} -
-

Statistiques

-
-

Ma balance

-
-

Ma consommation

-
-
-
+
+
+
+

Ma balance

+
+

Ma consommation

+
+
+
+
{% endif %} -
- {% if addcosts %} -

Gagné des majorations

-
-
    - {% for addcost in addcosts %} -
  • {{ addcost.date|date:'l j F' }}: +{{ addcost.sum_addcosts }}€
  • - {% endfor %} -
-
- {% endif %} -

Historique

-
-
+ +
+
+ {% if addcosts %} +

Gagné des majorations

+
+
    + {% for addcost in addcosts %} +
  • {{ addcost.date|date:'l j F' }}: +{{ addcost.sum_addcosts }}€
  • + {% endfor %} +
+
+ {% endif %} +
+
+
+
@@ -9,96 +9,104 @@ {% block title %}Article - {{ article.name }}{% endblock %} {% block header-title %}Informations sur l'article {{ article.name }}{% endblock %} -{% block fixed-content %} +{% block fixed %} -
-
{{ article.name }}
-
{{ article.category }}
-
- + + + {% endblock %} -{% block main-content %} +{% block main %} -
-

Historique

-
-
-

Inventaires

-
- - - - - - - - - - {% for inventoryart in inventoryarts %} - - - - - - {% endfor %} - -
DateStockErreur
- - {{ inventoryart.inventory.at }} - - {{ inventoryart.stock_new }}{{ inventoryart.stock_error }}
-
-
-
-

Prix fournisseurs

-
- - - - - - - - - - - - {% for supplierart in supplierarts %} - - - - - - - - {% endfor %} - -
DateFournisseurHTTVADroits
{{ supplierart.at }}{{ supplierart.supplier.name }}{{ supplierart.price_HT }}{{ supplierart.TVA }}{{ supplierart.rights }}
-
-
-
-
-
-

Statistiques

+
+ +
+ +
+
+
+
+ +

Inventaires récents

+
+ {% include "kfet/article_inventories_snippet.html" with inventoryarts=inventoryarts|slice:5 %} +
+ +
+
+ +

Derniers prix fournisseurs

+
+ {% include "kfet/article_suppliers_snippet.html" with supplierarts=supplierarts|slice:5 %} +
+ +
+
+
+
+ +

Ventes

+
+ +
+ +
+
+ {% include "kfet/article_inventories_snippet.html" %} +
+
+ +
+
+ {% include "kfet/article_suppliers_snippet.html" %} +
+
+
diff --git a/kfet/templates/kfet/article_suppliers_snippet.html b/kfet/templates/kfet/article_suppliers_snippet.html new file mode 100644 index 00000000..bd5970fd --- /dev/null +++ b/kfet/templates/kfet/article_suppliers_snippet.html @@ -0,0 +1,22 @@ + + + + + + + + + + + + {% for supplierart in supplierarts %} + + + + + + + + {% endfor %} + +
DateFournisseurHTTVADroits
{{ supplierart.at }}{{ supplierart.supplier.name }}{{ supplierart.price_HT|default_if_none:"" }}{{ supplierart.TVA|default_if_none:"" }}{{ supplierart.rights|default_if_none:"" }}
diff --git a/kfet/templates/kfet/article_update.html b/kfet/templates/kfet/article_update.html index d451df94..3f09e48e 100644 --- a/kfet/templates/kfet/article_update.html +++ b/kfet/templates/kfet/article_update.html @@ -1,12 +1,10 @@ -{% extends "kfet/base_col_1.html" %} +{% extends "kfet/base_form.html" %} {% block title %}{{ article.name }} - Édition{% endblock %} {% block header-title %}Édition de l'article {{ article.name }}{% endblock %} -{% block main-class %}content-form{% endblock %} +{% block main %} -{% block main-content %} - -{% include "kfet/base_form.html" with authz=perms.kfet.change_article submit_text="Mettre à jour"%} +{% include "kfet/form_full_snippet.html" with authz=perms.kfet.change_article submit_text="Mettre à jour"%} {% endblock %} diff --git a/kfet/templates/kfet/base.html b/kfet/templates/kfet/base.html index b18ee719..ecd69c3d 100644 --- a/kfet/templates/kfet/base.html +++ b/kfet/templates/kfet/base.html @@ -1,5 +1,4 @@ -{% load staticfiles %} -{% load menu_tags %} +{% load static menu_tags %} @@ -33,17 +32,17 @@ - {% main_menu template="kfet/base_nav.html" %} + {% flat_menu "kfet-nav" template="kfet/base_nav.html" apply_active_classes=True %}
{% block header %} {% if not page or not page.no_header %} -
-
-

+
+
+

{% block header-title %}{% endblock %}

-

+ {% endif %} {% endblock %} diff --git a/kfet/templates/kfet/base_col_1.html b/kfet/templates/kfet/base_col_1.html index 6bd6dd5c..03fea5e7 100644 --- a/kfet/templates/kfet/base_col_1.html +++ b/kfet/templates/kfet/base_col_1.html @@ -4,11 +4,11 @@ {% block content %} -
-
+
+
{% include "kfet/base_messages.html" %} -
- {% block main-content %}{% endblock %} +
+ {% block main %}{% endblock %}
diff --git a/kfet/templates/kfet/base_col_2.html b/kfet/templates/kfet/base_col_2.html index 2a1f8cd4..d0ac45b7 100644 --- a/kfet/templates/kfet/base_col_2.html +++ b/kfet/templates/kfet/base_col_2.html @@ -2,16 +2,16 @@ {% block content %} -
-
-
- {% block fixed-content %}{% endblock %} +
+
+
+ {% block fixed %}{% endblock %}
-
+
{% include "kfet/base_messages.html" %} -
- {% block main-content %}{% endblock %} +
+ {% block main %}{% endblock %}
diff --git a/kfet/templates/kfet/base_col_mult.html b/kfet/templates/kfet/base_col_mult.html new file mode 100644 index 00000000..e5bafc19 --- /dev/null +++ b/kfet/templates/kfet/base_col_mult.html @@ -0,0 +1,18 @@ +{% extends "kfet/base.html" %} + +{% block header-class %}text-center{% endblock %} + +{% block content %} + +
+
+ {% include "kfet/base_messages.html" %} +
+
+ {% block main %}{% endblock %} +
+
+
+
+ +{% endblock %} diff --git a/kfet/templates/kfet/base_footer.html b/kfet/templates/kfet/base_footer.html index be524139..c5333476 100644 --- a/kfet/templates/kfet/base_footer.html +++ b/kfet/templates/kfet/base_footer.html @@ -2,7 +2,7 @@ {% with "k-fet@ens.fr" as kfet_mail %} -