Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 116 additions & 1 deletion course/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@
from django.core.exceptions import (
ObjectDoesNotExist,
PermissionDenied,
SuspiciousOperation,
ValidationError,
)
from django.db import transaction
from django.shortcuts import get_object_or_404, redirect
from django.utils.safestring import mark_safe
from django.utils.translation import get_language, gettext_lazy as _, pgettext_lazy

Expand All @@ -44,7 +46,13 @@
from course.models import Event
from course.utils import CoursePageContext, course_view, render_course_page
from course.validation import ValidationContext
from relate.utils import HTML5DateTimeInput, StyledForm, as_local_time, string_concat
from relate.utils import (
HTML5DateTimeInput,
StyledForm,
StyledModelForm,
as_local_time,
string_concat,
)


class ListTextWidget(forms.TextInput):
Expand Down Expand Up @@ -348,6 +356,113 @@ def renumber_events(pctx: CoursePageContext):
# }}}


# {{{ single-event CRUD

class SingleEventForm(StyledModelForm):
def __init__(self, add_new: bool, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)

self.helper.add_input(
Submit("submit", _("Add event") if add_new else _("Update event")))

class Meta:
model = Event
exclude = ("course",)
widgets = {
"time": HTML5DateTimeInput(),
"end_time": HTML5DateTimeInput(),
}


@login_required
@course_view
def list_events(pctx: CoursePageContext):
if not pctx.has_permission(PPerm.edit_events):
raise PermissionDenied(_("may not edit events"))

events = (Event.objects
.filter(course=pctx.course)
.order_by("kind", "ordinal", "time"))

return render_course_page(pctx, "course/events-list.html", {
"events": events,
})


@login_required
@course_view
def edit_event(pctx: CoursePageContext, event_id: int) -> object:
if not pctx.has_permission(PPerm.edit_events):
raise PermissionDenied(_("may not edit events"))

request = pctx.request
num_event_id = int(event_id)

if num_event_id == -1:
event = Event(course=pctx.course)
add_new = True
else:
event = get_object_or_404(Event, id=num_event_id)
add_new = False

if not add_new and event.course.id != pctx.course.id:
raise SuspiciousOperation(
"may not edit event in a different course")

if request.method == "POST":
form = SingleEventForm(add_new, request.POST, instance=event)
if form.is_valid():
evt = form.save(commit=False)
evt.course = pctx.course
evt.save()
return redirect("relate-list_events", pctx.course.identifier)
else:
form = SingleEventForm(add_new, instance=event)

return render_course_page(pctx, "course/generic-course-form.html", {
"form": form,
"form_description": _("Add event") if add_new else _("Edit event"),
})


class DeleteEventForm(StyledForm):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.helper.add_input(Submit("submit", _("Yes, delete")))


@login_required
@course_view
def delete_event(pctx: CoursePageContext, event_id: int) -> object:
if not pctx.has_permission(PPerm.edit_events):
raise PermissionDenied(_("may not edit events"))

request = pctx.request
event = get_object_or_404(Event, id=int(event_id))

if event.course.id != pctx.course.id:
raise SuspiciousOperation(
"may not delete event in a different course")

if request.method == "POST":
form = DeleteEventForm(request.POST)
if form.is_valid():
event.delete()
messages.add_message(request, messages.SUCCESS, _("Event deleted."))
return redirect("relate-list_events", pctx.course.identifier)
else:
form = DeleteEventForm()

return render_course_page(pctx, "course/generic-course-form.html", {
"form": form,
"form_description": _("Delete event"),
"form_text":
_("Sure you want to delete '%(event)s'?") % {"event": event},
})

# }}}


# {{{ calendar

@dataclass(frozen=True)
Expand Down
59 changes: 59 additions & 0 deletions course/templates/course/events-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{% extends "course/course-base.html" %}

{% load i18n %}

{% block title %}
{% trans "Events" %} - {{ relate_site_name }}
{% endblock %}

{% block content %}
<h1>{% trans "Events" %}</h1>

<a href="{% url "relate-edit_event" course.identifier -1 %}" class="btn btn-outline-secondary">{% trans "Add event" %}</a>

<table class="table table-striped">
<thead>
<tr>
<th>{% trans "Kind" %}</th>
<th>{% trans "Ordinal" %}</th>
<th>{% trans "Start time" %}</th>
<th>{% trans "End time" %}</th>
<th>{% trans "All day" %}</th>
<th>{% trans "Shown in calendar" %}</th>
<th>{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for event in events %}
<tr>
<td>{{ event.kind }}</td>
<td>{{ event.ordinal|default:"" }}</td>
<td>{{ event.time }}</td>
<td>{{ event.end_time|default:"" }}</td>
<td>
{% if event.all_day %}
<i class="bi bi-check-square"></i>
{% else %}
<i class="bi bi-square"></i>
{% endif %}
</td>
<td>
{% if event.shown_in_calendar %}
<i class="bi bi-check-square"></i>
{% else %}
<i class="bi bi-square"></i>
{% endif %}
</td>
<td>
<a href="{% url "relate-edit_event" course.identifier event.id %}" class="btn btn-outline-secondary btn-sm">{% trans "Edit" %}</a>
<a href="{% url "relate-delete_event" course.identifier event.id %}" class="btn btn-outline-danger btn-sm">{% trans "Delete" %}</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="7">{% trans "No events." %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
Loading