forked from DGNum/gestioCOF
Merge branch 'Kerl/calendar' into 'master'
Ajout d'un calendrier dynamique Ce patch propose aux adhérents du COF de télécharger un calendrier dynamique (`.ics`). Il est configurable : - On peut s'abonner ou non aux événements du COF. - On peut choisir les spectacles auxquels on veut s'abonner. - Une checkbox permet d'ajouter d'un coup les spectacles pour lesquels on a obtenu une place - On peut en ajouter d'autres Pour faire fonctionner ce patch, il faut installer la bibliothèque python `icalendar` : pip install --upgrade -r requirements.txt Fixes #20 Fixes #14 See merge request !63
This commit is contained in:
commit
bbc4b59bfe
|
@ -1,10 +0,0 @@
|
||||||
BEGIN:VCALENDAR
|
|
||||||
VERSION:2.0
|
|
||||||
PRODID:-//GESTIOCOF/bda//EN
|
|
||||||
{% for spectacle in spectacles %}BEGIN:VEVENT
|
|
||||||
DTSTART;TZID=Europe/Paris:{{ spectacle.date|date:'Ymd\\THis' }}
|
|
||||||
DTEND;TZID=Europe/Paris:{{ spectacle.dtend|date:'Ymd\\THis' }}
|
|
||||||
SUMMARY:{{ spectacle.title|safe }}
|
|
||||||
LOCATION:{{ spectacle.location.name|safe }}
|
|
||||||
END:VEVENT
|
|
||||||
{% endfor %}END:VCALENDAR
|
|
|
@ -18,7 +18,9 @@
|
||||||
</table>
|
</table>
|
||||||
<h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4>
|
<h4 class="bda-prix">Total à payer : {{ total|floatformat }}€</h4>
|
||||||
<br/>
|
<br/>
|
||||||
<h4><a href="{% url "bda-places-attribuees-ics" tirage.id %}">Exporter au format calendrier</a> (.ics, compatible avec tous les logiciels d'agenda)</h4>
|
<p>Ne manque pas un spectacle avec le
|
||||||
|
<a href="{% url "gestioncof.views.calendar" %}">calendrier
|
||||||
|
automatique !</a></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h3>Vous n'avez aucune place :(</h3>
|
<h3>Vous n'avez aucune place :(</h3>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
BEGIN:VCALENDAR
|
|
||||||
VERSION:2.0
|
|
||||||
PRODID:-//GESTIOCOF/bda//EN
|
|
||||||
{% for place in places %}BEGIN:VEVENT
|
|
||||||
DTSTART;TZID=Europe/Paris:{{ place.spectacle.date|date:'Ymd\\THis' }}
|
|
||||||
DTEND;TZID=Europe/Paris:{{ place.spectacle.dtend|date:'Ymd\\THis' }}
|
|
||||||
SUMMARY:{{ place.spectacle.title|safe }}{% if place.double %} (deux places){% endif %}
|
|
||||||
LOCATION:{{ place.spectacle.location.name|safe }}
|
|
||||||
END:VEVENT
|
|
||||||
{% endfor %}END:VCALENDAR
|
|
|
@ -48,6 +48,5 @@
|
||||||
<h3> Exports </h3>
|
<h3> Exports </h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url 'bda-unpaid' tirage_id %}">Mailing list impayés</a>
|
<li><a href="{% url 'bda-unpaid' tirage_id %}">Mailing list impayés</a>
|
||||||
<li><a href="{% url 'bda-liste-spectacles-ics' tirage_id %}">Calendrier des spectacles (.ics)</a>
|
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -15,9 +15,6 @@ urlpatterns = patterns(
|
||||||
url(r'^places/(?P<tirage_id>\d+)$',
|
url(r'^places/(?P<tirage_id>\d+)$',
|
||||||
'bda.views.places',
|
'bda.views.places',
|
||||||
name="bda-places-attribuees"),
|
name="bda-places-attribuees"),
|
||||||
url(r'^places/(?P<tirage_id>\d+)/places_bda.ics$',
|
|
||||||
'bda.views.places_ics',
|
|
||||||
name="bda-places-attribuees-ics"),
|
|
||||||
url(r'^revente/(?P<tirage_id>\d+)$',
|
url(r'^revente/(?P<tirage_id>\d+)$',
|
||||||
'bda.views.revente',
|
'bda.views.revente',
|
||||||
name='bda-revente'),
|
name='bda-revente'),
|
||||||
|
@ -31,9 +28,6 @@ urlpatterns = patterns(
|
||||||
url(r'^spectacles/(?P<tirage_id>\d+)/(?P<spectacle_id>\d+)$',
|
url(r'^spectacles/(?P<tirage_id>\d+)/(?P<spectacle_id>\d+)$',
|
||||||
"bda.views.spectacle",
|
"bda.views.spectacle",
|
||||||
name="bda-spectacle"),
|
name="bda-spectacle"),
|
||||||
url(r'^spectacles-ics/(?P<tirage_id>\d+)$',
|
|
||||||
'bda.views.liste_spectacles_ics',
|
|
||||||
name="bda-liste-spectacles-ics"),
|
|
||||||
url(r'^spectacles/unpaid/(?P<tirage_id>\d+)$',
|
url(r'^spectacles/unpaid/(?P<tirage_id>\d+)$',
|
||||||
"bda.views.unpaid",
|
"bda.views.unpaid",
|
||||||
name="bda-unpaid"),
|
name="bda-unpaid"),
|
||||||
|
|
36
bda/views.py
36
bda/views.py
|
@ -106,31 +106,6 @@ def places(request, tirage_id):
|
||||||
"warning": warning})
|
"warning": warning})
|
||||||
|
|
||||||
|
|
||||||
@cof_required
|
|
||||||
def places_ics(request, tirage_id):
|
|
||||||
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
||||||
participant, created = Participant.objects.get_or_create(
|
|
||||||
user=request.user, tirage=tirage)
|
|
||||||
places = participant.attribution_set.order_by(
|
|
||||||
"spectacle__date", "spectacle").all()
|
|
||||||
filtered_places = []
|
|
||||||
places_dict = {}
|
|
||||||
spectacles = []
|
|
||||||
for place in places:
|
|
||||||
if place.spectacle in spectacles:
|
|
||||||
places_dict[place.spectacle].double = True
|
|
||||||
else:
|
|
||||||
place.double = False
|
|
||||||
place.spectacle.dtend = place.spectacle.date \
|
|
||||||
+ timedelta(seconds=7200)
|
|
||||||
places_dict[place.spectacle] = place
|
|
||||||
spectacles.append(place.spectacle)
|
|
||||||
filtered_places.append(place)
|
|
||||||
return render(request, "resume_places.ics",
|
|
||||||
{"participant": participant,
|
|
||||||
"places": filtered_places}, content_type="text/calendar")
|
|
||||||
|
|
||||||
|
|
||||||
@cof_required
|
@cof_required
|
||||||
def inscription(request, tirage_id):
|
def inscription(request, tirage_id):
|
||||||
tirage = get_object_or_404(Tirage, id=tirage_id)
|
tirage = get_object_or_404(Tirage, id=tirage_id)
|
||||||
|
@ -365,17 +340,6 @@ def unpaid(request, tirage_id):
|
||||||
return render(request, "bda-unpaid.html", {"unpaid": unpaid})
|
return render(request, "bda-unpaid.html", {"unpaid": unpaid})
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
|
||||||
def liste_spectacles_ics(request, tirage_id):
|
|
||||||
tirage = get_object_or_404(Tirage, id=tirage_id)
|
|
||||||
spectacles = tirage.spectacle_set.order_by("date").all()
|
|
||||||
for spectacle in spectacles:
|
|
||||||
spectacle.dtend = spectacle.date + timedelta(seconds=7200)
|
|
||||||
return render(request, "liste_spectacles.ics",
|
|
||||||
{"spectacles": spectacles, "tirage": tirage},
|
|
||||||
content_type="text/calendar")
|
|
||||||
|
|
||||||
|
|
||||||
@buro_required
|
@buro_required
|
||||||
def send_rappel(request, spectacle_id):
|
def send_rappel(request, spectacle_id):
|
||||||
show = get_object_or_404(Spectacle, id=spectacle_id)
|
show = get_object_or_404(Spectacle, id=spectacle_id)
|
||||||
|
|
|
@ -13,7 +13,7 @@ from django.views.generic.base import TemplateView
|
||||||
import autocomplete_light
|
import autocomplete_light
|
||||||
|
|
||||||
from gestioncof.urls import export_patterns, petitcours_patterns, \
|
from gestioncof.urls import export_patterns, petitcours_patterns, \
|
||||||
surveys_patterns, events_patterns
|
surveys_patterns, events_patterns, calendar_patterns
|
||||||
|
|
||||||
autocomplete_light.autodiscover()
|
autocomplete_light.autodiscover()
|
||||||
admin.autodiscover()
|
admin.autodiscover()
|
||||||
|
@ -32,6 +32,8 @@ urlpatterns = patterns(
|
||||||
url(r'^survey/', include(surveys_patterns)),
|
url(r'^survey/', include(surveys_patterns)),
|
||||||
# Evenements
|
# Evenements
|
||||||
url(r'^event/', include(events_patterns)),
|
url(r'^event/', include(events_patterns)),
|
||||||
|
# Calendrier
|
||||||
|
url(r'^calendar/', include(calendar_patterns)),
|
||||||
# Authentification
|
# Authentification
|
||||||
url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'),
|
url(r'^cof/denied$', TemplateView.as_view(template_name='cof-denied.html'),
|
||||||
name="cof-denied"),
|
name="cof-denied"),
|
||||||
|
|
|
@ -10,10 +10,13 @@ from django.contrib.auth.models import User
|
||||||
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
|
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
|
||||||
from django.db.models import Max
|
from django.db.models import Max
|
||||||
|
|
||||||
from gestioncof.models import CofProfile, EventCommentValue
|
from gestioncof.models import CofProfile, EventCommentValue, \
|
||||||
|
CalendarSubscription
|
||||||
from gestioncof.widgets import TriStateCheckbox
|
from gestioncof.widgets import TriStateCheckbox
|
||||||
from gestioncof.shared import lock_table, unlock_table
|
from gestioncof.shared import lock_table, unlock_table
|
||||||
|
|
||||||
|
from bda.models import Spectacle
|
||||||
|
|
||||||
|
|
||||||
class EventForm(forms.Form):
|
class EventForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -333,3 +336,21 @@ class AdminEventForm(forms.Form):
|
||||||
for name, value in self.cleaned_data.items():
|
for name, value in self.cleaned_data.items():
|
||||||
if name.startswith('comment_'):
|
if name.startswith('comment_'):
|
||||||
yield (self.fields[name].comment_id, value)
|
yield (self.fields[name].comment_id, value)
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarForm(forms.ModelForm):
|
||||||
|
subscribe_to_events = forms.BooleanField(
|
||||||
|
initial=True,
|
||||||
|
label="Événements du COF.")
|
||||||
|
subscribe_to_my_shows = forms.BooleanField(
|
||||||
|
initial=True,
|
||||||
|
label="Les spectacles pour lesquels j'ai obtenu une place.")
|
||||||
|
other_shows = forms.ModelMultipleChoiceField(
|
||||||
|
label="Spectacles supplémentaires.",
|
||||||
|
queryset=Spectacle.objects.filter(tirage__active=True),
|
||||||
|
widget=forms.CheckboxSelectMultiple)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = CalendarSubscription
|
||||||
|
fields = ['subscribe_to_events', 'subscribe_to_my_shows',
|
||||||
|
'other_shows']
|
||||||
|
|
50
gestioncof/migrations/0005_add_calendar.py
Normal file
50
gestioncof/migrations/0005_add_calendar.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('bda', '0004_mails-rappel'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('gestioncof', '0004_registration_mail'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CalendarSubscription',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False,
|
||||||
|
auto_created=True, primary_key=True)),
|
||||||
|
('token', models.UUIDField()),
|
||||||
|
('subscribe_to_events', models.BooleanField(default=True)),
|
||||||
|
('subscribe_to_my_shows', models.BooleanField(default=True)),
|
||||||
|
('other_shows', models.ManyToManyField(to='bda.Spectacle')),
|
||||||
|
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='custommail',
|
||||||
|
options={'verbose_name': 'Mail personnalisable',
|
||||||
|
'verbose_name_plural': 'Mails personnalisables'},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='eventoptionchoice',
|
||||||
|
options={'verbose_name': 'Choix', 'verbose_name_plural': 'Choix'},
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='event',
|
||||||
|
name='end_date',
|
||||||
|
field=models.DateTimeField(null=True, verbose_name=b'Date de fin',
|
||||||
|
blank=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='event',
|
||||||
|
name='start_date',
|
||||||
|
field=models.DateTimeField(
|
||||||
|
null=True, verbose_name=b'Date de d\xc3\xa9but', blank=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -13,6 +13,8 @@ from django.db.models.signals import post_save
|
||||||
|
|
||||||
from gestioncof.petits_cours_models import choices_length
|
from gestioncof.petits_cours_models import choices_length
|
||||||
|
|
||||||
|
from bda.models import Spectacle
|
||||||
|
|
||||||
OCCUPATION_CHOICES = (
|
OCCUPATION_CHOICES = (
|
||||||
('exterieur', _("Extérieur")),
|
('exterieur', _("Extérieur")),
|
||||||
('1A', _("1A")),
|
('1A', _("1A")),
|
||||||
|
@ -113,8 +115,8 @@ class CustomMail(models.Model):
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
title = models.CharField("Titre", max_length=200)
|
title = models.CharField("Titre", max_length=200)
|
||||||
location = models.CharField("Lieu", max_length=200)
|
location = models.CharField("Lieu", max_length=200)
|
||||||
start_date = models.DateField("Date de début", blank=True, null=True)
|
start_date = models.DateTimeField("Date de début", blank=True, null=True)
|
||||||
end_date = models.DateField("Date de fin", blank=True, null=True)
|
end_date = models.DateTimeField("Date de fin", blank=True, null=True)
|
||||||
description = models.TextField("Description", blank=True)
|
description = models.TextField("Description", blank=True)
|
||||||
image = models.ImageField("Image", blank=True, null=True,
|
image = models.ImageField("Image", blank=True, null=True,
|
||||||
upload_to="imgs/events/")
|
upload_to="imgs/events/")
|
||||||
|
@ -262,3 +264,15 @@ class Clipper(models.Model):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Clipper %s" % self.username
|
return "Clipper %s" % self.username
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class CalendarSubscription(models.Model):
|
||||||
|
token = models.UUIDField()
|
||||||
|
user = models.OneToOneField(User)
|
||||||
|
other_shows = models.ManyToManyField(Spectacle)
|
||||||
|
subscribe_to_events = models.BooleanField(default=True)
|
||||||
|
subscribe_to_my_shows = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Calendrier de %s" % self.user.get_full_name()
|
||||||
|
|
43
gestioncof/templates/calendar_subscription.html
Normal file
43
gestioncof/templates/calendar_subscription.html
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{% extends "base_title.html" %}
|
||||||
|
|
||||||
|
{% block realcontent %}
|
||||||
|
|
||||||
|
<h2>Calendrier dynamique</h2>
|
||||||
|
|
||||||
|
{% if success %}
|
||||||
|
<p class="success">Calendrier mis à jour avec succès</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if error %}
|
||||||
|
<p class="error">{{ error }}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p>Ce formulaire vous permet de définir un calendrier dynamique compatible avec
|
||||||
|
n'importe quel logiciel ou application d'agenda. Vous pouvez choisir de
|
||||||
|
souscrire aux événements du COF et/ou aux spectacles BdA.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% if token %}
|
||||||
|
<p>Votre calendrier (compatible avec toutes les applications d'agenda) se trouve à
|
||||||
|
<a href="{% url 'gestioncof.views.calendar_ics' token %}">cette adresse</a>.</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Pour l'ajouter à Thunderbird (lightning), il faut copier ce lien et aller
|
||||||
|
dans <tt>Fichier > Nouveau > Agenda</tt> puis choisir <tt>Sur le
|
||||||
|
réseau</tt> et le format <tt>.ics</tt>.</li>
|
||||||
|
<li>Avec Apple, il suffit de cliquer sur lien et d'ouvrir le fichier avec
|
||||||
|
l'application calendrier.</li>
|
||||||
|
<li>Google Agenda permet d'importer le fichier au format .ics depuis le menu
|
||||||
|
<tt>Préférences.</tt></li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<form action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<input type="submit" value="Enregistrer" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -50,7 +50,7 @@
|
||||||
<h3 class="block-title">Divers<span class="pull-right glyphicon glyphicon-question-sign"></span></h3>
|
<h3 class="block-title">Divers<span class="pull-right glyphicon glyphicon-question-sign"></span></h3>
|
||||||
<div class="hm-block">
|
<div class="hm-block">
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><a href="{% url "gestioncof.views.calendar" %}">Calendrier dynamique</a></li>
|
||||||
{% if user.profile.is_cof %}<li><a href="{% url "petits-cours-inscription" %}">Inscription pour donner des petits cours</a></li>{% endif %}
|
{% if user.profile.is_cof %}<li><a href="{% url "petits-cours-inscription" %}">Inscription pour donner des petits cours</a></li>{% endif %}
|
||||||
|
|
||||||
<li><a href="{% url "gestioncof.views.profile" %}">Éditer mon profil</a></li>
|
<li><a href="{% url "gestioncof.views.profile" %}">Éditer mon profil</a></li>
|
||||||
|
|
|
@ -45,3 +45,9 @@ events_patterns = [
|
||||||
url(r'^(?P<event_id>\d+)$', 'gestioncof.views.event'),
|
url(r'^(?P<event_id>\d+)$', 'gestioncof.views.event'),
|
||||||
url(r'^(?P<event_id>\d+)/status$', 'gestioncof.views.event_status'),
|
url(r'^(?P<event_id>\d+)/status$', 'gestioncof.views.event_status'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
calendar_patterns = [
|
||||||
|
url(r'^subscription$', 'gestioncof.views.calendar'),
|
||||||
|
url(r'^(?P<token>[a-z0-9-]+)/calendar.ics$',
|
||||||
|
'gestioncof.views.calendar_ics')
|
||||||
|
]
|
||||||
|
|
|
@ -5,6 +5,9 @@ from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import unicodecsv
|
import unicodecsv
|
||||||
|
import uuid
|
||||||
|
from datetime import timedelta
|
||||||
|
from icalendar import Calendar, Event as Vevent
|
||||||
|
|
||||||
from django.shortcuts import redirect, get_object_or_404, render
|
from django.shortcuts import redirect, get_object_or_404, render
|
||||||
from django.http import Http404, HttpResponse
|
from django.http import Http404, HttpResponse
|
||||||
|
@ -17,15 +20,16 @@ from gestioncof.models import Survey, SurveyAnswer, SurveyQuestion, \
|
||||||
SurveyQuestionAnswer
|
SurveyQuestionAnswer
|
||||||
from gestioncof.models import Event, EventRegistration, EventOption, \
|
from gestioncof.models import Event, EventRegistration, EventOption, \
|
||||||
EventOptionChoice
|
EventOptionChoice
|
||||||
from gestioncof.models import EventCommentField, EventCommentValue
|
from gestioncof.models import EventCommentField, EventCommentValue, \
|
||||||
|
CalendarSubscription
|
||||||
from gestioncof.shared import send_custom_mail
|
from gestioncof.shared import send_custom_mail
|
||||||
from gestioncof.models import CofProfile, Clipper
|
from gestioncof.models import CofProfile, Clipper
|
||||||
from gestioncof.decorators import buro_required
|
from gestioncof.decorators import buro_required, cof_required
|
||||||
from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \
|
from gestioncof.forms import UserProfileForm, EventStatusFilterForm, \
|
||||||
SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \
|
SurveyForm, SurveyStatusFilterForm, RegistrationUserForm, \
|
||||||
RegistrationProfileForm, AdminEventForm, EventForm
|
RegistrationProfileForm, AdminEventForm, EventForm, CalendarForm
|
||||||
|
|
||||||
from bda.models import Tirage
|
from bda.models import Tirage, Spectacle
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -633,3 +637,61 @@ def liste_diffcof(request):
|
||||||
personnes = CofProfile.objects.filter(mailing_cof=True, is_cof=True).all()
|
personnes = CofProfile.objects.filter(mailing_cof=True, is_cof=True).all()
|
||||||
return render(request, "liste_mails.html", {"titre": titre,
|
return render(request, "liste_mails.html", {"titre": titre,
|
||||||
"personnes": personnes})
|
"personnes": personnes})
|
||||||
|
|
||||||
|
|
||||||
|
@cof_required
|
||||||
|
def calendar(request):
|
||||||
|
try:
|
||||||
|
instance = CalendarSubscription.objects.get(user=request.user)
|
||||||
|
except CalendarSubscription.DoesNotExist:
|
||||||
|
instance = None
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = CalendarForm(request.POST, instance=instance)
|
||||||
|
if form.is_valid():
|
||||||
|
subscription = form.save(commit=False)
|
||||||
|
if instance is None:
|
||||||
|
subscription.user = request.user
|
||||||
|
subscription.token = uuid.uuid4()
|
||||||
|
subscription.save()
|
||||||
|
form.save_m2m()
|
||||||
|
return render(request, "calendar_subscription.html",
|
||||||
|
{'form': form,
|
||||||
|
'success': True,
|
||||||
|
'token': str(subscription.token)})
|
||||||
|
else:
|
||||||
|
return render(request, "calendar_subscription.html",
|
||||||
|
{'form': form, 'error': "Formulaire incorrect"})
|
||||||
|
else:
|
||||||
|
return render(request, "calendar_subscription.html",
|
||||||
|
{'form': CalendarForm(instance=instance),
|
||||||
|
'token': instance.token if instance else None})
|
||||||
|
|
||||||
|
|
||||||
|
def calendar_ics(request, token):
|
||||||
|
subscription = get_object_or_404(CalendarSubscription, token=token)
|
||||||
|
shows = subscription.other_shows.all()
|
||||||
|
if subscription.subscribe_to_my_shows:
|
||||||
|
shows |= Spectacle.objects.filter(
|
||||||
|
attribues__participant__user=subscription.user,
|
||||||
|
tirage__active=True)
|
||||||
|
shows = shows.distinct()
|
||||||
|
vcal = Calendar()
|
||||||
|
for show in shows:
|
||||||
|
vevent = Vevent()
|
||||||
|
vevent.add('dtstart', show.date)
|
||||||
|
vevent.add('dtend', show.date + timedelta(seconds=7200))
|
||||||
|
vevent.add('summary', show.title)
|
||||||
|
vevent.add('location', show.location.name)
|
||||||
|
vcal.add_component(vevent)
|
||||||
|
if subscription.subscribe_to_events:
|
||||||
|
for event in Event.objects.filter(old=False).all():
|
||||||
|
vevent = Vevent()
|
||||||
|
vevent.add('dtstart', event.start_date)
|
||||||
|
vevent.add('dtend', event.end_date)
|
||||||
|
vevent.add('summary', event.title)
|
||||||
|
vevent.add('location', event.location)
|
||||||
|
vevent.add('description', event.description)
|
||||||
|
vcal.add_component(vevent)
|
||||||
|
response = HttpResponse(content=vcal.to_ical())
|
||||||
|
response['Content-Type'] = "text/calendar"
|
||||||
|
return response
|
||||||
|
|
|
@ -10,4 +10,5 @@ Pillow==2.9.0
|
||||||
simplejson==3.8.2
|
simplejson==3.8.2
|
||||||
six==1.10.0
|
six==1.10.0
|
||||||
unicodecsv==0.14.1
|
unicodecsv==0.14.1
|
||||||
|
icalendar==3.10
|
||||||
django-bootstrap-form==3.2.1
|
django-bootstrap-form==3.2.1
|
||||||
|
|
Loading…
Reference in a new issue