diff --git a/program/models.py b/program/models.py index f11245b284d1a878abd38bb890dfbb08241cc019..ac7677b65c830e680e80c91c0dc23277d8962d4d 100644 --- a/program/models.py +++ b/program/models.py @@ -41,6 +41,12 @@ from steering.settings import ( ) +class ScheduleConflictError(ValidationError): + def __init__(self, *args, conflicts=None, **kwargs): + super().__init__(*args, **kwargs) + self.conflicts = conflicts + + class Type(models.Model): name = models.CharField(max_length=32) slug = models.SlugField(max_length=32, unique=True) @@ -732,7 +738,7 @@ class Schedule(models.Model): """ sdl = data["schedule"] - solutions = data["solutions"] + solutions = data.get("solutions", []) # Regenerate conflicts schedule = Schedule.instantiate_upcoming(sdl, show_pk, schedule_pk) @@ -756,9 +762,10 @@ class Schedule(models.Model): ) if len(solutions) != num_conflicts: - raise ValidationError( + raise ScheduleConflictError( _("Numbers of conflicts and solutions don't match."), code="one-solution-per-conflict", + conflicts=conflicts, ) # Projected timeslots to create @@ -963,7 +970,11 @@ class Schedule(models.Model): conflicts["notes"] = data.get("notes") conflicts["playlists"] = data.get("playlists") - return conflicts + raise ScheduleConflictError( + _("Not all conflicts have been resolved."), + code="unresolved-conflicts", + conflicts=conflicts, + ) # Collect upcoming timeslots to delete which might still remain del_timeslots = TimeSlot.objects.filter( diff --git a/program/views.py b/program/views.py index 8d18a2db210c52fb59f1199458faf268c2e3d351..c000b10be91cc6f379342a7f3531dd02807c00e1 100644 --- a/program/views.py +++ b/program/views.py @@ -42,6 +42,7 @@ from program.models import ( MusicFocus, Note, Schedule, + ScheduleConflictError, Show, TimeSlot, Topic, @@ -483,28 +484,17 @@ class APIScheduleViewSet( if show_pk is None or "schedule" not in request.data: return Response(status=status.HTTP_400_BAD_REQUEST) - # First create submit -> return projected timeslots and collisions - # TODO: Perhaps directly insert into database if no conflicts found - if "solutions" not in request.data: + try: + resolution = Schedule.resolve_conflicts(request.data, pk, show_pk) + except ScheduleConflictError as exc: # TODO: respond with status.HTTP_409_CONFLICT when the dashboard can handle it - return Response( - Schedule.make_conflicts(request.data["schedule"], pk, show_pk), - ) - - # Otherwise try to resolve - resolution = Schedule.resolve_conflicts(request.data, pk, show_pk) + return Response(exc.conflicts) if all(key in resolution for key in ["create", "update", "delete"]): # this is a dry-run return Response(resolution, status=status.HTTP_202_ACCEPTED) - # If resolution went well - if "projected" not in resolution: - return Response(resolution, status=status.HTTP_201_CREATED) - - # Otherwise return conflicts - # TODO: respond with status.HTTP_409_CONFLICT when the dashboard can handle it - return Response(resolution) + return Response(resolution, status=status.HTTP_201_CREATED) def update(self, request, *args, **kwargs): """ @@ -540,26 +530,14 @@ class APIScheduleViewSet( serializer = ScheduleSerializer(schedule) return Response(serializer.data) - # First update submit -> return projected timeslots and collisions - if "solutions" not in request.data: - # TODO: respond with status.HTTP_409_CONFLICT when the dashboard can handle it - return Response( - Schedule.make_conflicts( - request.data["schedule"], schedule.pk, schedule.show.pk - ) + try: + resolution = Schedule.resolve_conflicts( + request.data, schedule.pk, schedule.show.pk ) + except ScheduleConflictError as exc: + # TODO: respond with status.HTTP_409_CONFLICT when the dashboard can handle it + return Response(exc.conflicts) - # Otherwise try to resolve - resolution = Schedule.resolve_conflicts( - request.data, schedule.pk, schedule.show.pk - ) - - # If resolution went well - if "projected" not in resolution: - return Response(resolution) - - # Otherwise return conflicts - # TODO: respond with status.HTTP_409_CONFLICT when the dashboard can handle it return Response(resolution) def destroy(self, request, *args, **kwargs):