Skip to content

Commit

Permalink
Merge pull request #26 from maykinmedia/feature/register-kanalen-update
Browse files Browse the repository at this point in the history
✨ [open-zaak/open-notificaties#207] Update existing with register_kanalen
  • Loading branch information
stevenbal authored Dec 20, 2024
2 parents 3300aed + d798d77 commit b4191e9
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 127 deletions.
119 changes: 78 additions & 41 deletions notifications_api_common/management/commands/register_kanalen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
from typing import Optional

from django.contrib.sites.models import Site
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandError
from django.urls import reverse

from ape_pie.client import APIClient
from requests import Response
from requests.exceptions import JSONDecodeError, RequestException
from zgw_consumers.models import Service

from ...kanalen import KANAAL_REGISTRY
from ...models import NotificationsConfig
Expand All @@ -19,59 +19,63 @@
class KanaalException(Exception):
kanaal: str
data: dict | list
service: Service
base_url: str

def __init__(
self, kanaal: str, service: Service, data: Optional[dict | list] = None
):
def __init__(self, kanaal: str, base_url: str, data: Optional[dict | list] = None):
super().__init__()

self.kanaal = kanaal
self.service = service
self.base_url = base_url
self.data = data or {}


class KanaalRequestException(KanaalException):
def __str__(self) -> str:
return (
f"Unable to retrieve kanaal {self.kanaal} from {self.service}: {self.data}"
f"Unable to retrieve kanaal {self.kanaal} from {self.base_url}: {self.data}"
)


class KanaalCreateException(KanaalException):
def __str__(self) -> str:
return f"Unable to create kanaal {self.kanaal} at {self.service}: {self.data}"
return f"Unable to create kanaal {self.kanaal} at {self.base_url}: {self.data}"


class KanaalExistsException(KanaalException):
class KanaalUpdateException(KanaalException):
def __str__(self) -> str:
return f"Kanaal '{self.kanaal}' already exists within {self.service}"

return f"Unable to update kanaal {self.kanaal} at {self.base_url}: {self.data}"

def create_kanaal(kanaal: str, service: Service) -> None:
"""
Create a kanaal, if it doesn't exist yet.
"""
client = NotificationsConfig.get_client()

assert client
class KanaalExistsException(KanaalException):
def __str__(self) -> str:
return f"Kanaal '{self.kanaal}' already exists within {self.base_url}"

# look up the exchange in the registry
_kanaal = next(k for k in KANAAL_REGISTRY if k.label == kanaal)

def get_kanaal(kanaal: str, client: APIClient) -> dict | None:
response_data = []

try:
response: Response = client.get("kanaal", params={"naam": kanaal})
kanalen: list[dict] = response.json() or []
kanalen: list = response.json()
response.raise_for_status()
except (RequestException, JSONDecodeError) as exception:
raise KanaalRequestException(
kanaal=kanaal, service=service, data=response_data
kanaal=kanaal, base_url=client.base_url, data=response_data
) from exception
else:
if kanalen:
# `Kanaal.naam` is unique in Open Notificaties, so there should only be one
if len(kanalen) > 1:
logger.error(
"Found more than one Kanaal with naam %s, this should not be possible",
kanaal,
)
return kanalen[0]
return None


if kanalen:
raise KanaalExistsException(kanaal=kanaal, service=service, data=response_data)
def construct_kanaal_request_data(kanaal: str):
_kanaal = next(k for k in KANAAL_REGISTRY if k.label == kanaal)

# build up own documentation URL
domain = Site.objects.get_current().domain
Expand All @@ -80,24 +84,50 @@ def create_kanaal(kanaal: str, service: Service) -> None:
f"{protocol}://{domain}{reverse('notifications:kanalen')}#{kanaal}"
)

data = {
"naam": kanaal,
"documentatieLink": documentation_url,
"filters": list(_kanaal.kenmerken),
}
return data


def create_kanaal(kanaal: str, client) -> None:
"""
Create a kanaal, if it doesn't exist yet.
"""
data = construct_kanaal_request_data(kanaal)

response_data = {}
try:
response: Response = client.post(
"kanaal",
json={
"naam": kanaal,
"documentatieLink": documentation_url,
"filters": list(_kanaal.kenmerken),
},
)
response: Response = client.post("kanaal", json=data)

response_data: dict = response.json() or {}
response_data: dict = response.json()
response.raise_for_status()
except (RequestException, JSONDecodeError) as exception:
raise KanaalCreateException(
kanaal=kanaal, service=service, data=response_data
kanaal=kanaal, base_url=client.base_url, data=response_data
) from exception


def replace_kanaal(kanaal: str, existing_kanaal: dict, client: APIClient) -> None:
"""
Fully update a kanaal, if it doesn't exist yet.
"""
data = construct_kanaal_request_data(kanaal)

response_data = {}
try:
response: Response = client.put(existing_kanaal["url"], json=data)
response_data: dict = response.json()
response.raise_for_status()
except (RequestException, JSONDecodeError) as exception:
raise KanaalUpdateException(
kanaal=kanaal, base_url=client.base_url, data=response_data
) from exception
return


class Command(BaseCommand):
help = "Create kanaal in notification component"

Expand All @@ -115,23 +145,30 @@ def handle(self, **options):
config = NotificationsConfig.get_solo()

if not config.notifications_api_service:
self.stderr.write(
raise CommandError(
"NotificationsConfig does not have a "
"`notifications_api_service` configured"
)

service = config.notifications_api_service

# use CLI arg or fall back to setting
kanalen = options["kanalen"] or sorted(
[kanaal.label for kanaal in KANAAL_REGISTRY]
)

client = NotificationsConfig.get_client()
assert client

for kanaal in kanalen:
try:
create_kanaal(kanaal, service)
self.stdout.write(
f"Registered kanaal '{kanaal}' with {service.api_root}"
)
if existing_kanaal := get_kanaal(kanaal, client):
replace_kanaal(kanaal, existing_kanaal, client)
self.stdout.write(
f"Updated already existing kanaal '{kanaal}' with {client.base_url}"
)
else:
create_kanaal(kanaal, client)
self.stdout.write(
f"Registered kanaal '{kanaal}' with {client.base_url}"
)
except (KanaalException,) as exception:
self.stderr.write(f"{str(exception)} . Skipping..")
15 changes: 14 additions & 1 deletion testapp/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
from django.contrib import admin
from django.urls import include, path
from django.views import View

from .api import router

urlpatterns = [path("admin/", admin.site.urls), path("api/", include(router.urls))]
notifications_patterns = [
path("kanalen/", View.as_view(), name="kanalen"),
]


urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include(router.urls)),
path(
"notifications/",
include((notifications_patterns, "notifications"), namespace="notifications"),
),
]
Loading

0 comments on commit b4191e9

Please sign in to comment.