From d0923d56b36c0535d2b7cd227a08c91df304834a Mon Sep 17 00:00:00 2001
From: Konrad Mohrfeldt <konrad.mohrfeldt@farbdev.org>
Date: Thu, 25 Jul 2024 12:57:22 +0200
Subject: [PATCH] fix: raise DRF-compatible exception for configuration errors

ValueError has no built-in handling in DRF causing it to return an HTML
error page. This is unfortunate for clients that expect a JSON error
object like the dashboard.
---
 program/exceptions.py | 10 ++++++++++
 program/services.py   |  6 +++++-
 2 files changed, 15 insertions(+), 1 deletion(-)
 create mode 100644 program/exceptions.py

diff --git a/program/exceptions.py b/program/exceptions.py
new file mode 100644
index 00000000..b1ad279f
--- /dev/null
+++ b/program/exceptions.py
@@ -0,0 +1,10 @@
+from rest_framework import status
+from rest_framework.exceptions import ValidationError
+
+from django.utils.translation import gettext_lazy as _
+
+
+class ConfigurationError(ValidationError):
+    status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
+    default_detail = _("Invalid or insufficient server configuration.")
+    default_code = "misconfigured"
diff --git a/program/services.py b/program/services.py
index 86b9f0cd..87693930 100644
--- a/program/services.py
+++ b/program/services.py
@@ -30,6 +30,7 @@ from django.core.exceptions import ObjectDoesNotExist
 from django.db.models import Q, QuerySet
 from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
+from program.exceptions import ConfigurationError
 from program.models import (
     Note,
     ProgramEntry,
@@ -745,7 +746,10 @@ def generate_program_entries(
     radio_settings: RadioSettings | None = RadioSettings.objects.first()
     fallback_show = radio_settings.fallback_show if radio_settings is not None else None
     if fallback_show is None:
-        raise ValueError("Radio settings must set fallback show if include_virtual is True.")
+        raise ConfigurationError(
+            "Radio settings must define a fallback show if include_virtual is True.",
+            code="no-fallback-show-defined",
+        )
 
     entry_start = start
     timeslot: TimeSlot
-- 
GitLab