mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-12-06 11:57:41 +01:00
Merge main into potvieux
This commit is contained in:
@@ -17,14 +17,16 @@ from django.utils.translation import gettext_lazy as _
|
||||
from django.views import View
|
||||
from django.views.decorators.cache import cache_page
|
||||
from django.views.generic import DetailView, TemplateView, UpdateView
|
||||
from django_tables2.views import SingleTableView
|
||||
from django.views.generic.list import ListView
|
||||
from django_tables2.views import MultiTableMixin, SingleTableMixin
|
||||
from api.viewsets import is_regex
|
||||
from note.models import Alias, NoteSpecial, NoteUser
|
||||
from permission.backends import PermissionBackend
|
||||
from permission.views import ProtectQuerysetMixin, ProtectedCreateView
|
||||
|
||||
from .forms import ActivityForm, GuestForm
|
||||
from .models import Activity, Entry, Guest
|
||||
from .tables import ActivityTable, EntryTable, GuestTable
|
||||
from .models import Activity, Entry, Guest, Opener
|
||||
from .tables import ActivityTable, EntryTable, GuestTable, OpenerTable
|
||||
|
||||
|
||||
class ActivityCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
||||
@@ -57,27 +59,36 @@ class ActivityCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
||||
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.object.pk})
|
||||
|
||||
|
||||
class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||
class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, ListView):
|
||||
"""
|
||||
Displays all Activities, and classify if they are on-going or upcoming ones.
|
||||
"""
|
||||
model = Activity
|
||||
table_class = ActivityTable
|
||||
ordering = ('-date_start',)
|
||||
tables = [
|
||||
lambda data: ActivityTable(data, prefix="all-"),
|
||||
lambda data: ActivityTable(data, prefix="upcoming-"),
|
||||
]
|
||||
extra_context = {"title": _("Activities")}
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
return super().get_queryset(**kwargs).distinct()
|
||||
|
||||
def get_tables_data(self):
|
||||
# first table = all activities, second table = upcoming
|
||||
return [
|
||||
self.get_queryset().order_by("-date_start"),
|
||||
Activity.objects.filter(date_end__gt=timezone.now())
|
||||
.filter(PermissionBackend.filter_queryset(self.request, Activity, "view"))
|
||||
.distinct()
|
||||
.order_by("date_start")
|
||||
]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
upcoming_activities = Activity.objects.filter(date_end__gt=timezone.now())
|
||||
context['upcoming'] = ActivityTable(
|
||||
data=upcoming_activities.filter(PermissionBackend.filter_queryset(self.request, Activity, "view")),
|
||||
prefix='upcoming-',
|
||||
order_by='date_start',
|
||||
)
|
||||
tables = context["tables"]
|
||||
for name, table in zip(["table", "upcoming"], tables):
|
||||
context[name] = table
|
||||
|
||||
started_activities = self.get_queryset().filter(open=True, valid=True).distinct().all()
|
||||
context["started_activities"] = started_activities
|
||||
@@ -85,7 +96,7 @@ class ActivityListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
|
||||
return context
|
||||
|
||||
|
||||
class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
||||
class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, DetailView):
|
||||
"""
|
||||
Shows details about one activity. Add guest to context
|
||||
"""
|
||||
@@ -93,15 +104,40 @@ class ActivityDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
||||
context_object_name = "activity"
|
||||
extra_context = {"title": _("Activity detail")}
|
||||
|
||||
tables = [
|
||||
lambda data: GuestTable(data, prefix="guests-"),
|
||||
lambda data: OpenerTable(data, prefix="opener-"),
|
||||
]
|
||||
|
||||
def get_tables_data(self):
|
||||
return [
|
||||
Guest.objects.filter(activity=self.object)
|
||||
.filter(PermissionBackend.filter_queryset(self.request, Guest, "view")),
|
||||
self.object.opener.filter(activity=self.object)
|
||||
.filter(PermissionBackend.filter_queryset(self.request, Opener, "view")),
|
||||
]
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data()
|
||||
|
||||
table = GuestTable(data=Guest.objects.filter(activity=self.object)
|
||||
.filter(PermissionBackend.filter_queryset(self.request, Guest, "view")))
|
||||
context["guests"] = table
|
||||
tables = context["tables"]
|
||||
for name, table in zip(["guests", "opener"], tables):
|
||||
context[name] = table
|
||||
|
||||
context["activity_started"] = timezone.now() > timezone.localtime(self.object.date_start)
|
||||
|
||||
context["widget"] = {
|
||||
"name": "opener",
|
||||
"resetable": True,
|
||||
"attrs": {
|
||||
"class": "autocomplete form-control",
|
||||
"id": "opener",
|
||||
"api_url": "/api/note/alias/?note__polymorphic_ctype__model=noteuser",
|
||||
"name_field": "name",
|
||||
"placeholder": ""
|
||||
}
|
||||
}
|
||||
|
||||
return context
|
||||
|
||||
|
||||
@@ -158,12 +194,14 @@ class ActivityInviteView(ProtectQuerysetMixin, ProtectedCreateView):
|
||||
return reverse_lazy('activity:activity_detail', kwargs={"pk": self.kwargs["pk"]})
|
||||
|
||||
|
||||
class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||
class ActivityEntryView(LoginRequiredMixin, SingleTableMixin, TemplateView):
|
||||
"""
|
||||
Manages entry to an activity
|
||||
"""
|
||||
template_name = "activity/activity_entry.html"
|
||||
|
||||
table_class = EntryTable
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
"""
|
||||
Don't display the entry interface if the user has no right to see it (no right to add an entry for itself),
|
||||
@@ -198,13 +236,16 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||
|
||||
if "search" in self.request.GET and self.request.GET["search"]:
|
||||
pattern = self.request.GET["search"]
|
||||
if pattern[0] != "^":
|
||||
pattern = "^" + pattern
|
||||
|
||||
# Check if this is a valid regex. If not, we won't check regex
|
||||
valid_regex = is_regex(pattern)
|
||||
suffix = "__iregex" if valid_regex else "__istartswith"
|
||||
pattern = "^" + pattern if valid_regex and pattern[0] != "^" else pattern
|
||||
guest_qs = guest_qs.filter(
|
||||
Q(first_name__iregex=pattern)
|
||||
| Q(last_name__iregex=pattern)
|
||||
| Q(inviter__alias__name__iregex=pattern)
|
||||
| Q(inviter__alias__normalized_name__iregex=Alias.normalize(pattern))
|
||||
Q(**{f"first_name{suffix}": pattern})
|
||||
| Q(**{f"last_name{suffix}": pattern})
|
||||
| Q(**{f"inviter__alias__name{suffix}": pattern})
|
||||
| Q(**{f"inviter__alias__normalized_name{suffix}": Alias.normalize(pattern)})
|
||||
)
|
||||
else:
|
||||
guest_qs = guest_qs.none()
|
||||
@@ -222,26 +263,38 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||
balance=F("note__balance"))
|
||||
|
||||
# Keep only users that have a note
|
||||
note_qs = note_qs.filter(note__noteuser__isnull=False)
|
||||
note_qs = note_qs.filter(note__noteuser__isnull=False).exclude(note__inactivity_reason='forced')
|
||||
|
||||
# if activity.activity_type.name != "Pot Vieux":
|
||||
# # Keep only members
|
||||
# note_qs = note_qs.filter(
|
||||
# note__noteuser__user__memberships__club=activity.attendees_club,
|
||||
# note__noteuser__user__memberships__date_start__lte=timezone.now(),
|
||||
# note__noteuser__user__memberships__date_end__gte=timezone.now(),
|
||||
# )
|
||||
|
||||
if activity.activity_type.name != "Pot Vieux":
|
||||
# Keep only members
|
||||
note_qs = note_qs.filter(
|
||||
note__noteuser__user__memberships__club=activity.attendees_club,
|
||||
note__noteuser__user__memberships__date_start__lte=timezone.now(),
|
||||
note__noteuser__user__memberships__date_end__gte=timezone.now(),
|
||||
)
|
||||
|
||||
# Keep only valid members
|
||||
# note_qs = note_qs.filter(
|
||||
# note__noteuser__user__memberships__club=activity.attendees_club,
|
||||
# note__noteuser__user__memberships__date_start__lte=timezone.now(),
|
||||
# note__noteuser__user__memberships__date_end__gte=timezone.now(),
|
||||
# )
|
||||
|
||||
# Filter with permission backend
|
||||
note_qs = note_qs.filter(PermissionBackend.filter_queryset(self.request, Alias, "view"))
|
||||
|
||||
if "search" in self.request.GET and self.request.GET["search"]:
|
||||
pattern = self.request.GET["search"]
|
||||
|
||||
# Check if this is a valid regex. If not, we won't check regex
|
||||
valid_regex = is_regex(pattern)
|
||||
suffix = "__iregex" if valid_regex else "__icontains"
|
||||
note_qs = note_qs.filter(
|
||||
Q(note__noteuser__user__first_name__iregex=pattern)
|
||||
| Q(note__noteuser__user__last_name__iregex=pattern)
|
||||
| Q(name__iregex=pattern)
|
||||
| Q(normalized_name__iregex=Alias.normalize(pattern))
|
||||
Q(**{f"note__noteuser__user__first_name{suffix}": pattern})
|
||||
| Q(**{f"note__noteuser__user__last_name{suffix}": pattern})
|
||||
| Q(**{f"name{suffix}": pattern})
|
||||
| Q(**{f"normalized_name{suffix}": Alias.normalize(pattern)})
|
||||
)
|
||||
else:
|
||||
note_qs = note_qs.none()
|
||||
@@ -253,15 +306,9 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||
if settings.DATABASES[note_qs.db]["ENGINE"] == 'django.db.backends.postgresql' else note_qs.distinct()[:20]
|
||||
return note_qs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""
|
||||
Query the list of Guest and Note to the activity and add information to makes entry with JS.
|
||||
"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
def get_table_data(self):
|
||||
activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request, Activity, "view"))\
|
||||
.distinct().get(pk=self.kwargs["pk"])
|
||||
context["activity"] = activity
|
||||
|
||||
matched = []
|
||||
|
||||
@@ -274,8 +321,17 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView):
|
||||
note.activity = activity
|
||||
matched.append(note)
|
||||
|
||||
table = EntryTable(data=matched)
|
||||
context["table"] = table
|
||||
return matched
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""
|
||||
Query the list of Guest and Note to the activity and add information to makes entry with JS.
|
||||
"""
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request, Activity, "view"))\
|
||||
.distinct().get(pk=self.kwargs["pk"])
|
||||
context["activity"] = activity
|
||||
|
||||
context["entries"] = Entry.objects.filter(activity=activity)
|
||||
|
||||
@@ -317,8 +373,8 @@ X-WR-CALNAME:Kfet Calendar
|
||||
NAME:Kfet Calendar
|
||||
CALSCALE:GREGORIAN
|
||||
BEGIN:VTIMEZONE
|
||||
TZID:Europe/Berlin
|
||||
X-LIC-LOCATION:Europe/Berlin
|
||||
TZID:Europe/Paris
|
||||
X-LIC-LOCATION:Europe/Paris
|
||||
BEGIN:DAYLIGHT
|
||||
TZOFFSETFROM:+0100
|
||||
TZOFFSETTO:+0200
|
||||
@@ -340,10 +396,10 @@ END:VTIMEZONE
|
||||
DTSTAMP:{"{:%Y%m%dT%H%M%S}".format(activity.date_start)}Z
|
||||
UID:{md5((activity.name + "$" + str(activity.id) + str(activity.date_start)).encode("UTF-8")).hexdigest()}
|
||||
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)}
|
||||
DTSTART:{"{:%Y%m%dT%H%M%S}Z".format(activity.date_start)}
|
||||
DTEND:{"{:%Y%m%dT%H%M%S}Z".format(activity.date_end)}
|
||||
LOCATION:{self.multilines(activity.location, 75, 9) if activity.location else "Kfet"}
|
||||
DESCRIPTION;CHARSET=UTF-8:""" + self.multilines(activity.description.replace("\n", "\\n"), 75, 26) + """
|
||||
DESCRIPTION;CHARSET=UTF-8:""" + self.multilines(activity.description.replace("\n", "\\n"), 75, 26) + f"""
|
||||
-- {activity.organizer.name}
|
||||
END:VEVENT
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user