Skip to content

Commit

Permalink
✨ [maykinmedia/django-setup-configuration#1] add configuration steps
Browse files Browse the repository at this point in the history
  • Loading branch information
annashamray committed Apr 23, 2024
1 parent fa398d3 commit b2e586e
Show file tree
Hide file tree
Showing 11 changed files with 247 additions and 1 deletion.
3 changes: 2 additions & 1 deletion requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ open-api-framework
# Core python libraries
glom # data represenation based on spec
jsonschema
django-log-outgoing-requests
furl

# Django libraries
git+https://github.com/maykinmedia/django-setup-configuration.git@feature/1-config-command
django-log-outgoing-requests

# Common ground libraries
notifications-api-common
12 changes: 12 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ faker==8.1.0
# via zgw-consumers
flower==2.0.1
# via open-api-framework
furl==2.1.3
# via -r requirements/base.in
gemma-zds-client==1.0.1
# via
# commonground-api-common
Expand Down Expand Up @@ -232,6 +234,8 @@ notifications-api-common==0.2.2
# commonground-api-common
open-api-framework==0.2.0
# via -r requirements/base.in
orderedmultidict==1.0.1
# via furl
oyaml==1.0
# via commonground-api-common
packaging==23.2
Expand Down Expand Up @@ -298,8 +302,16 @@ sentry-sdk==1.39.2
# via open-api-framework
six==1.16.0
# via
<<<<<<< HEAD
# bleach
# isodate
=======
# django-markup
# furl
# isodate
# jsonschema
# orderedmultidict
>>>>>>> 6096ba9 (:sparkles: [https://github.com/maykinmedia/django-setup-configuration/issues/1] add configuration steps)
# python-dateutil
# qrcode
# requests-mock
Expand Down
6 changes: 6 additions & 0 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ flower==2.0.1
# open-api-framework
freezegun==1.1.0
# via -r requirements/test-tools.in
furl==2.1.3
# via -r requirements/base.txt
gemma-zds-client==1.0.1
# via
# -r requirements/base.txt
Expand Down Expand Up @@ -365,6 +367,10 @@ notifications-api-common==0.2.2
# commonground-api-common
open-api-framework==0.2.0
# via -r requirements/base.txt
orderedmultidict==1.0.1
# via
# -r requirements/base.txt
# furl
oyaml==1.0
# via
# -r requirements/base.txt
Expand Down
2 changes: 2 additions & 0 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ flower==2.0.1
# open-api-framework
freezegun==1.1.0
# via -r requirements/ci.txt
furl==2.1.3
# via -r requirements/ci.txt
gemma-zds-client==1.0.1
# via
# -r requirements/ci.txt
Expand Down
37 changes: 37 additions & 0 deletions src/objects/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
# Project applications.
"objects.accounts",
"objects.api",
"objects.config",
"objects.core",
"objects.token",
"objects.utils",
Expand Down Expand Up @@ -503,3 +504,39 @@
CELERY_TASK_SOFT_TIME_LIMIT = config(
"CELERY_TASK_SOFT_TIME_LIMIT", default=5 * 60
) # soft

#
# Django setup configuration
#
SETUP_CONFIGURATION_STEPS = [
"objects.config.site.SiteConfigurationStep",
"objects.config.objecttypes.ObjecttypesStep",
"objects.config.demo.DemoUserStep",
]


#
# Objecttypes settings
#

# setup_configuration command
# sites config
SITES_CONFIG_ENABLE = config("SITES_CONFIG_ENABLE", default=True)
OBJECTS_DOMAIN = config("OBJECTS_DOMAIN", "")
OBJECTS_ORGANIZATION = config("OBJECTS_ORGANIZATION", "")
# objecttypes config
OBJECTS_OBJECTTYPES_CONFIG_ENABLE = config(
"OBJECTS_OBJECTTYPES_CONFIG_ENABLE", default=True
)
OBJECTTYPES_API_ROOT = config("OBJECTTYPES_API_ROOT", "")
if OBJECTTYPES_API_ROOT and not OBJECTTYPES_API_ROOT.endswith("/"):
OBJECTTYPES_API_ROOT = f"{OBJECTTYPES_API_ROOT.strip()}/"
OBJECTTYPES_API_OAS = config(
"OBJECTTYPES_API_OAS", default=f"{OBJECTTYPES_API_ROOT}schema/openapi.yaml"
)
OBJECTS_OBJECTTYPES_TOKEN = config("OBJECTS_OBJECTTYPES_TOKEN", "")
# Demo User Configuration
DEMO_CONFIG_ENABLE = config("DEMO_CONFIG_ENABLE", default=DEBUG)
DEMO_TOKEN = config("DEMO_TOKEN", "")
DEMO_PERSON = config("DEMO_PERSON", "")
DEMO_EMAIL = config("DEMO_EMAIL", "")
Empty file added src/objects/config/__init__.py
Empty file.
63 changes: 63 additions & 0 deletions src/objects/config/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from django.conf import settings
from django.urls import reverse

import requests
from django_setup_configuration.configuration import BaseConfigurationStep
from django_setup_configuration.exceptions import SelfTestFailed

from objects.token.models import TokenAuth
from objects.utils import build_absolute_url


class DemoUserStep(BaseConfigurationStep):
"""
Create demo user to request Objects API
**NOTE** For now demo user has all permissions.
"""

verbose_name = "Demo User Configuration"
required_settings = [
"DEMO_TOKEN",
"DEMO_PERSON",
"DEMO_EMAIL",
]
enable_setting = "DEMO_CONFIG_ENABLE"

def is_configured(self) -> bool:
return TokenAuth.objects.filter(token=settings.DEMO_TOKEN).exists()

def configure(self):
token_auth, created = TokenAuth.objects.get_or_create(
token=settings.DEMO_TOKEN,
defaults={
"contact_person": settings.DEMO_PERSON,
"email": settings.DEMO_EMAIL,
"is_superuser": True,
},
)
if (
token_auth.contact_person != settings.DEMO_PERSON
or token_auth.email != settings.DEMO_EMAIL
):
token_auth.contact_person = settings.DEMO_PERSON
token_auth.email = settings.DEMO_EMAIL
token_auth.save(update_fields=["contact_person", "email"])

def test_configuration(self):
endpoint = reverse("v2:object-list")
full_url = build_absolute_url(endpoint, request=None)

try:
response = requests.get(
full_url,
headers={
"HTTP_AUTHORIZATION": f"Token {settings.OBJECTS_OBJECTTYPES_TOKEN}",
"Accept": "application/json",
},
)
response.raise_for_status()
except requests.RequestException as exc:
raise SelfTestFailed(
"Could not list objects for the configured token"
) from exc
58 changes: 58 additions & 0 deletions src/objects/config/objecttypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from django.conf import settings

import requests
from django_setup_configuration.configuration import BaseConfigurationStep
from django_setup_configuration.exceptions import SelfTestFailed
from zds_client.client import ClientError
from zgw_consumers.constants import APITypes, AuthTypes
from zgw_consumers.models import Service


class ObjecttypesStep(BaseConfigurationStep):
"""
Configure credentials for Objects API to request Objecttypes API
Normal mode doesn't change the token after its initial creation.
If the token is changed, run this command with 'overwrite' flag
"""

verbose_name = "Objecttypes Configuration"
required_settings = [
"OBJECTTYPES_API_ROOT",
"OBJECTS_OBJECTTYPES_TOKEN",
]
enable_setting = "OBJECTS_OBJECTTYPES_CONFIG_ENABLE"

def is_configured(self) -> bool:
return Service.objects.filter(api_root=settings.OBJECTTYPES_API_ROOT).exists()

def configure(self) -> None:
service, created = Service.objects.update_or_create(
api_root=settings.OBJECTTYPES_API_ROOT,
defaults={
"label": "Objecttypes API",
"api_type": APITypes.orc,
"oas": settings.OBJECTTYPES_API_OAS,
"auth_type": AuthTypes.api_key,
"header_key": "Authorization",
"header_value": f"Token {settings.OBJECTS_OBJECTTYPES_TOKEN}",
},
)
if not created:
service.oas = settings.OBJECTTYPES_API_OAS
service.header_value = f"Token {settings.OBJECTS_OBJECTTYPES_TOKEN}"
service.save(update_fields=["oas", "header_value"])

def test_configuration(self) -> None:
"""
This check depends on the configuration in Objecttypes
"""
client = Service.objects.get(
api_root=settings.OBJECTTYPES_API_ROOT
).build_client()
try:
client.list("objecttype")
except (requests.RequestException, ClientError) as exc:
raise SelfTestFailed(
"Could not Could not retrieve list of objecttypes from Objecttypes API."
) from exc
37 changes: 37 additions & 0 deletions src/objects/config/site.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from django.conf import settings
from django.contrib.sites.models import Site
from django.urls import reverse

import requests
from django_setup_configuration.configuration import BaseConfigurationStep
from django_setup_configuration.exceptions import SelfTestFailed

from objects.utils import build_absolute_url


class SiteConfigurationStep(BaseConfigurationStep):
"""
Configure the application site/domain.
"""

verbose_name = "Site Configuration"
required_settings = ["OBJECTS_DOMAIN", "OBJECTS_ORGANIZATION"]
enable_setting = "SITES_CONFIG_ENABLE"

def is_configured(self) -> bool:
site = Site.objects.get_current()
return site.domain == settings.OBJECTS_DOMAIN

def configure(self):
site = Site.objects.get_current()
site.domain = settings.OBJECTS_DOMAIN
site.name = f"Objects {settings.OBJECTS_ORGANIZATION}".strip()
site.save()

def test_configuration(self):
full_url = build_absolute_url(reverse("home"))
try:
response = requests.get(full_url)
response.raise_for_status()
except requests.RequestException as exc:
raise SelfTestFailed(f"Could not access home page at '{full_url}'") from exc
1 change: 1 addition & 0 deletions src/objects/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
template_name="index.html",
extra_context={"version": api_settings.DEFAULT_VERSION},
),
name="home",
),
path("ref/", include("vng_api_common.urls")),
path("ref/", include("notifications_api_common.urls")),
Expand Down
29 changes: 29 additions & 0 deletions src/objects/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from django.conf import settings
from django.http import HttpRequest

from furl import furl


def get_domain() -> str:
"""
Obtain the domain/netloc according to settings or configuration.
"""
from django.contrib.sites.models import Site

if settings.OBJECTS_DOMAIN:
return settings.OBJECTS_DOMAIN

return Site.objects.get_current().domain


def build_absolute_url(path: str, request: HttpRequest | None = None) -> str:
if request is not None:
return request.build_absolute_uri(path)

domain = get_domain()
_furl = furl(
scheme="https" if settings.IS_HTTPS else "http",
netloc=domain,
path=path,
)
return _furl.url

0 comments on commit b2e586e

Please sign in to comment.