diff --git a/aleksis/apps/paweljong/forms.py b/aleksis/apps/paweljong/forms.py index 0a24683b1a136fd672bd76a4ff86703123a807f6..c864f82da15981bb728a2a7ee16344ba70a950c5 100644 --- a/aleksis/apps/paweljong/forms.py +++ b/aleksis/apps/paweljong/forms.py @@ -489,3 +489,15 @@ class RegistrationStatesForm(forms.ModelForm): class Meta: model = RegistrationState exclude = [] + + +class PersonGroupFormPerson(forms.Form): + + layout = Layout("username") + + username = forms.CharField( + required=True, + label=_("Person"), + widget=forms.TextInput(attrs={"autofocus": "", "autocomplete": "off"}), + help_text=_("Please enter a username."), + ) diff --git a/aleksis/apps/paweljong/menus.py b/aleksis/apps/paweljong/menus.py index bc3e904e3dea19ae8f627260258f3eedfc58728b..2d9cc4ffc0f1ea11c3a3209d614bc551cfd89cae 100644 --- a/aleksis/apps/paweljong/menus.py +++ b/aleksis/apps/paweljong/menus.py @@ -88,17 +88,6 @@ MENUS = { ) ], }, - { - "name": _("Registrations"), - "url": "registrations", - "icon": "how_to_reg", - "validators": [ - ( - "aleksis.core.util.predicates.permission_validator", - "paweljong.view_registrations_rule", - ) - ], - }, ], }, ], diff --git a/aleksis/apps/paweljong/static/css/paweljong.css b/aleksis/apps/paweljong/static/css/paweljong.css index 99c7a34797ca3d85042364cdefd5df7ef981ead7..bbbd62ba963d75468de412ae06d4ca0a82c251fa 100644 --- a/aleksis/apps/paweljong/static/css/paweljong.css +++ b/aleksis/apps/paweljong/static/css/paweljong.css @@ -50,3 +50,12 @@ time.icon span { padding-top: 0.8em; color: #0606FA; } + +#owners-chip { + width: 16px; + height: 16px; +} + +#event-detail-table { + table-layout: fixed; +} diff --git a/aleksis/apps/paweljong/tables.py b/aleksis/apps/paweljong/tables.py index 4876f8d46a4aa816e98b3ce2ca1abae4b63fc8d1..f380dc94318e707a320407873fd7ccc54c40b59e 100644 --- a/aleksis/apps/paweljong/tables.py +++ b/aleksis/apps/paweljong/tables.py @@ -20,9 +20,17 @@ class ManageEventsTable(tables.Table): verbose_name=_("Edit"), text=_("Edit"), ) - view = tables.LinkColumn( + + view_public = tables.LinkColumn( "event_by_name", args=[A("slug")], + verbose_name=_("Public page"), + text=_("Public page"), + ) + + view = tables.LinkColumn( + "event_detail_by_name", + args=[A("slug")], verbose_name=_("View"), text=_("View"), ) @@ -127,3 +135,27 @@ class RegistrationStatesTable(tables.Table): def render_name(self, value, record): context = dict(state=record) return render_to_string("paweljong/registration_state/chip.html", context) + + +class ChildGroupsTable(tables.Table): + """Table to list groups.""" + + class Meta: + attrs = {"class": "highlight"} + + name = tables.LinkColumn("group_by_id", args=[A("id")]) + short_name = tables.LinkColumn("group_by_id", args=[A("id")]) + + add_persons = tables.LinkColumn( + "add_persons_to_group", + args=[A("id")], + verbose_name=_("Add persons"), + text=_("Add persons"), + ) + + +class AdditionalFieldsTable(tables.Table): + class Meta: + attrs = {"class": "highlight"} + + title = tables.LinkColumn("edit_additional_field_by_id", args=[A("id")]) diff --git a/aleksis/apps/paweljong/templates/paweljong/event/detail.html b/aleksis/apps/paweljong/templates/paweljong/event/detail.html new file mode 100644 index 0000000000000000000000000000000000000000..1adf1eb19146dbd5e621ee7b7aadb28936c8a262 --- /dev/null +++ b/aleksis/apps/paweljong/templates/paweljong/event/detail.html @@ -0,0 +1,94 @@ +{# -*- engine:django -*- #} + +{% extends "core/base.html" %} + +{% load i18n static rules material_form coerce html_helpers %} +{% load render_table from django_tables2 %} + +{% block browser_title %}{{ event }}{% endblock %} + +{% block extra_head %} + <link rel="stylesheet" href="{% static 'css/paweljong.css' %}"/> +{% endblock %} + +{% block content %} + <h4>{{ event }}</h4> + + {% has_perm 'paweljong.manage_event' user event as can_manage_event %} + + {% if can_manage_event %} + <p> + {% if can_manage_event %} + <a href="{% url 'edit_event_by_slug' event.slug %}" class="btn waves-effect waves-light"> + <i class="material-icons left iconify" data-icon="mdi:edit"></i> + {% trans "Edit" %} + </a> + {% endif %} + + </p> + {% endif %} + + <div class="card"> + <div class="card-content"> + <p>{{ event.description }}</p> + <table id="event-detail-table"> + <tr> + <td><i class="material-icons small">event</i></td> + <td>{{ event.date_event }}</td> + <td><i class="material-icons small">location_on</i></td> + <td>{{ event.place }}</td> + </tr> + <tr> + <td><i class="material-icons small">edit_calendar</i></td> + <td colspan="2">{% trans "Registration open until" %}:</td> + <td>{{ event.date_registration }}</td> + </tr> + <tr> + <td><i class="material-icons small">money</i></td> + <td colspan="2">{% trans "Participation fee (all inclusive)" %}</td> + <td>{{ event.cost }}</td> + </tr> + <tr> + <td><i class="material-icons small">group</i></td> + <td colspan="2">{{ event.linked_group.members.count }}</td> + <td>{% trans "of" %} {{ event.max_participants }}</td> + </tr> + <tr> + <td><i class="material-icons iconify" data-icon="vscode-icons:file-type-light-codeowners"></i></td> + <td colspan="2">{% trans "Owners" %}</td> + <td> + {% for owner in event.owners_persons.all %} + <div class="chip"> + <img src="{{ owner.avatar_url }}" alt="{{ owner }}" id="owners-chip"> + <a href="{{ owner.get_absolute_url }}">{{ owner }}</a> + </div> + {% endfor %} + </td> + </tr> + <tr> + <td>{% trans "Description" %}</td> + <td colspan="3"> + {{ event.information|add_class_to_el:"ul, browser-default"|safe }} + </td> + </tr> + </table> + </div> + </div> + </div> + </div> + + <div class="row"> + <div class="col s3"> + <h5>{% blocktrans %}Additional fields{% endblocktrans %}</h5> + {% render_table additional_fields_table %} + </div> + <div class="col s9"> + <h5>{% blocktrans %}Child groups{% endblocktrans%}</h5> + {% render_table child_groups_table %} + </div> + </div> + + <h5>{% blocktrans %}Registrations{% endblocktrans %}</h5> + {% render_table registrations_table %} + +{% endblock %} diff --git a/aleksis/apps/paweljong/templates/paweljong/event/persons_group.html b/aleksis/apps/paweljong/templates/paweljong/event/persons_group.html new file mode 100644 index 0000000000000000000000000000000000000000..5819aa8382735771d5962359afed1bf94d7841c6 --- /dev/null +++ b/aleksis/apps/paweljong/templates/paweljong/event/persons_group.html @@ -0,0 +1,20 @@ +{% extends "core/base.html" %} +{% load material_form i18n any_js %} + +{% block page_title %}{% blocktrans %}Add person to group{% endblocktrans %}{% endblock %} +{% block browser_title %}{% blocktrans %}Add person to group{% endblocktrans %}{% endblock %} + +{% block extra_head %} + {{ form.media.css }} +{% endblock %} + +{% block content %} + + <form method="post"> + {% csrf_token %} + {% form form=form %}{% form %} + {% include "core/partials/save_button.html" %} + </form> + {{ form.media.js }} + +{% endblock %} diff --git a/aleksis/apps/paweljong/templates/paweljong/event_registration/list.html b/aleksis/apps/paweljong/templates/paweljong/event_registration/list.html deleted file mode 100644 index cb9184dcd16821a049b0eef1610ed589aca45f2b..0000000000000000000000000000000000000000 --- a/aleksis/apps/paweljong/templates/paweljong/event_registration/list.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "core/base.html" %} -{% load material_form i18n %} - -{% load render_table from django_tables2 %} - -{% block page_title %}{% blocktrans %}Registrations{% endblocktrans %}{% endblock %} -{% block browser_title %}{% blocktrans %}Registrations{% endblocktrans %}{% endblock %} - -{% block content %} - - <h5>{% trans "Filter registrations" %}</h5> - <form method="get"> - {% form form=registrations_filter.form %}{% endform %} - {% trans "Search" as caption %} - {% include "core/partials/save_button.html" with caption=caption icon="search" %} - <button type="reset" class="btn red waves-effect waves-light"> - <i class="material-icons left">clear</i> - {% trans "Clear" %} - </button> - </form> - - <h5>{% trans "Selected registrations" %}</h5> - {% render_table registrations_table %} - -{% endblock %} diff --git a/aleksis/apps/paweljong/urls.py b/aleksis/apps/paweljong/urls.py index d32f21f12cab2bf2939f238d3f20dba273a09046..d046e0506d6be8905b11e3b530bf83bf01b15e70 100644 --- a/aleksis/apps/paweljong/urls.py +++ b/aleksis/apps/paweljong/urls.py @@ -42,7 +42,13 @@ urlpatterns = [ views.RegisterEventWizardView.as_view(register_forms, condition_dict=condition_dict), name="register_event_by_slug", ), + path( + "group_persons/<int:pk>/add", + views.PersonGroupView.as_view(), + name="add_persons_to_group", + ), path("event/<slug:slug>", views.EventFullView.as_view(), name="event_by_name"), + path("event/<slug:slug>/detail", views.EventDetailView.as_view(), name="event_detail_by_name"), path( "event/<slug:slug>/start", views.RegisterEventStart.as_view(), @@ -71,7 +77,6 @@ urlpatterns = [ path("vouchers/<int:pk>/print", views.print_voucher, name="print_voucher_by_pk"), path("vouchers/", views.vouchers, name="vouchers"), path("event/lists/generate", views.generate_lists, name="generate_lists"), - path("event/registrations/list", views.registrations, name="registrations"), path( "event/registrations/<int:pk>/retract", views.RetractRegistration.as_view(), diff --git a/aleksis/apps/paweljong/views.py b/aleksis/apps/paweljong/views.py index c587200ec7f43cb03a1005a81d87bab1781c5e31..79de5e25d048c5ff8084829778c8048ac6d86f29 100644 --- a/aleksis/apps/paweljong/views.py +++ b/aleksis/apps/paweljong/views.py @@ -24,12 +24,11 @@ from templated_email import send_templated_mail from aleksis.apps.postbuero.models import MailAddress from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView -from aleksis.core.models import Activity, Person +from aleksis.core.models import Activity, Group, Person from aleksis.core.util import messages from aleksis.core.util.core_helpers import get_site_preferences, objectgetter_optional -from aleksis.core.util.predicates import queryset_rules_filter -from .filters import EventFilter, EventRegistrationFilter, VoucherFilter +from .filters import EventFilter, VoucherFilter from .forms import ( EditEventForm, EditEventRegistrationForm, @@ -37,11 +36,14 @@ from .forms import ( EditTermForm, EditVoucherForm, GenerateListForm, + PersonGroupFormPerson, RegistrationNotificationForm, RegistrationStatesForm, ) from .models import Event, EventRegistration, InfoMailing, RegistrationState, Terms, Voucher from .tables import ( + AdditionalFieldsTable, + ChildGroupsTable, EventRegistrationsTable, InfoMailingsTable, ManageEventsTable, @@ -135,28 +137,6 @@ def generate_lists(request: HttpRequest) -> HttpResponse: return render(request, "paweljong/print/manage.html", context) -@permission_required("paweljong.view_registrations_rule") -def registrations(request: HttpRequest) -> HttpResponse: - """List view listing all registrations.""" - context = {} - - # Get all registrations - registrations = queryset_rules_filter( - request.user, EventRegistration.objects.all(), "paweljong.view_registration_rule" - ) - - # Get filter - registrations_filter = EventRegistrationFilter(request.GET, queryset=registrations) - context["registrations_filter"] = registrations_filter - - # Build table - registrations_table = EventRegistrationsTable(registrations_filter.qs) - RequestConfig(request).configure(registrations_table) - context["registrations_table"] = registrations_table - - return render(request, "paweljong/event_registration/list.html", context) - - @method_decorator(never_cache, name="dispatch") class EventRegistrationCreateView(PermissionRequiredMixin, AdvancedCreateView): """Create view for event registrations.""" @@ -912,3 +892,63 @@ class RetractRegistration(PermissionRequiredMixin, View): messages.success(self.request, _("Registration successfully retracted.")) return redirect("registrations") + + +class EventDetailView(PermissionRequiredMixin, DetailView): + """Detail view for an event instance.""" + + context_object_name = "event" + permission_required = "paweljong.view_event_rule" + template_name = "paweljong/event/detail.html" + model = Event + slug_field = "slug" + + def get_queryset(self): + return Event.objects.all() + + def get_context_data(self, **kwargs): + + context = super().get_context_data(**kwargs) + + # Registrations table + registrations = EventRegistration.objects.filter(event=self.object) + registrations_table = EventRegistrationsTable(registrations) + RequestConfig(self.request).configure(registrations_table) + context["registrations_table"] = registrations_table + + # Child groups table + child_groups = self.object.linked_group.child_groups.all() + child_groups_table = ChildGroupsTable(child_groups) + RequestConfig(self.request).configure(child_groups_table) + context["child_groups_table"] = child_groups_table + + # Additional fields table + additional_fields = self.object.linked_group.additional_fields.all() + additional_fields_table = AdditionalFieldsTable(additional_fields) + RequestConfig(self.request).configure(additional_fields_table) + context["additional_fields_table"] = additional_fields_table + + return context + + +class PersonGroupView(PermissionRequiredMixin, FormView): + + template_name = "paweljong/event/persons_group.html" + permission_required = "paweljong.add_persons_to_group_rule" + form_class = PersonGroupFormPerson + + def form_valid(self, form): + + group = Group.objects.get(id=self.kwargs["pk"]) + + try: + person = Person.objects.get(user__username=form.cleaned_data["username"]) + group.members.add(person) + messages.success(self.request, _(f"Person {person} added successfully!")) + except Person.DoesNotExist: + messages.error(self.request, _("Person does not exist!")) + + return super().form_valid(self) + + def get_success_url(self): + return reverse("add_persons_to_group", kwargs={"pk": self.kwargs["pk"]})