mirror of
https://gitlab.crans.org/bde/nk20
synced 2024-11-26 18:37:12 +00:00
Export activites as an ICS Calendar
This commit is contained in:
parent
5c7fe716ad
commit
70e1a611dd
@ -14,4 +14,5 @@ urlpatterns = [
|
|||||||
path('<int:pk>/entry/', views.ActivityEntryView.as_view(), name='activity_entry'),
|
path('<int:pk>/entry/', views.ActivityEntryView.as_view(), name='activity_entry'),
|
||||||
path('<int:pk>/update/', views.ActivityUpdateView.as_view(), name='activity_update'),
|
path('<int:pk>/update/', views.ActivityUpdateView.as_view(), name='activity_update'),
|
||||||
path('new/', views.ActivityCreateView.as_view(), name='activity_create'),
|
path('new/', views.ActivityCreateView.as_view(), name='activity_create'),
|
||||||
|
path('calendar.ics', views.CalendarView.as_view(), name='calendar_ics'),
|
||||||
]
|
]
|
||||||
|
@ -1,283 +1,344 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
from hashlib import md5
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.models import F, Q
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.urls import reverse_lazy
|
from django.db.models import F, Q
|
||||||
from django.utils import timezone
|
from django.http import HttpResponse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic import DetailView, TemplateView, UpdateView
|
from django.utils import timezone
|
||||||
from django_tables2.views import SingleTableView
|
from django.utils.translation import gettext_lazy as _
|
||||||
from note.models import Alias, NoteSpecial, NoteUser
|
from django.views import View
|
||||||
from permission.backends import PermissionBackend
|
from django.views.generic import DetailView, TemplateView, UpdateView
|
||||||
from permission.views import ProtectQuerysetMixin, ProtectedCreateView
|
from django_tables2.views import SingleTableView
|
||||||
|
from note.models import Alias, NoteSpecial, NoteUser
|
||||||
from .forms import ActivityForm, GuestForm
|
from permission.backends import PermissionBackend
|
||||||
from .models import Activity, Entry, Guest
|
from permission.views import ProtectQuerysetMixin, ProtectedCreateView
|
||||||
from .tables import ActivityTable, EntryTable, GuestTable
|
|
||||||
|
from .forms import ActivityForm, GuestForm
|
||||||
|
from .models import Activity, Entry, Guest
|
||||||
class ActivityCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
from .tables import ActivityTable, EntryTable, GuestTable
|
||||||
"""
|
|
||||||
View to create a new Activity
|
|
||||||
"""
|
class ActivityCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
||||||
model = Activity
|
"""
|
||||||
form_class = ActivityForm
|
View to create a new Activity
|
||||||
extra_context = {"title": _("Create new activity")}
|
"""
|
||||||
|
model = Activity
|
||||||
def get_sample_object(self):
|
form_class = ActivityForm
|
||||||
return Activity(
|
extra_context = {"title": _("Create new activity")}
|
||||||
name="",
|
|
||||||
description="",
|
def get_sample_object(self):
|
||||||
creater=self.request.user,
|
return Activity(
|
||||||
activity_type_id=1,
|
name="",
|
||||||
organizer_id=1,
|
description="",
|
||||||
attendees_club_id=1,
|
creater=self.request.user,
|
||||||
date_start=timezone.now(),
|
activity_type_id=1,
|
||||||
date_end=timezone.now(),
|
organizer_id=1,
|
||||||
)
|
attendees_club_id=1,
|
||||||
|
date_start=timezone.now(),
|
||||||
def form_valid(self, form):
|
date_end=timezone.now(),
|
||||||
form.instance.creater = self.request.user
|
)
|
||||||
return super().form_valid(form)
|
|
||||||
|
def form_valid(self, form):
|
||||||
def get_success_url(self, **kwargs):
|
form.instance.creater = self.request.user
|
||||||
self.object.refresh_from_db()
|
return super().form_valid(form)
|
||||||
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.object.pk})
|
|
||||||
|
def get_success_url(self, **kwargs):
|
||||||
|
self.object.refresh_from_db()
|
||||||
class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.object.pk})
|
||||||
"""
|
|
||||||
Displays all Activities, and classify if they are on-going or upcoming ones.
|
|
||||||
"""
|
class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||||
model = Activity
|
"""
|
||||||
table_class = ActivityTable
|
Displays all Activities, and classify if they are on-going or upcoming ones.
|
||||||
ordering = ('-date_start',)
|
"""
|
||||||
extra_context = {"title": _("Activities")}
|
model = Activity
|
||||||
|
table_class = ActivityTable
|
||||||
def get_queryset(self):
|
ordering = ('-date_start',)
|
||||||
return super().get_queryset().distinct()
|
extra_context = {"title": _("Activities")}
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_queryset(self):
|
||||||
context = super().get_context_data(**kwargs)
|
return super().get_queryset().distinct()
|
||||||
|
|
||||||
upcoming_activities = Activity.objects.filter(date_end__gt=timezone.now())
|
def get_context_data(self, **kwargs):
|
||||||
context['upcoming'] = ActivityTable(
|
context = super().get_context_data(**kwargs)
|
||||||
data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")),
|
|
||||||
prefix='upcoming-',
|
upcoming_activities = Activity.objects.filter(date_end__gt=timezone.now())
|
||||||
)
|
context['upcoming'] = ActivityTable(
|
||||||
|
data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")),
|
||||||
started_activities = Activity.objects\
|
prefix='upcoming-',
|
||||||
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
|
)
|
||||||
.filter(open=True, valid=True).all()
|
|
||||||
context["started_activities"] = started_activities
|
started_activities = Activity.objects\
|
||||||
|
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
|
||||||
return context
|
.filter(open=True, valid=True).all()
|
||||||
|
context["started_activities"] = started_activities
|
||||||
|
|
||||||
class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
return context
|
||||||
"""
|
|
||||||
Shows details about one activity. Add guest to context
|
|
||||||
"""
|
class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
||||||
model = Activity
|
"""
|
||||||
context_object_name = "activity"
|
Shows details about one activity. Add guest to context
|
||||||
extra_context = {"title": _("Activity detail")}
|
"""
|
||||||
|
model = Activity
|
||||||
def get_context_data(self, **kwargs):
|
context_object_name = "activity"
|
||||||
context = super().get_context_data()
|
extra_context = {"title": _("Activity detail")}
|
||||||
|
|
||||||
table = GuestTable(data=Guest.objects.filter(activity=self.object)
|
def get_context_data(self, **kwargs):
|
||||||
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view")))
|
context = super().get_context_data()
|
||||||
context["guests"] = table
|
|
||||||
|
table = GuestTable(data=Guest.objects.filter(activity=self.object)
|
||||||
context["activity_started"] = timezone.now() > timezone.localtime(self.object.date_start)
|
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view")))
|
||||||
|
context["guests"] = table
|
||||||
return context
|
|
||||||
|
context["activity_started"] = timezone.now() > timezone.localtime(self.object.date_start)
|
||||||
|
|
||||||
class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
return context
|
||||||
"""
|
|
||||||
Updates one Activity
|
|
||||||
"""
|
class ActivityUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||||
model = Activity
|
"""
|
||||||
form_class = ActivityForm
|
Updates one Activity
|
||||||
extra_context = {"title": _("Update activity")}
|
"""
|
||||||
|
model = Activity
|
||||||
def get_success_url(self, **kwargs):
|
form_class = ActivityForm
|
||||||
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
|
extra_context = {"title": _("Update activity")}
|
||||||
|
|
||||||
|
def get_success_url(self, **kwargs):
|
||||||
class ActivityInviteView(ProtectQuerysetMixin, ProtectedCreateView):
|
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
|
||||||
"""
|
|
||||||
Invite a Guest, The rules to invites someone are defined in `forms:activity.GuestForm`
|
|
||||||
"""
|
class ActivityInviteView(ProtectQuerysetMixin, ProtectedCreateView):
|
||||||
model = Guest
|
"""
|
||||||
form_class = GuestForm
|
Invite a Guest, The rules to invites someone are defined in `forms:activity.GuestForm`
|
||||||
template_name = "activity/activity_form.html"
|
"""
|
||||||
|
model = Guest
|
||||||
def get_sample_object(self):
|
form_class = GuestForm
|
||||||
""" Creates a standart Guest binds to the Activity"""
|
template_name = "activity/activity_form.html"
|
||||||
activity = Activity.objects.get(pk=self.kwargs["pk"])
|
|
||||||
return Guest(
|
def get_sample_object(self):
|
||||||
activity=activity,
|
""" Creates a standart Guest binds to the Activity"""
|
||||||
first_name="",
|
activity = Activity.objects.get(pk=self.kwargs["pk"])
|
||||||
last_name="",
|
return Guest(
|
||||||
inviter=self.request.user.note,
|
activity=activity,
|
||||||
)
|
first_name="",
|
||||||
|
last_name="",
|
||||||
def get_context_data(self, **kwargs):
|
inviter=self.request.user.note,
|
||||||
context = super().get_context_data(**kwargs)
|
)
|
||||||
activity = context["form"].activity
|
|
||||||
context["title"] = _('Invite guest to the activity "{}"').format(activity.name)
|
def get_context_data(self, **kwargs):
|
||||||
return context
|
context = super().get_context_data(**kwargs)
|
||||||
|
activity = context["form"].activity
|
||||||
def get_form(self, form_class=None):
|
context["title"] = _('Invite guest to the activity "{}"').format(activity.name)
|
||||||
form = super().get_form(form_class)
|
return context
|
||||||
form.activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
|
|
||||||
.get(pk=self.kwargs["pk"])
|
def get_form(self, form_class=None):
|
||||||
form.fields["inviter"].initial = self.request.user.note
|
form = super().get_form(form_class)
|
||||||
return form
|
form.activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
|
||||||
|
.get(pk=self.kwargs["pk"])
|
||||||
def form_valid(self, form):
|
form.fields["inviter"].initial = self.request.user.note
|
||||||
form.instance.activity = Activity.objects\
|
return form
|
||||||
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).get(pk=self.kwargs["pk"])
|
|
||||||
return super().form_valid(form)
|
def form_valid(self, form):
|
||||||
|
form.instance.activity = Activity.objects\
|
||||||
def get_success_url(self, **kwargs):
|
.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view")).get(pk=self.kwargs["pk"])
|
||||||
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def get_success_url(self, **kwargs):
|
||||||
class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
|
||||||
"""
|
|
||||||
Manages entry to an activity
|
|
||||||
"""
|
class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||||
template_name = "activity/activity_entry.html"
|
"""
|
||||||
|
Manages entry to an activity
|
||||||
def dispatch(self, request, *args, **kwargs):
|
"""
|
||||||
"""
|
template_name = "activity/activity_entry.html"
|
||||||
Don't display the entry interface if the user has no right to see it (no right to add an entry for itself),
|
|
||||||
it is closed or doesn't manage entries.
|
def dispatch(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
activity = Activity.objects.get(pk=self.kwargs["pk"])
|
Don't display the entry interface if the user has no right to see it (no right to add an entry for itself),
|
||||||
|
it is closed or doesn't manage entries.
|
||||||
sample_entry = Entry(activity=activity, note=self.request.user.note)
|
"""
|
||||||
if not PermissionBackend.check_perm(self.request.user, "activity.add_entry", sample_entry):
|
activity = Activity.objects.get(pk=self.kwargs["pk"])
|
||||||
raise PermissionDenied(_("You are not allowed to display the entry interface for this activity."))
|
|
||||||
|
sample_entry = Entry(activity=activity, note=self.request.user.note)
|
||||||
if not activity.activity_type.manage_entries:
|
if not PermissionBackend.check_perm(self.request.user, "activity.add_entry", sample_entry):
|
||||||
raise PermissionDenied(_("This activity does not support activity entries."))
|
raise PermissionDenied(_("You are not allowed to display the entry interface for this activity."))
|
||||||
|
|
||||||
if not activity.open:
|
if not activity.activity_type.manage_entries:
|
||||||
raise PermissionDenied(_("This activity is closed."))
|
raise PermissionDenied(_("This activity does not support activity entries."))
|
||||||
return super().dispatch(request, *args, **kwargs)
|
|
||||||
|
if not activity.open:
|
||||||
def get_invited_guest(self, activity):
|
raise PermissionDenied(_("This activity is closed."))
|
||||||
"""
|
return super().dispatch(request, *args, **kwargs)
|
||||||
Retrieves all Guests to the activity
|
|
||||||
"""
|
def get_invited_guest(self, activity):
|
||||||
|
"""
|
||||||
guest_qs = Guest.objects\
|
Retrieves all Guests to the activity
|
||||||
.annotate(balance=F("inviter__balance"), note_name=F("inviter__user__username"))\
|
"""
|
||||||
.filter(activity=activity)\
|
|
||||||
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view"))\
|
guest_qs = Guest.objects\
|
||||||
.order_by('last_name', 'first_name').distinct()
|
.annotate(balance=F("inviter__balance"), note_name=F("inviter__user__username"))\
|
||||||
|
.filter(activity=activity)\
|
||||||
if "search" in self.request.GET and self.request.GET["search"]:
|
.filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view"))\
|
||||||
pattern = self.request.GET["search"]
|
.order_by('last_name', 'first_name').distinct()
|
||||||
if pattern[0] != "^":
|
|
||||||
pattern = "^" + pattern
|
if "search" in self.request.GET and self.request.GET["search"]:
|
||||||
guest_qs = guest_qs.filter(
|
pattern = self.request.GET["search"]
|
||||||
Q(first_name__regex=pattern)
|
if pattern[0] != "^":
|
||||||
| Q(last_name__regex=pattern)
|
pattern = "^" + pattern
|
||||||
| Q(inviter__alias__name__regex=pattern)
|
guest_qs = guest_qs.filter(
|
||||||
| Q(inviter__alias__normalized_name__regex=Alias.normalize(pattern))
|
Q(first_name__regex=pattern)
|
||||||
)
|
| Q(last_name__regex=pattern)
|
||||||
else:
|
| Q(inviter__alias__name__regex=pattern)
|
||||||
guest_qs = guest_qs.none()
|
| Q(inviter__alias__normalized_name__regex=Alias.normalize(pattern))
|
||||||
return guest_qs
|
)
|
||||||
|
else:
|
||||||
def get_invited_note(self, activity):
|
guest_qs = guest_qs.none()
|
||||||
"""
|
return guest_qs
|
||||||
Retrieves all Note that can attend the activity,
|
|
||||||
they need to have an up-to-date membership in the attendees_club.
|
def get_invited_note(self, activity):
|
||||||
"""
|
"""
|
||||||
note_qs = Alias.objects.annotate(last_name=F("note__noteuser__user__last_name"),
|
Retrieves all Note that can attend the activity,
|
||||||
first_name=F("note__noteuser__user__first_name"),
|
they need to have an up-to-date membership in the attendees_club.
|
||||||
username=F("note__noteuser__user__username"),
|
"""
|
||||||
note_name=F("name"),
|
note_qs = Alias.objects.annotate(last_name=F("note__noteuser__user__last_name"),
|
||||||
balance=F("note__balance"))
|
first_name=F("note__noteuser__user__first_name"),
|
||||||
|
username=F("note__noteuser__user__username"),
|
||||||
# Keep only users that have a note
|
note_name=F("name"),
|
||||||
note_qs = note_qs.filter(note__noteuser__isnull=False)
|
balance=F("note__balance"))
|
||||||
|
|
||||||
# Keep only members
|
# Keep only users that have a note
|
||||||
note_qs = note_qs.filter(
|
note_qs = note_qs.filter(note__noteuser__isnull=False)
|
||||||
note__noteuser__user__memberships__club=activity.attendees_club,
|
|
||||||
note__noteuser__user__memberships__date_start__lte=timezone.now(),
|
# Keep only members
|
||||||
note__noteuser__user__memberships__date_end__gte=timezone.now(),
|
note_qs = note_qs.filter(
|
||||||
)
|
note__noteuser__user__memberships__club=activity.attendees_club,
|
||||||
|
note__noteuser__user__memberships__date_start__lte=timezone.now(),
|
||||||
# Filter with permission backend
|
note__noteuser__user__memberships__date_end__gte=timezone.now(),
|
||||||
note_qs = note_qs.filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view"))
|
)
|
||||||
|
|
||||||
if "search" in self.request.GET and self.request.GET["search"]:
|
# Filter with permission backend
|
||||||
pattern = self.request.GET["search"]
|
note_qs = note_qs.filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view"))
|
||||||
note_qs = note_qs.filter(
|
|
||||||
Q(note__noteuser__user__first_name__regex=pattern)
|
if "search" in self.request.GET and self.request.GET["search"]:
|
||||||
| Q(note__noteuser__user__last_name__regex=pattern)
|
pattern = self.request.GET["search"]
|
||||||
| Q(name__regex=pattern)
|
note_qs = note_qs.filter(
|
||||||
| Q(normalized_name__regex=Alias.normalize(pattern))
|
Q(note__noteuser__user__first_name__regex=pattern)
|
||||||
)
|
| Q(note__noteuser__user__last_name__regex=pattern)
|
||||||
else:
|
| Q(name__regex=pattern)
|
||||||
note_qs = note_qs.none()
|
| Q(normalized_name__regex=Alias.normalize(pattern))
|
||||||
|
)
|
||||||
if settings.DATABASES[note_qs.db]["ENGINE"] == 'django.db.backends.postgresql':
|
else:
|
||||||
note_qs = note_qs.distinct('note__pk')[:20]
|
note_qs = note_qs.none()
|
||||||
else:
|
|
||||||
# SQLite doesn't support distinct fields. For compatibility reason (in dev mode), the note list will only
|
if settings.DATABASES[note_qs.db]["ENGINE"] == 'django.db.backends.postgresql':
|
||||||
# have distinct aliases rather than distinct notes with a SQLite DB, but it can fill the result page.
|
note_qs = note_qs.distinct('note__pk')[:20]
|
||||||
# In production mode, please use PostgreSQL.
|
else:
|
||||||
note_qs = note_qs.distinct()[:20]
|
# SQLite doesn't support distinct fields. For compatibility reason (in dev mode), the note list will only
|
||||||
return note_qs
|
# have distinct aliases rather than distinct notes with a SQLite DB, but it can fill the result page.
|
||||||
|
# In production mode, please use PostgreSQL.
|
||||||
def get_context_data(self, **kwargs):
|
note_qs = note_qs.distinct()[:20]
|
||||||
"""
|
return note_qs
|
||||||
Query the list of Guest and Note to the activity and add information to makes entry with JS.
|
|
||||||
"""
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
"""
|
||||||
|
Query the list of Guest and Note to the activity and add information to makes entry with JS.
|
||||||
activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
|
"""
|
||||||
.distinct().get(pk=self.kwargs["pk"])
|
context = super().get_context_data(**kwargs)
|
||||||
context["activity"] = activity
|
|
||||||
|
activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\
|
||||||
matched = []
|
.distinct().get(pk=self.kwargs["pk"])
|
||||||
|
context["activity"] = activity
|
||||||
for guest in self.get_invited_guest(activity):
|
|
||||||
guest.type = "Invité"
|
matched = []
|
||||||
matched.append(guest)
|
|
||||||
|
for guest in self.get_invited_guest(activity):
|
||||||
for note in self.get_invited_note(activity):
|
guest.type = "Invité"
|
||||||
note.type = "Adhérent"
|
matched.append(guest)
|
||||||
note.activity = activity
|
|
||||||
matched.append(note)
|
for note in self.get_invited_note(activity):
|
||||||
|
note.type = "Adhérent"
|
||||||
table = EntryTable(data=matched)
|
note.activity = activity
|
||||||
context["table"] = table
|
matched.append(note)
|
||||||
|
|
||||||
context["entries"] = Entry.objects.filter(activity=activity)
|
table = EntryTable(data=matched)
|
||||||
|
context["table"] = table
|
||||||
context["title"] = _('Entry for activity "{}"').format(activity.name)
|
|
||||||
context["noteuser_ctype"] = ContentType.objects.get_for_model(NoteUser).pk
|
context["entries"] = Entry.objects.filter(activity=activity)
|
||||||
context["notespecial_ctype"] = ContentType.objects.get_for_model(NoteSpecial).pk
|
|
||||||
|
context["title"] = _('Entry for activity "{}"').format(activity.name)
|
||||||
activities_open = Activity.objects.filter(open=True).filter(
|
context["noteuser_ctype"] = ContentType.objects.get_for_model(NoteUser).pk
|
||||||
PermissionBackend.filter_queryset(self.request.user, Activity, "view")).distinct().all()
|
context["notespecial_ctype"] = ContentType.objects.get_for_model(NoteSpecial).pk
|
||||||
context["activities_open"] = [a for a in activities_open
|
|
||||||
if PermissionBackend.check_perm(self.request.user,
|
activities_open = Activity.objects.filter(open=True).filter(
|
||||||
"activity.add_entry",
|
PermissionBackend.filter_queryset(self.request.user, Activity, "view")).distinct().all()
|
||||||
Entry(activity=a, note=self.request.user.note,))]
|
context["activities_open"] = [a for a in activities_open
|
||||||
|
if PermissionBackend.check_perm(self.request.user,
|
||||||
return context
|
"activity.add_entry",
|
||||||
|
Entry(activity=a, note=self.request.user.note,))]
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarView(View):
|
||||||
|
"""
|
||||||
|
Render an ICS calendar with all valid activities.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def multilines(self, string, maxlength, offset=0):
|
||||||
|
newstring = string[:maxlength - offset]
|
||||||
|
string = string[maxlength - offset:]
|
||||||
|
while string:
|
||||||
|
newstring += "\r\n "
|
||||||
|
newstring += string[:maxlength - 1]
|
||||||
|
string = string[maxlength - 1:]
|
||||||
|
return newstring
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
ics = """BEGIN:VCALENDAR
|
||||||
|
VERSION: 2.0
|
||||||
|
PRODID:Note Kfet 2020
|
||||||
|
X-WR-CALNAME:Kfet Calendar
|
||||||
|
NAME:Kfet Calendar
|
||||||
|
CALSCALE:GREGORIAN
|
||||||
|
BEGIN:VTIMEZONE
|
||||||
|
TZID:Europe/Berlin
|
||||||
|
TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Berlin
|
||||||
|
X-LIC-LOCATION:Europe/Berlin
|
||||||
|
BEGIN:DAYLIGHT
|
||||||
|
TZOFFSETFROM:+0100
|
||||||
|
TZOFFSETTO:+0200
|
||||||
|
TZNAME:CEST
|
||||||
|
DTSTART:19700329T020000
|
||||||
|
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
||||||
|
END:DAYLIGHT
|
||||||
|
BEGIN:STANDARD
|
||||||
|
TZOFFSETFROM:+0200
|
||||||
|
TZOFFSETTO:+0100
|
||||||
|
TZNAME:CET
|
||||||
|
DTSTART:19701025T030000
|
||||||
|
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||||
|
END:STANDARD
|
||||||
|
END:VTIMEZONE
|
||||||
|
"""
|
||||||
|
for activity in Activity.objects.filter(valid=True).order_by("-date_start").all():
|
||||||
|
ics += f"""BEGIN:VEVENT
|
||||||
|
DTSTAMP:{"{:%Y%m%dT%H%M%S}".format(activity.date_start)}Z
|
||||||
|
UID:{activity.id}
|
||||||
|
SUMMARY;CHARSET=UTF-8:{self.multilines(activity.name, 75, 22)}
|
||||||
|
DTSTART;TZID=Europe/Berlin:{"{:%Y%m%dT%H%M%S}".format(activity.date_start)}
|
||||||
|
DTEND;TZID=Europe/Berlin:{"{:%Y%m%dT%H%M%S}".format(activity.date_end)}
|
||||||
|
LOCATION:{self.multilines(activity.location, 75, 9) if activity.location else "Kfet"}
|
||||||
|
DESCRIPTION;CHARSET=UTF-8:{self.multilines(activity.description, 75, 26)}
|
||||||
|
-- {activity.organizer.name}
|
||||||
|
END:VEVENT
|
||||||
|
"""
|
||||||
|
ics += "END:VCALENDAR"
|
||||||
|
ics = ics.replace("\r", "").replace("\n", "\r\n")
|
||||||
|
return HttpResponse(ics, content_type="text/calendar; charset=UTF-8")
|
||||||
|
@ -117,10 +117,7 @@ def delete_object(sender, instance, **kwargs):
|
|||||||
Each time a model is deleted, an entry in the table `Changelog` is added in the database
|
Each time a model is deleted, an entry in the table `Changelog` is added in the database
|
||||||
"""
|
"""
|
||||||
# noinspection PyProtectedMember
|
# noinspection PyProtectedMember
|
||||||
if instance._meta.label_lower in EXCLUDED:
|
if instance._meta.label_lower in EXCLUDED or hasattr(instance, "_no_log"):
|
||||||
return
|
|
||||||
|
|
||||||
if hasattr(instance, "_no_log"):
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Si un utilisateur est connecté, on récupère l'utilisateur courant ainsi que son adresse IP
|
# Si un utilisateur est connecté, on récupère l'utilisateur courant ainsi que son adresse IP
|
||||||
|
Loading…
Reference in New Issue
Block a user