Calendrier dynamique + sympa + jolies dates

This commit is contained in:
Evarin 2018-01-28 23:44:48 +01:00
parent f8952225d6
commit ba87044638
13 changed files with 414 additions and 102 deletions

View file

@ -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"},
),
]

View file

@ -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
@ -27,12 +28,13 @@ 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):
body = StreamField([
@ -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"

View file

@ -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 {

View file

@ -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(
$("<div>", {class:"details"})
.html(this.nextElementSibling.outerHTML)
);
}
});

View file

@ -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";

View file

@ -1,11 +1,25 @@
{% load wagtailcore_tags wagtailroutablepage_tags static %}
<table class="calendar">
<tbody>
<tr>
<th><a href="javascript:void(0);" cal-dest="{{ prev_month }}" class="cal-btn">&lt;</a></th>
<th colspan="5">{{ this_month|date:"F Y" }}</th>
<th><a href="javascript:void(0);" cal-dest="{{ next_month }}" class="cal-btn">&gt;</a></th>
</tr>
<tr><th>L</th><th>M</th><th>M</th><th>J</th><th>V</th><th>S</th><th>D</th></tr>
{% for week in weeks %}
<tr>
{% for day in week %}
<td class="{{ day.class }}">
{% if day.events %}<a href="javascript:void(0)">{{ day.day }}</a>{% else %}{{ day.day }}{% endif %}
{% if day.events %}
<a href="javascript:void(0)">{{ day.day }}</a>
<ul class="cal-events">
<li class="datename">Le {{ day.date|date:"d F Y" }}</li>
{% for event in day.events %}
<li><a href="{% pageurl event %}">{{ event.title }}</a></li>
{% endfor %}
</ul>
{% else %}{{ day.day }}{% endif %}
</td>
{% endfor %}
</tr>

View file

@ -0,0 +1,2 @@
{% load cofcms_tags %}
{% calendar month year %}

View file

@ -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 }}
<script src="{% static "js/jquery.min.js" %}"></script>
<script src="{% static "cofcms/js/calendar.js" %}"></script>
{% endblock %}
{% block aside_title %}Calendrier{% endblock %}
{% block aside %}
{% calendar %}
<div id="calendar-wrap">
{% calendar %}
</div>
{% endblock %}
{% block content %}
{% get_current_language as curlang %}
<section class="intro">
<h1>{{ page.title }}</h1>
<div>{{ page.introduction|safe }}</div>
@ -26,7 +35,7 @@
<div class="actu-infos">
<h2><a href="{% pageurl actu %}">{{ actu.title }}</a></h2>
{% if actu.is_event %}
<p><span class="actu-dates">{{ actu.dates|capfirst }}</span><br />{{ actu.chapo }}</p>
<p><span class="actu-dates">{{ actu|dates:curlang|capfirst }}</span><br />{{ actu.chapo }}</p>
{% else %}
{{ actu.body|safe|truncatewords_html:15 }}
{% endif %}

View file

@ -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 %}
<section class="intro">
<h1>{{ page.title }}</h1>
<p class="date">A lieu {{ page.dates }}</p>
<p class="date">A lieu {{ page|dates:curlang }}</p>
<p>{{ page.chapo }}</p>
</section>

View file

@ -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 }}
<script src="{% static "js/jquery.min.js" %}"></script>
<script src="{% static "cofcms/js/calendar.js" %}"></script>
{% endblock %}
{% block aside_title %}Agenda{% endblock %}
{% block aside %}
{% calendar %}
<div id="calendar-wrap">
{% calendar %}
</div>
{% endblock %}
{% block content %}
{% get_current_language as curlang %}
<section class="intro">
<h1>{{ page.title }}</h1>
<div>{{ page.introduction|safe }}</div>
@ -20,8 +30,7 @@
</div>
<div class="actu-misc">
{% if actu.is_event %}
{% get_current_language as curlang %}
<span class="actu-minical">{% mini_calendar actu curlang %}</span><span class="actu-dates">{{ actu.dates }}</span>
<span class="actu-minical">{% mini_calendar actu %}</span><span class="actu-dates">{{ actu|dates:curlang }}</span>
{% else %}
{{ actu.body|safe|truncatewords_html:10 }}
{% endif %}

View file

@ -0,0 +1,26 @@
{% extends "cofcms/base.html" %}
{% load i18n %}
{% block content %}
<section class="intro">
<h1>{% trans "Listes mail" %}</h1>
</section>
<section class="pagecontent">
<article class="paragraph">
{% 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 %}
</article>
<article class="paragraph">
<form method="POST" action="">
{% csrf_token %}
{% if erreur %}<p class="erreur">{% trans erreur %}</p>{% endif %}
<p>{% blocktrans %}Comment s'appellent les poissons du bassin ?{% endblocktrans %}</p>
<input type="text" name="bassin" />
<input type="submit" />
</article>
</section>
{% endblock %}

View file

@ -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"))

View file

@ -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})