diff --git a/fiesta/apps/events/models/participant.py b/fiesta/apps/events/models/participant.py
index 4f524230..407db3ce 100644
--- a/fiesta/apps/events/models/participant.py
+++ b/fiesta/apps/events/models/participant.py
@@ -16,7 +16,7 @@ class Participant(BaseModel):
user = models.ForeignKey(
to="accounts.User",
- related_name="participants",
+ related_name="event_participants",
on_delete=models.SET_NULL,
null=True,
db_index=True,
@@ -26,7 +26,7 @@ class Participant(BaseModel):
event = models.ForeignKey(
to="events.Event",
on_delete=models.SET_NULL,
- related_name="participants",
+ related_name="event_participants",
null=True,
db_index=True,
verbose_name=_("event"),
diff --git a/fiesta/apps/events/templates/events/event_detail.html b/fiesta/apps/events/templates/events/event_detail.html
index cd346af4..1266ab1f 100644
--- a/fiesta/apps/events/templates/events/event_detail.html
+++ b/fiesta/apps/events/templates/events/event_detail.html
@@ -99,7 +99,7 @@
Organizers
-
-
-
{% endif %}
+
@@ -142,7 +141,11 @@ Organizers
Event
@@ -191,12 +194,16 @@ {{ event.title }}
{% if request.membership.is_international %}
-
-
+
+ {%translate "Register"%}
+
+
{% endif %}
+
@@ -249,10 +256,14 @@ {{ event.title }}
{% if request.membership.is_international %}
-
+
+ {%translate "Register"%}
+
+
{% endif %}
diff --git a/fiesta/apps/events/templates/events/index.html b/fiesta/apps/events/templates/events/index.html
index 9f89a2e3..9b47cfd3 100644
--- a/fiesta/apps/events/templates/events/index.html
+++ b/fiesta/apps/events/templates/events/index.html
@@ -7,10 +7,10 @@
Your events
- {% for participating in participations %}
- {% with event=participating.event %}
- {% include "events/parts/event_item.html"%}
- {% endwith %}
+ {% for event in users_events %}
+
+ {% include "events/parts/event_item.html"%}
+
{% endfor %}
diff --git a/fiesta/apps/events/templates/events/parts/kick_participant_button.html b/fiesta/apps/events/templates/events/parts/kick_participant_button.html
new file mode 100644
index 00000000..ee05ae5d
--- /dev/null
+++ b/fiesta/apps/events/templates/events/parts/kick_participant_button.html
@@ -0,0 +1,9 @@
+{% load i18n %}
+
+
+{% translate "Kick" %}
+
\ No newline at end of file
diff --git a/fiesta/apps/events/templatetags/event_tags.py b/fiesta/apps/events/templatetags/event_tags.py
index cfb9992f..770fd3d2 100644
--- a/fiesta/apps/events/templatetags/event_tags.py
+++ b/fiesta/apps/events/templatetags/event_tags.py
@@ -18,6 +18,7 @@ def show_participants(context, event: Event):
return event.participants.filter(state='confirmed')
return None
+
@register.simple_tag(takes_context=True)
def get_price_variants(context, event: Event):
request: HttpRequest = context["request"]
@@ -29,11 +30,11 @@ def get_price_variants(context, event: Event):
@register.simple_tag(takes_context=True)
def get_event_fullness(context, event: Event):
- if event.participants.all().count() <= event.capacity:
+ if event.event_participants.all().count() <= event.capacity:
return 0
- elif event.participants.all().count() < event.capacity & event.participants.all().count() > event.capacity/2:
+ elif event.event_participants.all().count() < event.capacity & event.participants.all().count() > event.capacity/2:
return 1
- elif event.participants.all().count() >= event.capacity:
+ elif event.event_participants.all().count() >= event.capacity:
return 2
@register.simple_tag(takes_context=True)
@@ -54,9 +55,10 @@ def is_participant(context, event: Event) -> bool:
@register.simple_tag(takes_context=True)
def can_edit(context, event: Event) -> bool:
request: HttpRequest = context["request"]
- return is_moc(context, event) or event.author == request.membership.user or request.membership.user.has_perm("events.change_event")
+ return is_moc(context, event) or event.author == request.membership.user or request.membership.is_privileged or request.membership.user.has_perm('events.change_event')
@register.simple_tag(takes_context=True)
def can_see_participants(context, event: Event) -> bool:
request: HttpRequest = context["request"]
- return is_moc(context, event) or event.author == request.membership.user or request.membership.user.has_perm("events.change_event")
\ No newline at end of file
+ return is_moc(context, event) or event.author == request.membership.user or request.membership.is_privileged or request.membership.user.has_perm('events.change_event')
+
diff --git a/fiesta/apps/events/urls.py b/fiesta/apps/events/urls.py
index f5d7db03..a570acae 100644
--- a/fiesta/apps/events/urls.py
+++ b/fiesta/apps/events/urls.py
@@ -3,7 +3,7 @@
from django.urls import path
from .views import EventsIndexView
-from .views.event import AddEventView, EventDetailView, ParticipantsView, UpdateEventView, EventParticipantRegister
+from .views.event import AddEventView, EventDetailView, ParticipantsView, UpdateEventView, EventParticipantRegister, DeleteEventView, EventParticipantKick
from .views.organizer import AddOrganizerView, UpdateOrganizerRole, DeleteOrganizerView
from .views.price import AddPriceView, UpdatePriceView, DeletePriceView
from .views.place import PlaceView, AddPlaceView, UpdatePlaceView, DeletePlaceView
@@ -15,8 +15,9 @@
urlpatterns = [
path('', EventsIndexView.as_view(), name="index"),
path('add-event', AddEventView.as_view(), name="add-event"),
- path('event-update/', UpdateEventView.as_view(), name="event-update"),
+ path('event-detail/update/', UpdateEventView.as_view(), name="event-update"),
path('event-detail/', EventDetailView.as_view(), name="event-detail"),
+ path('event-detail/delete/', DeleteEventView.as_view(), name="event-delete"),
path("event-detail//participants", ParticipantsView.as_view(), name="participants"), # event-detail//
path("event-detail//organizers/", UpdateOrganizerRole.as_view(), name="role-change"), # event-detail//
path("event-detail//organizers/delete/", DeleteOrganizerView.as_view(), name="organizer-delete"), # event-detail//
@@ -30,4 +31,5 @@
path("place/update/", UpdatePlaceView.as_view(), name="place-update"),
path("place/delete/", DeletePlaceView.as_view(), name="place-delete"),
path("event-detail//register", EventParticipantRegister.as_view(), name="event-register"),
+ path("event-detail//kick/", EventParticipantKick.as_view(), name="event-kick")
]
diff --git a/fiesta/apps/events/views/event.py b/fiesta/apps/events/views/event.py
index bfa9d776..77477da3 100644
--- a/fiesta/apps/events/views/event.py
+++ b/fiesta/apps/events/views/event.py
@@ -14,14 +14,14 @@
import django_filters
from django.contrib.postgres.search import SearchVector
from django.forms import TextInput
-from django.views.generic import CreateView, DetailView, UpdateView, View
+from django.views.generic import CreateView, DetailView, UpdateView, DeleteView, View
import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from django.urls import reverse
from django_filters import CharFilter, ChoiceFilter
-from ..models import Participant, Organizer
+from ..models import Participant, Organizer, PriceVariant
from ..models.event import Event
from apps.utils.views import AjaxViewMixin
from apps.fiestaforms.views.htmx import HtmxFormViewMixin
@@ -38,6 +38,7 @@
from ...utils.breadcrumbs import with_breadcrumb, with_plugin_home_breadcrumb, with_object_breadcrumb
from allauth.account.utils import get_next_redirect_url
from django.contrib.auth import REDIRECT_FIELD_NAME
+import datetime
@@ -88,7 +89,7 @@ class UpdateEventView(
form_class = AddEventForm
template_name = "fiestaforms/pages/card_page_for_ajax_form.html"
- ajax_template_name = "events/templates/parts/update_event_form.html"
+ ajax_template_name = "events/parts/update_event_form.html"
success_message = _("Event updated")
@@ -99,6 +100,7 @@ def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpRespo
def get_initial(self):
return dict(
section=self.request.in_space_of_section,
+ author=self.event.author
)
def get_object(self, queryset=None):
@@ -117,7 +119,20 @@ def get_context_data(self, **kwargs):
def get_success_url(self):
return reverse("events:event-detail", args=[self.object.id])
+class DeleteEventView(
+ EnsurePrivilegedUserViewMixin,
+ EnsureInSectionSpaceViewMixin,
+ DeleteView,
+ HtmxFormViewMixin,
+ AjaxViewMixin,
+ SuccessMessageMixin):
+
+ def get_object(self, queryset=None) -> Event:
+ return get_object_or_404(Event, pk=self.kwargs.get("pk"))
+ def get_success_url(self):
+ return reverse("events:index")
+
@with_plugin_home_breadcrumb
@with_breadcrumb(_("Detail"))
class EventDetailView(
@@ -163,7 +178,14 @@ def filter_search(self, queryset, name, value):
return queryset.annotate(search=SearchVector("user__last_name", "user__first_name", "state")).filter(
search=value
)
+
+class EventKickButtonColumn(tables.TemplateColumn):
+ def __init__(self, event, *args, **kwargs):
+ self.event = event
+ super().__init__(*args, **kwargs)
+ def render(self, record, *args, **kwargs):
+ return super().render(record, extra_context={'event': self.event}, *args, **kwargs)
class EventParticipantsTable(tables.Table):
created = tables.DateTimeColumn(
@@ -182,9 +204,9 @@ class EventParticipantsTable(tables.Table):
accessor="event.title",
attrs={"th": {"class": "text-center"}},
)
- price__name = tables.Column(
+ price__amount = tables.Column(
verbose_name=_("Price"),
- accessor="price.name",
+ accessor="price.amount",
attrs={"th": {"class": "text-center"}},
)
state = tables.Column(
@@ -193,6 +215,11 @@ class EventParticipantsTable(tables.Table):
order_by="state",
attrs={"th": {"class": "text-center"}},
)
+ kick_button = EventKickButtonColumn(
+ event=None,
+ template_name="events/parts/kick_participant_button.html",
+ attrs={"th": {"class": "text-center"}},
+ )
class Meta:
model = Participant
@@ -202,8 +229,9 @@ class Meta:
sequence = (
"user__full_name",
"event__title",
- "price__name",
- "state"
+ "price__amount",
+ "state",
+ "kick_button"
)
empty_text = _("There are no participants")
@@ -213,6 +241,11 @@ def render_created(self, value):
def render_price__name(self, value):
return str(value)
+
+ def __init__(self, *args, **kwargs):
+ event = kwargs.pop('event', None)
+ super().__init__(*args, **kwargs)
+ self.columns['kick_button'].event = event
@with_plugin_home_breadcrumb
@@ -232,7 +265,17 @@ class ParticipantsView(
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
self.event = get_object_or_404(Event, pk=self.kwargs.get("pk"))
return super().dispatch(request, *args, **kwargs)
-
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context ['event'] = self.event
+ return context
+
+ def get_table_kwargs(self):
+ kwargs = super().get_table_kwargs()
+ kwargs['event'] = self.event
+ return kwargs
+
def get_queryset(self):
return self.request.in_space_of_section.events.get(id=self.event.pk).participants.filter(
state__in=(
@@ -245,14 +288,49 @@ def get_queryset(self):
class EventParticipantRegister(
EnsureInSectionSpaceViewMixin,
- CreateView):
-
- model = Participant
+ View):
- def form_valid(self, form: BaseModelForm) -> HttpResponse:
+ model = Participant
+
+ def dispatch(self, request, *args, **kwargs):
+ self.event = get_object_or_404(Event, pk=self.kwargs.get("pk"))
+ return super().dispatch(request, *args, **kwargs)
+
+ def choose_price(self):
+ if PriceVariant.objects.filter(event=self.event, type=EventPriceVariantType.FREE).exists():
+ return PriceVariant.objects.filter(event=self.event, type=EventPriceVariantType.FREE).get()
+ elif self.request.user.is_esn_card_holder & PriceVariant.objects.filter(event=self.event, type=EventPriceVariantType.WITH_ESN_CARD).exists():
+ return PriceVariant.objects.filter(event=self.event, type=EventPriceVariantType.WITH_ESN_CARD).get()
+ elif PriceVariant.objects.filter(event=self.event, type=EventPriceVariantType.STANDARD).exists():
+ return PriceVariant.objects.filter(event=self.event, type=EventPriceVariantType.STANDARD).get()
+ return None
+
+ def post(self, request, *args, **kwargs):
+ if Participant.objects.filter(user=self.request.user, event=self.event).exists():
+ return HttpResponse("You are already registered for this event.")
+ if self.choose_price() is None:
+ return HttpResponse("You can't register for this event yet.")
Participant.objects.create(
+ created=datetime.datetime.now(),
user=self.request.user,
-
+ event=self.event,
+ price=self.choose_price()
)
- return super().form_valid(form)
+ return HttpResponse("Sucsessfully registered for this event.")
+
+class EventParticipantKick(
+ EnsurePrivilegedUserViewMixin,
+ EnsureInSectionSpaceViewMixin,
+ DeleteView):
+
+ model = Participant
+
+ def get_object(self, queryset= None):
+ return get_object_or_404(Participant, pk=self.kwargs.get("pkp"))
+
+ def get_success_url(self) -> str:
+ return reverse("events:participants", args=[self.kwargs.get("pk")])
+
+
+
\ No newline at end of file
diff --git a/fiesta/apps/events/views/index.py b/fiesta/apps/events/views/index.py
index 150df070..813701cb 100644
--- a/fiesta/apps/events/views/index.py
+++ b/fiesta/apps/events/views/index.py
@@ -14,10 +14,10 @@ class EventsIndexView(EnsureInSectionSpaceViewMixin, ListView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- # Get the user's confirmed participants
- participations = self.request.user.participants.filter(state=Participant.State.CONFIRMED)
+ participants = Participant.objects.filter(user=self.request.membership.user)
- # Add the confirmed participants to the context
- context['participations'] = participations
+ events = [participant.event for participant in participants if participant.event]
+
+ context['users_events'] = events
return context
\ No newline at end of file