diff --git a/shiftregister/app/views.py b/shiftregister/app/views.py index 0bca633..96efbf1 100644 --- a/shiftregister/app/views.py +++ b/shiftregister/app/views.py @@ -8,6 +8,7 @@ from django.core.cache import cache from django.db import transaction from django.db.models import Count, ExpressionWrapper, F, Q from django.db.models.fields import DateTimeField +from django.db.models.functions import Coalesce from django.shortcuts import get_object_or_404, redirect, render from django.utils import timezone from dynamic_preferences.registries import global_preferences_registry @@ -30,7 +31,7 @@ def index(request): event_end_at = global_preferences["helper__event_end_at"] days = ( Shift.objects.filter( - deleted=False, start_at__gte=event_start_at, start_at__lte=event_end_at + start_at__gte=event_start_at, start_at__lte=event_end_at ) .datetimes("start_at", "day") .all() @@ -65,13 +66,12 @@ def index(request): # dont show shifts starting in <60 minutes? # currently only sorts by date free_shifts = ( - Shift.with_reg_count() + Shift.objects.with_reg_count() .filter( help_wanted, start_at__gte=day + timedelta(hours=6), start_at__lte=day + timedelta(hours=30), start_at__gt=timezone.now(), - deleted=False, ) .order_by("start_at") for day in days @@ -191,7 +191,12 @@ def register(request): @event_state def shift(request, shiftid): - shift = get_object_or_404(Shift.with_reg_count(), pk=shiftid) + shift = get_object_or_404( + Shift.all_objects.with_reg_count() + .select_related("event__calendar") + .annotate(restricted=Coalesce("event__calendar__restricted", False)), + pk=shiftid, + ) helper = request.helper context = { "enable_asta": global_preferences["helper__enable_asta"], @@ -201,15 +206,14 @@ def shift(request, shiftid): "shift": shift, "shift_form": EmptyForm, } - - # this currently ignores date/time - request.session["last_seen_shift"] = shiftid - if ( + context["can_register"] = ( shift.required_helpers > shift.registration_count() or shift.required_helpers == 0 and shift.room.required_helpers > shift.registration_count() - ): - context["can_register"] = True + ) and not shift.restricted + + # this currently ignores date/time + request.session["last_seen_shift"] = shiftid if helper: context["helper"] = helper diff --git a/shiftregister/importer/admin.py b/shiftregister/importer/admin.py index d5e6786..2f5afe6 100644 --- a/shiftregister/importer/admin.py +++ b/shiftregister/importer/admin.py @@ -10,5 +10,5 @@ def update_calendar(modeladmin, request, queryset): @admin.register(Calendar) class CalendarAdmin(admin.ModelAdmin): - list_display = ("name", "url", "needs_fallback", "has_errors") + list_display = ("name", "url", "needs_fallback", "restricted", "has_errors") actions = (update_calendar,) diff --git a/shiftregister/importer/migrations/0005_calendar_restricted.py b/shiftregister/importer/migrations/0005_calendar_restricted.py new file mode 100644 index 0000000..4a0fd0e --- /dev/null +++ b/shiftregister/importer/migrations/0005_calendar_restricted.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.4 on 2025-05-16 22:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("importer", "0004_calendar_name"), + ] + + operations = [ + migrations.AddField( + model_name="calendar", + name="restricted", + field=models.BooleanField(default=False), + ), + ] diff --git a/shiftregister/importer/models.py b/shiftregister/importer/models.py index ed9aa71..76e46ef 100644 --- a/shiftregister/importer/models.py +++ b/shiftregister/importer/models.py @@ -8,6 +8,7 @@ class Calendar(models.Model): needs_fallback = models.BooleanField(default=False, editable=True) has_errors = models.BooleanField(default=False, editable=False) name = models.CharField(max_length=255, null=True, blank=True) + restricted = models.BooleanField(default=False) def update(self): # break circular import @@ -18,5 +19,7 @@ class Calendar(models.Model): class Event(Shift): + objects = models.Manager() + uuid = models.UUIDField(primary_key=True, editable=False) calendar = models.ForeignKey(Calendar, on_delete=models.CASCADE) diff --git a/shiftregister/metrics/views.py b/shiftregister/metrics/views.py index 1c77f50..201263b 100644 --- a/shiftregister/metrics/views.py +++ b/shiftregister/metrics/views.py @@ -35,7 +35,7 @@ def metrics(request): ), ( "fallback_shifts_full", - Shift.with_reg_count() + Shift.objects.with_reg_count() .annotate( real_required_helpers=Case( When( @@ -46,7 +46,6 @@ def metrics(request): fallbackassignment_count=Count("fallbackassignment"), ) .filter( - deleted=False, reg_count__gte=F("real_required_helpers"), fallbackassignment_count__gt=0, ) @@ -96,16 +95,14 @@ def metrics(request): ), ( "helpers_required", - Shift.objects.filter(deleted=False) - .annotate( + Shift.objects.annotate( real_required_helpers=Case( When( required_helpers=0, then=F("room__required_helpers") ), default=F("required_helpers"), ) - ) - .aggregate(sum=Sum("real_required_helpers"))["sum"] + ).aggregate(sum=Sum("real_required_helpers"))["sum"] or 0, ), ( @@ -124,15 +121,15 @@ def metrics(request): *( ( f'shifts{{room="{room.name}"}}', - Shift.objects.filter(deleted=False, room=room).count(), + Shift.objects.filter(room=room).count(), ) for room in Room.objects.all() ), *( ( f'shifts_occupied{{room="{room.name}"}}', - Shift.with_reg_count() - .filter(deleted=False, reg_count__gte=1, room=room) + Shift.objects.with_reg_count() + .filter(reg_count__gte=1, room=room) .count(), ) for room in Room.objects.all() @@ -140,7 +137,7 @@ def metrics(request): *( ( f'shifts_full{{room="{room.name}"}}', - Shift.with_reg_count() + Shift.objects.with_reg_count() .annotate( real_required_helpers=Case( When( @@ -151,7 +148,7 @@ def metrics(request): ) ) .filter( - deleted=False, + reg_count__gt=0, reg_count__gte=F("real_required_helpers"), room=room, ) diff --git a/shiftregister/signage/views.py b/shiftregister/signage/views.py index fe1fbf3..c1bb3a8 100644 --- a/shiftregister/signage/views.py +++ b/shiftregister/signage/views.py @@ -33,16 +33,16 @@ def public_dashboard(request): ) num_free_shifts = ( - Shift.with_reg_count() - .filter(help_wanted, deleted=False, start_at__gte=timezone.now()) + Shift.objects.with_reg_count() + .filter(help_wanted, start_at__gte=timezone.now()) .count() ) if num_free_shifts > 0: facts.append(("Zu übernehmende Schichten", num_free_shifts)) next_free_shifts = ( - Shift.with_reg_count() - .filter(help_wanted, start_at__gt=timezone.now(), deleted=False) + Shift.objects.with_reg_count() + .filter(help_wanted, start_at__gt=timezone.now()) .order_by("start_at")[:4] ) @@ -79,7 +79,7 @@ def team_dashboard(request): day = today team_shifts = ( - Shift.with_reg_count() + Shift.all_objects.with_reg_count() .annotate( end_at=ExpressionWrapper( F("start_at") + F("duration"), output_field=models.DateTimeField() diff --git a/shiftregister/team/views.py b/shiftregister/team/views.py index 9ad36af..21aae57 100644 --- a/shiftregister/team/views.py +++ b/shiftregister/team/views.py @@ -44,7 +44,7 @@ def shift_overview(request): context = {} context["running_shifts"] = ( - Shift.with_reg_count() + Shift.all_objects.with_reg_count() .prefetch_related("event__calendar") .annotate( checkin_count=Count( @@ -65,7 +65,7 @@ def shift_overview(request): ) context["next_shifts"] = ( - Shift.with_reg_count() + Shift.all_objects.with_reg_count() .prefetch_related("event__calendar") .annotate(checkin_count=checkin_count) .filter( @@ -80,7 +80,7 @@ def shift_overview(request): context["next_shifts_per_room"] = filter( lambda x: x is not None, ( - Shift.with_reg_count() + Shift.all_objects.with_reg_count() .prefetch_related("event__calendar") .filter(room=room, start_at__gt=timezone.now(), deleted=False) .order_by("start_at") @@ -99,7 +99,10 @@ def add_helper_shift(self): @login_required def shift_detail(request, pk): shift = get_object_or_404( - Shift.with_reg_count().prefetch_related("shiftregistration_set__helper"), pk=pk + Shift.all_objects.with_reg_count().prefetch_related( + "shiftregistration_set__helper" + ), + pk=pk, ) form = HelperShift() if request.method == "POST": @@ -217,7 +220,7 @@ class ShiftList(LoginRequiredMixin, ListView): title = "Alle Schichten" def get_queryset(self): - return Shift.with_reg_count() + return Shift.all_objects.with_reg_count() def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -236,7 +239,7 @@ class FreeShiftList(ShiftList): required_helpers=0 ) & Q(room__required_helpers__gt=F("reg_count")) return ( - Shift.with_reg_count() + Shift.all_objects.with_reg_count() .annotate( end_at=ExpressionWrapper( F("start_at") + F("duration"), @@ -265,7 +268,7 @@ class RoomShiftList(ShiftList): required_helpers=0 ) & Q(room__required_helpers__gt=F("reg_count")) return ( - Shift.with_reg_count() + Shift.all_objects.with_reg_count() .filter( deleted=False, room=room,