Skip to content

Commit

Permalink
add shift copy
Browse files Browse the repository at this point in the history
  • Loading branch information
jeriox committed Sep 12, 2024
1 parent b6b38b2 commit aa15014
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 39 deletions.
4 changes: 4 additions & 0 deletions ephios/core/forms/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ class EventCopyForm(forms.Form):
recurrence = RecurrenceField()


class ShiftCopyForm(forms.Form):
recurrence = RecurrenceField(pick_hour=True)


class EventTypeForm(forms.ModelForm):
class Meta:
model = EventType
Expand Down
3 changes: 3 additions & 0 deletions ephios/core/templates/core/fragments/shift_header.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
<li><a class="dropdown-item" href="{% url "core:shift_edit" shift.pk %}"><span
class="fas fa-edit"></span>
{% translate "Edit" %}</a></li>
<li><a class="dropdown-item" href="{% url "core:shift_copy" shift.pk %}"><span
class="fas fa-copy"></span>
{% translate "Copy" %}</a></li>
{% if shift.event.shifts.count > 1 %}
<a class="dropdown-item" href="{% url "core:shift_delete" shift.pk %}"><span
class="fas fa-trash-alt"></span> {% translate "Delete" %}</a>
Expand Down
24 changes: 24 additions & 0 deletions ephios/core/templates/core/shift_copy.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load static %}
{% load i18n %}

{% block title %}
{% translate "Copy shift" %}
{% endblock %}

{% block css %}
{% endblock %}

{% block content %}
<div class="page-header">
<h1>
{% translate "Copy shift" %} "{{ shift.event.title }}" <small>({{ shift.get_datetime_display }})</small>
</h1>
</div>
{{ form.errors }}
<form method="post">
{% csrf_token %}
{{ form.recurrence }}
</form>
{% endblock %}
3 changes: 3 additions & 0 deletions ephios/core/templates/core/shift_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ <h2>
<button type="submit" name="addAnother" class="btn btn-secondary float-end">
<span class="fas fa-plus"></span> {% translate "Add another shift" %}
</button>
<button type="submit" name="copyShift" class="btn btn-secondary float-end me-1">
<span class="fas fa-copy"></span> {% translate "Copy shift" %}
</button>
</div>
</form>
</div>
Expand Down
8 changes: 2 additions & 6 deletions ephios/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
EventNotificationView,
EventUpdateView,
HomeView,
RRuleOccurrenceView,
ShiftCopyView,
)
from ephios.core.views.eventtype import (
EventTypeCreateView,
Expand Down Expand Up @@ -177,12 +177,8 @@
AddPlaceholderParticipantView.as_view(),
name="shift_disposition_add_placeholder",
),
path("shifts/<int:pk>/copy/", ShiftCopyView.as_view(), name="shift_copy"),
path("calendar/<str:calendar_token>/", user_event_feed_view, name="user_event_feed"),
path(
"extra/rruleoccurrence/",
RRuleOccurrenceView.as_view(),
name="rrule_occurrences",
),
path("settings/data/", PersonalDataSettingsView.as_view(), name="settings_personal_data"),
path("settings/calendar/", CalendarSettingsView.as_view(), name="settings_calendar"),
path(
Expand Down
61 changes: 34 additions & 27 deletions ephios/core/views/event.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import json
from calendar import _nextmonth, _prevmonth
from collections import defaultdict
from copy import copy
from datetime import datetime, time, timedelta

from csp.decorators import csp_exempt
from dateutil.rrule import rrulestr
from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import ValidationError
from django.db.models import BooleanField, Case, Count, Max, Min, Prefetch, Q, QuerySet, When
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.utils.datastructures import MultiValueDict
from django.utils.formats import date_format
from django.utils.functional import cached_property
from django.utils.safestring import mark_safe
from django.utils.timezone import get_current_timezone, make_aware
Expand All @@ -36,7 +33,7 @@
from guardian.shortcuts import assign_perm, get_objects_for_user, get_users_with_perms

from ephios.core.calendar import ShiftCalendar
from ephios.core.forms.events import EventCopyForm, EventForm, EventNotificationForm
from ephios.core.forms.events import EventCopyForm, EventForm, EventNotificationForm, ShiftCopyForm
from ephios.core.models import AbstractParticipation, Event, EventType, Shift
from ephios.core.services.notifications.types import (
CustomEventParticipantNotification,
Expand Down Expand Up @@ -547,16 +544,8 @@ def get_success_url(self):
return reverse("core:event_copy", kwargs=dict(pk=self.object.pk))

def form_valid(self, form):
messages.info(
self.request,
[
date_format(obj, format="SHORT_DATE_FORMAT")
for obj in form.cleaned_data["recurrence"]
],
)
return super().form_valid(form)
tz = get_current_timezone()
for date in occurrences:
for date in form.cleaned_data["recurrence"].xafter(timezone.now(), 1000, inc=True):
event = self.get_object()
start_date = event.get_start_time().astimezone(tz).date()
shifts = list(event.shifts.all())
Expand Down Expand Up @@ -618,20 +607,38 @@ def as_view(cls, **initkwargs):
return csp_exempt(super().as_view(**initkwargs))


class RRuleOccurrenceView(CustomPermissionRequiredMixin, View):
permission_required = "core.add_event"
class ShiftCopyView(CustomPermissionRequiredMixin, SingleObjectMixin, FormView):
permission_required = "core.change_event"
model = Shift
template_name = "core/shift_copy.html"
form_class = ShiftCopyForm

def post(self, *args, **kwargs):
try:
recurrence = rrulestr(json.loads(self.request.body)["recurrence_string"])
return HttpResponse(
json.dumps(
list(recurrence.xafter(timezone.now(), count=1000)),
default=lambda obj: date_format(obj, format="SHORT_DATE_FORMAT"),
)
)
except (TypeError, KeyError, ValueError):
return HttpResponse()
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.object = self.get_object()

def get_success_url(self):
return reverse("core:event_detail", kwargs=dict(pk=self.object.event.pk, slug="event"))

def form_valid(self, form):
shift = self.object
duration = shift.end_time - shift.start_time
meeting_offset = shift.start_time - shift.meeting_time
shifts_to_create = []
for dt in form.cleaned_data["recurrence"].xafter(timezone.now(), 1000, inc=True):
shift = copy(shift)
shift.pk = None
shift.meeting_time = dt - meeting_offset
shift.start_time = dt
shift.end_time = dt + duration
shifts_to_create.append(shift)
Shift.objects.bulk_create(shifts_to_create)
messages.success(self.request, _("Shift copied successfully."))
return super().form_valid(form)

@classmethod
def as_view(cls, **initkwargs):
return csp_exempt(super().as_view(**initkwargs))


class HomeView(LoginRequiredMixin, TemplateView):
Expand Down
4 changes: 4 additions & 0 deletions ephios/core/views/shift.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ def post(self, *args, **kwargs):
self.save_plugin_forms()
if "addAnother" in self.request.POST:
return redirect(reverse("core:event_createshift", kwargs={"pk": self.kwargs.get("pk")}))
elif "copyShift" in self.request.POST:
return redirect(reverse("core:shift_copy", kwargs={"pk": shift.pk}))
try:
self.event.activate()
messages.success(
Expand Down Expand Up @@ -232,6 +234,8 @@ def post(self, *args, **kwargs):
return redirect(
reverse("core:event_createshift", kwargs={"pk": shift.event.pk})
)
elif "copyShift" in self.request.POST:
return redirect(reverse("core:shift_copy", kwargs={"pk": shift.pk}))
messages.success(
self.request, _("The shift {shift} has been saved.").format(shift=shift)
)
Expand Down
13 changes: 8 additions & 5 deletions ephios/extra/templates/extra/widgets/recurrence_picker.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% load static %}

<input type="hidden" autocomplete="off" id="pick_hour" value="{{ widget.pick_hour|lower }}">
<div id="vue_app" class="row mt-2">
<div id="vue_app" class="row mt-4">
<div id="chooser" class="col-6">
<div class="input-group pb-4">
<div class="input-group-text">{% translate "starting at" %}</div>
Expand Down Expand Up @@ -217,10 +217,13 @@
id="id_recurrence">
{{ csrf_token }}
</div>
<div class="col-6">
<ul>
<li v-for="date in computed_dates">[[ date ]]</li>
</ul>
<div class="col-6" v-if="computed_dates.length > 0">
<h3>{% translate "Selected dates:" %}</h3>
<div class="two-columns">
<ul>
<li v-for="date in computed_dates">[[ date ]]</li>
</ul>
</div>
</div>
</div>
<script type="text/javascript" src="{% static "rrule/rrule.min.js" %}"></script>
Expand Down
4 changes: 3 additions & 1 deletion ephios/static/ephios/js/event_copy.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ document.addEventListener('DOMContentLoaded', (event) => {
})

const computed_dates = computed(() => {
return rrule_set ? rrule_set.value.all(): []
return rrule_set ? rrule_set.value.all().map(date => {
return formatDate(date) + " " + (date.getUTCHours() < 10 ? "0" : "") + date.getUTCHours() + ":" + (date.getUTCMinutes() < 10 ? "0" : "") + date.getUTCMinutes()
}): []
})

const rrule_string = computed(() => {
Expand Down

0 comments on commit aa15014

Please sign in to comment.