diff --git a/aleksis/core/static/public/style.scss b/aleksis/core/static/public/style.scss index 26ac19ca5d715923f279e9eb07b8e172110aa4bf..889b790f98cb0be7ed2de37a12a884acff5c4ca9 100644 --- a/aleksis/core/static/public/style.scss +++ b/aleksis/core/static/public/style.scss @@ -23,6 +23,9 @@ rect#background { .waves-effect.waves-primary .waves-ripple { background-color: lighten($primary-color, 5%); } +.waves-effect.waves-secondary .waves-ripple { + background-color: lighten($secondary-color, 5%); +} .success { @extend .light-green, .lighten-3 @@ -974,3 +977,16 @@ svg.iconify { text-align: center; } } + +.btn-small-line-height { + line-height: $button-small-height; +} + +.btn-smaller-padding { + padding: 0 8px; +} + +p.ical-description { + margin: 0; + font-weight: 300; +} diff --git a/aleksis/core/templates/core/ical/ical_create.html b/aleksis/core/templates/core/ical/ical_create.html new file mode 100644 index 0000000000000000000000000000000000000000..64ff80083ebab3e61cd108d46ee1bff158cdd236 --- /dev/null +++ b/aleksis/core/templates/core/ical/ical_create.html @@ -0,0 +1,20 @@ +{% extends 'core/base.html' %} +{% load i18n material_form %} + +{% block page_title %}{% blocktrans %}Create iCal URL{% endblocktrans %}{% endblock page_title %} +{% block browser_title %}{% blocktrans %}Create iCal URL{% endblocktrans %}{% endblock browser_title %} + +{% block content %} + <form method="post"> + {% csrf_token %} + + {% form form=form %}{% endform %} + + {% include "core/partials/save_button.html" %} + <a href="{% url "ical_feed_list" %}" class="btn red"> + <i class="material-icons iconify left" data-icon="mdi:close"></i> + {% blocktrans %}Cancel{% endblocktrans %} + </a> + </form> + +{% endblock content %} diff --git a/aleksis/core/templates/core/ical/ical_edit.html b/aleksis/core/templates/core/ical/ical_edit.html new file mode 100644 index 0000000000000000000000000000000000000000..cd46c475531bc1154f5f36c16ae1476b79e73137 --- /dev/null +++ b/aleksis/core/templates/core/ical/ical_edit.html @@ -0,0 +1,20 @@ +{% extends 'core/base.html' %} +{% load i18n material_form %} + +{% block page_title %}{% blocktrans %}Edit iCal URL {{ object }}{% endblocktrans %}{% endblock page_title %} +{% block browser_title %}{% blocktrans %}Edit iCal URL {{ object }}{% endblocktrans %}{% endblock browser_title %} + +{% block content %} + <form method="post"> + {% csrf_token %} + + {% form form=form %}{% endform %} + + {% include "core/partials/save_button.html" %} + <a href="{% url "ical_feed_list" %}" class="btn red"> + <i class="material-icons iconify left" data-icon="mdi:close"></i> + {% blocktrans %}Cancel{% endblocktrans %} + </a> + </form> + +{% endblock content %} diff --git a/aleksis/core/templates/core/ical/ical_list.html b/aleksis/core/templates/core/ical/ical_list.html new file mode 100644 index 0000000000000000000000000000000000000000..abd3d9b25ea0ba2f85aac6281f73ede48f4c1cb5 --- /dev/null +++ b/aleksis/core/templates/core/ical/ical_list.html @@ -0,0 +1,39 @@ +{% extends 'core/base.html' %} +{% load i18n msg_box static %} + +{% block page_title %}{% trans "ICal Feeds" %}{% endblock page_title %} +{% block browser_title %}{% trans "ICal Feeds" %}{% endblock browser_title %} + +{% block content %} + {% trans "These are URLs for different Calendar Feeds in the iCal (.ics) format. You can create as many as you want and import them in your calendar software." as msg %} + {% msg_box msg=msg status="info" %} + <a href="{% url "ical_feed_create" %}" class="btn green"> + <i class="material-icons iconify left" data-icon="mdi:add"></i> + {% trans "Create iCal URL" %} + </a> + <h2>{% trans "Your iCal URLs" %}</h2> + <div class="collection"> + {% for object in object_list %} + <div class="collection-item"> + <span class="title btn-small-line-height"> + {{ object }} + <a href="{% url "ical_feed_delete" object.pk %}" + class="secondary-content btn-flat btn-small red-text btn-smaller-padding waves-effect waves-red"> + <i class="material-icons iconify" data-icon="mdi:delete-outline"></i> + </a> + <a href="{% url "ical_feed_edit" object.pk %}" + class="secondary-content btn-flat btn-small primary-color-text btn-smaller-padding waves-effect waves-primary"> + <i class="material-icons iconify" data-icon="mdi:pencil-outline"></i> + </a> + <button type="button" data-target="input-{{ forloop.counter0 }}" + class="secondary-content btn-flat btn-small secondary-color-text btn-smaller-padding copy-button waves-effect waves-secondary"> + <i class="material-icons iconify" data-icon="mdi:content-copy"></i> + </button> + </span> + <p class="ical-description">{{ object.ical_feed_object.title }} – {{ object.ical_feed_object.description }}</p> + <input type="url" readonly value="https://{{ request.site }}{{ object.get_absolute_url }}" + id="input-{{ forloop.counter0 }}"> + </div> + {% endfor %} + </div> +{% endblock content %} diff --git a/aleksis/core/urls.py b/aleksis/core/urls.py index f39808e0ef0ed22e9c3b94e91fc5c1161beccdb9..58a8c29d4b60b448b6fd05a5f7f83c732565d159 100644 --- a/aleksis/core/urls.py +++ b/aleksis/core/urls.py @@ -320,6 +320,13 @@ urlpatterns = [ name="assign_permission", ), path("pdfs/<int:pk>/", views.RedirectToPDFFile.as_view(), name="redirect_to_pdf_file"), + + path("ical/", views.ICalFeedListView.as_view(), name="ical_feed_list"), + path("ical/create/", views.ICalFeedCreateView.as_view(), name="ical_feed_create"), + path("ical/<int:pk>/edit/", views.ICalFeedEditView.as_view(), name="ical_feed_edit"), + path("ical/<int:pk>/delete/", views.ICalFeedDeleteView.as_view(), name="ical_feed_delete"), + path("ical/<slug:slug>.ics", views.ICalFeedView.as_view(), name="ical_feed"), + path("__icons__/", include("dj_iconify.urls")), ] diff --git a/aleksis/core/views.py b/aleksis/core/views.py index 32e83c3746630ddf96e5c179180dbfb2face50d2..36ef779b84b17af8cccffdf5a1dce614b6837f1b 100644 --- a/aleksis/core/views.py +++ b/aleksis/core/views.py @@ -105,6 +105,7 @@ from .models import ( PersonInvitation, SchoolTerm, TaskUserAssignment, + PersonalICalUrl, ) from .registries import ( group_preferences_registry, @@ -1564,3 +1565,67 @@ class CustomAuthorizationView(AuthorizationView): context = super().get_context_data(**kwargs) context["no_menu"] = True return context + + +class ICalFeedView(DetailView): + model = PersonalICalUrl + slug_field = "uuid" + + def get(self, request, *args, **kwargs): + obj: PersonalICalUrl = self.get_object() + if obj.ical_feed_object: + kwargs["person"] = obj.person + return obj.ical_feed_object()(request, *args, **kwargs) + else: + return HttpResponse(status=204) + + +class ICalFeedListView(ListView): + model = PersonalICalUrl + template_name = "core/ical/ical_list.html" + + def get_queryset(self): + return PersonalICalUrl.objects.filter(person=self.request.user.person) + + +class ICalFeedEditView(AdvancedEditView): + model = PersonalICalUrl + template_name = "core/ical/ical_edit.html" + success_url = reverse_lazy("ical_feed_list") + success_message = _("ICal feed updated successfully") + + fields = ["name", "ical_feed"] + + def get_queryset(self): + return PersonalICalUrl.objects.filter(person=self.request.user.person) + + def form_valid(self, form): + obj = form.save(commit=False) + obj.person = self.request.user.person + obj.save() + return super().form_valid(form) + + +class ICalFeedDeleteView(AdvancedDeleteView): + model = PersonalICalUrl + template_name = "core/pages/delete.html" + success_url = reverse_lazy("ical_feed_list") + success_message = _("ICal feed deleted successfully") + + def get_queryset(self): + return PersonalICalUrl.objects.filter(person=self.request.user.person) + + +class ICalFeedCreateView(AdvancedCreateView): + model = PersonalICalUrl + template_name = "core/ical/ical_create.html" + success_url = reverse_lazy("ical_feed_list") + success_message = _("ICal feed created successfully") + + fields = ["name", "ical_feed"] + + def form_valid(self, form): + obj = form.save(commit=False) + obj.person = self.request.user.person + obj.save() + return super().form_valid(form)