diff --git a/gestioncof/cms/migrations/0003_auto_20180128_2215.py b/gestioncof/cms/migrations/0003_auto_20180128_2215.py new file mode 100644 index 00000000..89b59957 --- /dev/null +++ b/gestioncof/cms/migrations/0003_auto_20180128_2215.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.9 on 2018-01-28 21:15 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.contrib.wagtailroutablepage.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0039_collectionviewrestriction'), + ('cofcms', '0002_auto_20180128_1717'), + ] + + operations = [ + migrations.CreateModel( + name='COFUtilPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), + ], + options={ + 'verbose_name_plural': 'Pages utilitaires', + 'verbose_name': 'Page utilitaire', + }, + bases=(wagtail.contrib.wagtailroutablepage.models.RoutablePageMixin, 'wagtailcore.page'), + ), + migrations.AlterModelOptions( + name='cofdirectoryentrypage', + options={'verbose_name': "Entrée d'annuaire", 'verbose_name_plural': "Entrées d'annuaire"}, + ), + ] diff --git a/gestioncof/cms/models.py b/gestioncof/cms/models.py index da6f6a8b..eeb6a025 100644 --- a/gestioncof/cms/models.py +++ b/gestioncof/cms/models.py @@ -1,15 +1,16 @@ from django.db import models -from wagtail.wagtailcore.models import Page, Orderable from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger -from wagtail.wagtailcore.fields import RichTextField, StreamField -from wagtail.wagtailcore import blocks -from wagtail.wagtailimages.edit_handlers import ImageChooserPanel -from wagtail.wagtailimages.blocks import ImageChooserBlock from django.utils.translation import ugettext as _ +from wagtail.contrib.wagtailroutablepage.models import RoutablePageMixin, route from wagtail.wagtailadmin.edit_handlers import FieldPanel, StreamFieldPanel +from wagtail.wagtailcore import blocks +from wagtail.wagtailcore.fields import RichTextField, StreamField +from wagtail.wagtailcore.models import Page, Orderable +from wagtail.wagtailimages.edit_handlers import ImageChooserPanel +from wagtail.wagtailimages.blocks import ImageChooserBlock from wagtail.wagtailsnippets.models import register_snippet # Page pouvant afficher des actualités @@ -18,7 +19,7 @@ class COFActuIndexMixin(): def actus(self): actus = COFActuPage.objects.live().order_by('-date_start').descendant_of(self) return actus - + # Racine du site du COF class COFRootPage(Page, COFActuIndexMixin): introduction = RichTextField("Introduction") @@ -27,11 +28,12 @@ class COFRootPage(Page, COFActuIndexMixin): FieldPanel('introduction', classname="full"), ] - subpage_types = ['COFActuIndexPage', 'COFPage', 'COFDirectoryPage'] - + subpage_types = ['COFActuIndexPage', 'COFPage', 'COFDirectoryPage', 'COFUtilPage'] + class Meta: verbose_name = "Racine site du COF" verbose_name_plural = "Racines site du COF" + # Page lambda du site class COFPage(Page): @@ -77,7 +79,7 @@ class COFActuIndexPage(Page, COFActuIndexMixin): context['actus'] = actus return context -class COFActuPage(Page): +class COFActuPage(RoutablePageMixin, Page): chapo = models.TextField("Description rapide", blank=True) body = RichTextField("Contenu") image = models.ForeignKey( @@ -104,49 +106,6 @@ class COFActuPage(Page): subpage_types = [] parent_page_types = ['COFActuIndexPage'] - class Meta: - verbose_name = "Actualité simple" - verbose_name_plural = "Actualités simples" - - @property - def dates(self): - if self.date_end: - if self.date_end.date() == self.date_start.date(): - if self.all_day: - return self.date_start.strftime(_("le %A %d %B %Y")) - else: - return _("le %s de %s à %s") % \ - (self.date_start.strftime("%A %d %B %Y"), - self.date_start.strftime(_("%Hh%M")), - self.date_end.strftime(_("%Hh%M"))) - else: - tmpl = "%A %d %B %Y" - diff_i = len(tmpl) - if self.date_end.year != self.date_start.year: - diff_i = len(tmpl) - elif self.date_end.month != self.date_start.month: - diff_i = len(tmpl) - 3 - elif self.date_end.day != self.date_start.day: - diff_i = len(tmpl) - 6 - common = tmpl[diff_i:] - diff = tmpl[:diff_i] - if self.all_day: - return _("du %s au %s %s") % \ - (self.date_start.strftime(diff), - self.date_end.strftime(diff), - self.date_end.strftime(common)) - else: - return _("du %s %s à %s au %s à %s") % \ - (self.date_start.strftime(diff), - self.date_start.strftime(common), - self.date_start.strftime("%Hh%M"), - self.date_end.strftime(diff), - self.date_end.strftime("%Hh%M")) - else: - if self.all_day: - return self.date_start.strftime(_("le %A %d %B %Y")) - else: - return self.date_start.strftime(_("le %A %d %B %Y à %Hh%M")) class Meta: verbose_name = "Actualité" verbose_name_plural = "Actualités" @@ -207,5 +166,28 @@ class COFDirectoryEntryPage(Page, Orderable): parent_page_types = ['COFDirectoryPage'] class Meta: - verbose_name = "Éntrée d'annuaire" - verbose_name_plural = "Éntrées d'annuaire" + verbose_name = "Entrée d'annuaire" + verbose_name_plural = "Entrées d'annuaire" + +# Pour le calendrier et le sympa, ne doit pas être pris par ModelTranslation +class COFUtilPage(RoutablePageMixin, Page): + # Protection pour le serveur des mailing listes + @route(r'^sympa/$') + def sympa(self, request): + from .views import sympa_view + return sympa_view(request) + + # Mini calendrier + @route(r'^calendar/(\d+)/(\d+)/$') + def calendar(self, request, year, month): + from .views import raw_calendar_view + return raw_calendar_view(request, int(year), int(month)) + + def debugged_get_url(self, request): + parent = COFRootPage.objects.parent_of(self).live().first() + burl = parent.relative_url(request.site) + return burl + self.slug + + class Meta: + verbose_name = "Page utilitaire" + verbose_name_plural = "Pages utilitaires" diff --git a/gestioncof/cms/static/cofcms/css/screen.css b/gestioncof/cms/static/cofcms/css/screen.css index 0f82ce97..617a6162 100644 --- a/gestioncof/cms/static/cofcms/css/screen.css +++ b/gestioncof/cms/static/cofcms/css/screen.css @@ -402,45 +402,107 @@ article:last-child { max-width: 70%; } -/* line 335, ../sass/screen.scss */ +/* line 334, ../sass/screen.scss */ +.calendar { + color: rgba(0, 0, 0, 0.8); +} +/* line 337, ../sass/screen.scss */ .calendar td, .calendar th { text-align: center; - vertical-align: center; + vertical-align: middle; border: 2px solid transparent; padding: 1px; } -/* line 342, ../sass/screen.scss */ +/* line 344, ../sass/screen.scss */ .calendar th { font-weight: bold; } -/* line 346, ../sass/screen.scss */ +/* line 348, ../sass/screen.scss */ .calendar td { font-size: 0.8em; - width: 25px; - height: 30px; + width: 28px; + height: 28px; } -/* line 351, ../sass/screen.scss */ +/* line 353, ../sass/screen.scss */ .calendar td.out { opacity: 0.3; } -/* line 354, ../sass/screen.scss */ +/* line 356, ../sass/screen.scss */ .calendar td.today { border-bottom-color: #000; } -/* line 357, ../sass/screen.scss */ -.calendar td:nth-child(7) { - background: rgba(0, 0, 0, 0.3); -} -/* line 360, ../sass/screen.scss */ -.calendar td:nth-child(6) { +/* line 359, ../sass/screen.scss */ +.calendar td:nth-child(7), .calendar td:nth-child(6) { background: rgba(0, 0, 0, 0.2); } -/* line 363, ../sass/screen.scss */ +/* line 362, ../sass/screen.scss */ .calendar td.hasevent { + position: relative; font-weight: bold; - color: #997000; + color: #90001C; font-size: 1em; } +/* line 368, ../sass/screen.scss */ +.calendar td.hasevent > a { + padding: 3px; + color: #90001C !important; +} +/* line 373, ../sass/screen.scss */ +.calendar td.hasevent ul.cal-events { + text-align: left; + display: none; + position: absolute; + z-index: 2; + background: #fff; + width: 150px; + left: -30px; + margin-top: 10px; + padding: 5px; + background-color: #90001C; +} +/* line 386, ../sass/screen.scss */ +.calendar td.hasevent ul.cal-events .datename { + display: none; +} +/* line 389, ../sass/screen.scss */ +.calendar td.hasevent ul.cal-events:before { + top: -12px; + left: 38px; + content: ""; + position: absolute; + border: 6px solid transparent; + border-bottom-color: #90001C; +} +/* line 397, ../sass/screen.scss */ +.calendar td.hasevent ul.cal-events a { + color: #fff; +} +/* line 402, ../sass/screen.scss */ +.calendar td.hasevent > a:hover { + background-color: #90001C; + color: #fff !important; +} +/* line 406, ../sass/screen.scss */ +.calendar td.hasevent > a:hover + ul.cal-events { + display: block; +} + +/* line 414, ../sass/screen.scss */ +#calendar-wrap .details { + border-top: 1px solid #90001C; + margin-top: 15px; + padding-top: 10px; +} +/* line 419, ../sass/screen.scss */ +#calendar-wrap .details li.datename { + font-weight: bold; + font-size: 1.1em; + margin-bottom: 5px; +} +/* line 420, ../sass/screen.scss */ +#calendar-wrap .details li.datename:after { + content: " :"; +} /* line 1, ../sass/_responsive.scss */ header .minimenu { diff --git a/gestioncof/cms/static/cofcms/js/calendar.js b/gestioncof/cms/static/cofcms/js/calendar.js new file mode 100644 index 00000000..dbc1024d --- /dev/null +++ b/gestioncof/cms/static/cofcms/js/calendar.js @@ -0,0 +1,32 @@ +$(function(){ + var mem = {}; + var ctt = $("#calendar-wrap"); + makeInteractive(); + + function makeInteractive () { + $(".cal-btn").on("click", loadCalendar); + $(".hasevent a").on("click", showEvents); + } + + function loadCalendar () { + var url = $(this).attr("cal-dest"); + if (mem[url] != undefined) { + ctt.html(mem[url]); + makeInteractive(); + return; + } + ctt.innerText = "Chargement..."; + ctt.load(url, function () { + mem[url] = this.innerHTML; + makeInteractive(); + }); + } + + function showEvents() { + ctt.find(".details").remove(); + ctt.append( + $("
", {class:"details"}) + .html(this.nextElementSibling.outerHTML) + ); + } +}); diff --git a/gestioncof/cms/static/cofcms/sass/screen.scss b/gestioncof/cms/static/cofcms/sass/screen.scss index a389822b..9e2379d7 100644 --- a/gestioncof/cms/static/cofcms/sass/screen.scss +++ b/gestioncof/cms/static/cofcms/sass/screen.scss @@ -332,9 +332,11 @@ article { } .calendar { + color: rgba(#000, 0.8); + td, th { text-align: center; - vertical-align: center; + vertical-align: middle; border: 2px solid transparent; padding: 1px; } @@ -345,8 +347,8 @@ article { td { font-size: 0.8em; - width: 25px; - height: 30px; + width: 28px; + height: 28px; &.out { opacity: 0.3; @@ -354,18 +356,74 @@ article { &.today { border-bottom-color: #000; } - &:nth-child(7) { - background: rgba(#000, 0.3); - } - &:nth-child(6) { + &:nth-child(7), &:nth-child(6) { background: rgba(#000, 0.2); } &.hasevent { + position: relative; font-weight: bold; - color: darken($lien, 10%); + color: $sousbandeau; font-size: 1em; + + & > a { + padding: 3px; + color: $sousbandeau !important; + } + + ul.cal-events { + + text-align: left; + display: none; + position: absolute; + z-index: 2; + background: #fff; + width: 150px; + left: -30px; + margin-top: 10px; + padding: 5px; + background-color: $sousbandeau; + + .datename { + display: none; + } + &:before { + top: -12px; + left: 38px; + content: ""; + position: absolute; + border: 6px solid transparent; + border-bottom-color: $sousbandeau; + } + a { + color: #fff; + } + } + + & > a:hover { + background-color: $sousbandeau; + color: #fff !important; + + & + ul.cal-events { + display: block; + } + } } } } +#calendar-wrap .details { + border-top: 1px solid $sousbandeau; + margin-top: 15px; + padding-top: 10px; + + li.datename { + &:after { + content: " :"; + } + font-weight: bold; + font-size: 1.1em; + margin-bottom: 5px; + } +} + @import "_responsive"; diff --git a/gestioncof/cms/templates/cofcms/calendar.html b/gestioncof/cms/templates/cofcms/calendar.html index 98eacdab..02568f0d 100644 --- a/gestioncof/cms/templates/cofcms/calendar.html +++ b/gestioncof/cms/templates/cofcms/calendar.html @@ -1,11 +1,25 @@ +{% load wagtailcore_tags wagtailroutablepage_tags static %} + + + + + {% for week in weeks %} {% for day in week %} {% endfor %} diff --git a/gestioncof/cms/templates/cofcms/calendar_raw.html b/gestioncof/cms/templates/cofcms/calendar_raw.html new file mode 100644 index 00000000..9ee1aa79 --- /dev/null +++ b/gestioncof/cms/templates/cofcms/calendar_raw.html @@ -0,0 +1,2 @@ +{% load cofcms_tags %} +{% calendar month year %} diff --git a/gestioncof/cms/templates/cofcms/cof_actu_index_page.html b/gestioncof/cms/templates/cofcms/cof_actu_index_page.html index fc21dec8..1e7878ab 100644 --- a/gestioncof/cms/templates/cofcms/cof_actu_index_page.html +++ b/gestioncof/cms/templates/cofcms/cof_actu_index_page.html @@ -1,12 +1,21 @@ {% extends "cofcms/base_aside.html" %} -{% load wagtailimages_tags cofcms_tags wagtailcore_tags %} +{% load wagtailimages_tags cofcms_tags wagtailcore_tags static i18n %} + +{% block extra_head %} + {{ block.super }} + + +{% endblock %} {% block aside_title %}Calendrier{% endblock %} {% block aside %} - {% calendar %} +
+ {% calendar %} +
{% endblock %} {% block content %} + {% get_current_language as curlang %}

{{ page.title }}

{{ page.introduction|safe }}
@@ -26,7 +35,7 @@

{{ actu.title }}

{% if actu.is_event %} -

{{ actu.dates|capfirst }}
{{ actu.chapo }}

+

{{ actu|dates:curlang|capfirst }}
{{ actu.chapo }}

{% else %} {{ actu.body|safe|truncatewords_html:15 }} {% endif %} diff --git a/gestioncof/cms/templates/cofcms/cof_actu_page.html b/gestioncof/cms/templates/cofcms/cof_actu_page.html index 7774d07a..f4af9166 100644 --- a/gestioncof/cms/templates/cofcms/cof_actu_page.html +++ b/gestioncof/cms/templates/cofcms/cof_actu_page.html @@ -1,10 +1,11 @@ {% extends "cofcms/base.html" %} -{% load wagtailimages_tags cofcms_tags %} +{% load wagtailimages_tags cofcms_tags i18n %} {% block content %} + {% get_current_language as curlang %}

{{ page.title }}

-

A lieu {{ page.dates }}

+

A lieu {{ page|dates:curlang }}

{{ page.chapo }}

diff --git a/gestioncof/cms/templates/cofcms/cof_root_page.html b/gestioncof/cms/templates/cofcms/cof_root_page.html index ec61aa43..3ec030a4 100644 --- a/gestioncof/cms/templates/cofcms/cof_root_page.html +++ b/gestioncof/cms/templates/cofcms/cof_root_page.html @@ -1,12 +1,22 @@ {% extends "cofcms/base_aside.html" %} -{% load static cofcms_tags wagtailimages_tags i18n wagtailcore_tags %} +{% load static cofcms_tags wagtailimages_tags wagtailroutablepage_tags i18n wagtailcore_tags %} + + +{% block extra_head %} + {{ block.super }} + + +{% endblock %} {% block aside_title %}Agenda{% endblock %} {% block aside %} - {% calendar %} +
+ {% calendar %} +
{% endblock %} {% block content %} + {% get_current_language as curlang %}

{{ page.title }}

{{ page.introduction|safe }}
@@ -20,8 +30,7 @@
{% if actu.is_event %} - {% get_current_language as curlang %} - {% mini_calendar actu curlang %}{{ actu.dates }} + {% mini_calendar actu %}{{ actu|dates:curlang }} {% else %} {{ actu.body|safe|truncatewords_html:10 }} {% endif %} diff --git a/gestioncof/cms/templates/cofcms/sympa.html b/gestioncof/cms/templates/cofcms/sympa.html new file mode 100644 index 00000000..119c0614 --- /dev/null +++ b/gestioncof/cms/templates/cofcms/sympa.html @@ -0,0 +1,26 @@ +{% extends "cofcms/base.html" %} +{% load i18n %} + +{% block content %} +
+

{% trans "Listes mail" %}

+
+ +
+
+ {% blocktrans %} + Tous les abonnements aux listes de diffusion de mail à l'ENS se gèrent sur le serveur de mail SYMPA + + Pour y accéder : Merci de répondre à cette question anti-robots. + {% endblocktrans %} +
+
+
+ {% csrf_token %} + {% if erreur %}

{% trans erreur %}

{% endif %} +

{% blocktrans %}Comment s'appellent les poissons du bassin ?{% endblocktrans %}

+ + +
+
+{% endblock %} diff --git a/gestioncof/cms/templatetags/cofcms_tags.py b/gestioncof/cms/templatetags/cofcms_tags.py index e226d33b..45b7950b 100644 --- a/gestioncof/cms/templatetags/cofcms_tags.py +++ b/gestioncof/cms/templatetags/cofcms_tags.py @@ -4,7 +4,9 @@ from django.conf import settings from django.utils import timezone import locale -from ..models import COFActuPage +from django.utils.translation import ugettext as _ + +from ..models import COFActuPage, COFUtilPage import re @@ -15,17 +17,22 @@ def obfuscate_mail(value): val = value.replace('', '-').replace('@', 'arbre').replace('.', 'pont')[1:] return val -@register.inclusion_tag("cofcms/calendar.html") -def calendar(): +@register.inclusion_tag("cofcms/calendar.html", takes_context=True) +def calendar(context, month=None, year=None): now = timezone.now() - month_start = date(now.year, now.month, 1) + if month is None: + month_start = date(now.year, now.month, 1) + else: + month_start = date(year, month, 1) next_month = month_start + timedelta(days=32) next_month = date(next_month.year, next_month.month, 1) + prev_month = month_start - timedelta(days=2) month_prestart = month_start - timedelta(days=month_start.weekday()) month_postend = next_month + timedelta(days=(next_month.weekday()+6)%7) events = COFActuPage.objects.live()\ .filter(date_start__range=[month_prestart, - month_postend])\ + month_postend], + is_event=True)\ .order_by('-date_start') events = list(events) weeks = [] @@ -43,22 +50,39 @@ def calendar(): else: curevents.append(e) day = {'day': curday.day, + 'date': curday, 'class': (('today ' if (curday.day == now.day - and curday.month == now.month) else '') - + ('in ' if curday.month == now.month else 'out') + and curday.month == now.month + and curday.year == now.year) else '') + + ('in ' if (curday.month == month_start.month + and curday.year == month_start.year) + else 'out ') + ('hasevent' if len(curevents) > 0 else '')), 'events': curevents} week.append(day) curday += deltaday weeks.append(week) - return {"events": events, "weeks": weeks} + + + # Calendar next/prev urls + try: + utilpage = COFUtilPage.objects.live()[0] + except COFUtilPage.DoesNotExist: + utilpage = None + request = context['request'] + burl = utilpage.debugged_get_url(request) + "/" + prev_url = burl + utilpage.reverse_subpage("calendar", + args=["%d" % (prev_month.year,), + "%d" % (prev_month.month,)]) + next_url = burl + utilpage.reverse_subpage("calendar", + args=["%d" % (next_month.year,), + "%d" % (next_month.month,)]) + context.push({"events": events, "weeks": weeks, "this_month": month_start, + "prev_month": prev_url, "next_month": next_url}) + return context @register.inclusion_tag("cofcms/mini_calendar.html") -def mini_calendar(event, loc): - try: - locale.setlocale(locale.LC_TIME, loc) - except locale.Error: - pass +def mini_calendar(event): days = [] today = timezone.now().date() date_start = event.date_start.date() @@ -71,3 +95,51 @@ def mini_calendar(event, loc): 'today': curday == today}) curday += timedelta(days=1) return {"days": days} + + +@register.filter() +def dates(event, loc=None): + try: + if loc == "fr": + locale.setlocale(locale.LC_TIME, "fr_FR.UTF-8") + else: + locale.setlocale(locale.LC_TIME, "en_US.UTF-8") + except locale.Error as e: + pass + if event.date_end: + if event.date_end.date() == event.date_start.date(): + if event.all_day: + return event.date_start.strftime(_("le %A %d %B %Y")) + else: + return _("le %s de %s à %s") % \ + (event.date_start.strftime("%A %d %B %Y"), + event.date_start.strftime(_("%Hh%M")), + event.date_end.strftime(_("%Hh%M"))) + else: + tmpl = "%A %d %B %Y" + diff_i = len(tmpl) + if event.date_end.year != event.date_start.year: + diff_i = len(tmpl) + elif event.date_end.month != event.date_start.month: + diff_i = len(tmpl) - 3 + elif event.date_end.day != event.date_start.day: + diff_i = len(tmpl) - 6 + common = tmpl[diff_i:] + diff = tmpl[:diff_i] + if event.all_day: + return _("du %s au %s %s") % \ + (event.date_start.strftime(diff), + event.date_end.strftime(diff), + event.date_end.strftime(common)) + else: + return _("du %s %s à %s au %s à %s") % \ + (event.date_start.strftime(diff), + event.date_start.strftime(common), + event.date_start.strftime("%Hh%M"), + event.date_end.strftime(diff), + event.date_end.strftime("%Hh%M")) + else: + if event.all_day: + return event.date_start.strftime(_("le %A %d %B %Y")) + else: + return event.date_start.strftime(_("le %A %d %B %Y à %Hh%M")) diff --git a/gestioncof/cms/views.py b/gestioncof/cms/views.py index 91ea44a2..af70c6d7 100644 --- a/gestioncof/cms/views.py +++ b/gestioncof/cms/views.py @@ -1,3 +1,15 @@ from django.shortcuts import render +from django.http.response import HttpResponseRedirect +import re -# Create your views here. +def raw_calendar_view(request, year, month): + return render(request, "cofcms/calendar_raw.html", {"month": month, "year": year}) + +def sympa_view(request): + erreur = None + if request.POST and "bassin" in request.POST: + if re.match(r'\s*(les|the)\s*ernests?\s*', request.POST["bassin"], + re.IGNORECASE): + return HttpResponseRedirect("https://lists.ens.fr/wws") + erreur = "Réponse invalide" + return render(request, "cofcms/sympa.html", {"erreur": erreur})
<{{ this_month|date:"F Y" }}>
LMMJVSD
- {% if day.events %}{{ day.day }}{% else %}{{ day.day }}{% endif %} + {% if day.events %} + {{ day.day }} +
    +
  • Le {{ day.date|date:"d F Y" }}
  • + {% for event in day.events %} +
  • {{ event.title }}
  • + {% endfor %} +
+ {% else %}{{ day.day }}{% endif %}