Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 1 addition & 39 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ services:
SUBPATH: ${SUBPATH}
DB_CONN_MAX_AGE: "0"
DB_POOL_ENABLED: True

# Enabling Open Telemetry requires the services in docker/docker-compose.observability.yaml
# to be up and running.
OTEL_SDK_DISABLED: ${OTEL_SDK_DISABLED:-true}
Expand Down Expand Up @@ -89,44 +89,6 @@ services:
networks:
- objects-dev

objecttypes-web:
image: maykinmedia/objecttypes-api:latest
environment: &app-env
DB_NAME: objecttypes
DB_USER: objecttypes
DJANGO_SETTINGS_MODULE: objecttypes.conf.docker
SECRET_KEY: ${SECRET_KEY:-fgv=c0hz&tl*8*3m3893@m+1pstrvidc9e^5@fpspmg%cyf15d}
ALLOWED_HOSTS: '*'
CACHE_DEFAULT: redis:6379/0
CACHE_AXES: redis:6379/0
DISABLE_2FA: yes
SUBPATH: ${SUBPATH:-/}
volumes:
- ./docker/objecttypes/objecttypes.json:/app/fixtures/objecttypes.json
ports:
- 8001:8000
depends_on:
objecttypes-web-init:
condition: service_completed_successfully
networks:
- objects-dev

objecttypes-web-init:
image: maykinmedia/objecttypes-api:latest
environment:
<<: *app-env
#
# Django-setup-configuration
RUN_SETUP_CONFIG: ${RUN_SETUP_CONFIG:-true}
command: /setup_configuration.sh
volumes:
- ./docker/setup_configuration/objecttypes_data.yaml:/app/setup_configuration/data.yaml
depends_on:
- db
- redis
networks:
- objects-dev

celery:
image: maykinmedia/objects-api:latest
build: *web_build
Expand Down
18 changes: 1 addition & 17 deletions docker/setup_configuration/data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ sites_config:
zgw_consumers_config_enable: true
zgw_consumers:
services:
- identifier: objecttypes-api
label: Objecttypes API
api_root: http://objecttypes-web:8000/api/v2/
api_connection_check_path: objecttypes
api_type: orc
auth_type: api_key
header_key: Authorization
header_value: Token b9f100590925b529664ed9d370f5f8da124b2c20

- identifier: notifications-api
label: Notificaties API
api_root: http://notificaties.local/api/v1/
Expand All @@ -40,11 +31,9 @@ objecttypes:
items:
- uuid: b427ef84-189d-43aa-9efd-7bb2c459e281
name: Object Type 1
service_identifier: objecttypes-api

- uuid: b0e8553f-8b1a-4d55-ab90-6d02f1bcf2c2
name: Object Type 2
service_identifier: objecttypes-api


tokenauth_config_enable: true
Expand All @@ -60,11 +49,6 @@ tokenauth:
permissions:
- object_type: b0e8553f-8b1a-4d55-ab90-6d02f1bcf2c2
mode: read_only
use_fields: true
fields:
'1':
- record__data__leeftijd
- record__data__kiemjaar
# additional permissions can be added like this:
# - object_type: b427ef84-189d-43aa-9efd-7bb2c459e281
# mode: read_and_write
Expand Down Expand Up @@ -119,4 +103,4 @@ oidc_db_config_admin_auth:
default_groups: []
make_users_staff: true
superuser_group_names:
- Registreerders
- Registreerders
6 changes: 0 additions & 6 deletions docs/installation/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,6 @@ Content Security Policy
* ``CSP_REPORT_PERCENTAGE``: Fraction (between 0 and 1) of requests to include report-uri directive. Defaults to: ``0.0``.


Cache
-----

* ``OBJECTTYPE_VERSION_CACHE_TIMEOUT``: Timeout in seconds for cache when retrieving objecttype versions. Defaults to: ``300``.


Optional
--------

Expand Down
3 changes: 1 addition & 2 deletions performance_test/create_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@
from objects.token.tests.factories import PermissionFactory, TokenAuthFactory

object_type = ObjectTypeFactory.create(
service__api_root="http://localhost:8001/api/v2/",
uuid="f1220670-8ab7-44f1-a318-bd0782e97662",
)

token = TokenAuthFactory(token="secret", is_superuser=False)
token = TokenAuthFactory.create(token="secret", is_superuser=False)
PermissionFactory.create(
object_type=object_type,
mode=PermissionModes.read_only,
Expand Down
2 changes: 2 additions & 0 deletions requirements/base.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ furl
# Django libraries
django-capture-tag

django-jsonsuit

# Common ground libraries
django-setup-configuration>=0.5.0
notifications-api-common[setup-configuration]
Expand Down
3 changes: 3 additions & 0 deletions requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ django==5.2.11
# django-filter
# django-formtools
# django-jsonform
# django-jsonsuit
# django-log-outgoing-requests
# django-markup
# django-otp
Expand Down Expand Up @@ -138,6 +139,8 @@ django-jsonform==2.22.0
# via
# mozilla-django-oidc-db
# open-api-framework
django-jsonsuit==0.5.0
# via -r requirements/base.in
django-log-outgoing-requests==0.6.1
# via open-api-framework
django-markup==1.8.1
Expand Down
5 changes: 5 additions & 0 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ django==5.2.11
# django-filter
# django-formtools
# django-jsonform
# django-jsonsuit
# django-log-outgoing-requests
# django-markup
# django-otp
Expand Down Expand Up @@ -222,6 +223,10 @@ django-jsonform==2.22.0
# -r requirements/base.txt
# mozilla-django-oidc-db
# open-api-framework
django-jsonsuit==0.5.0
# via
# -c requirements/base.txt
# -r requirements/base.txt
django-log-outgoing-requests==0.6.1
# via
# -c requirements/base.txt
Expand Down
5 changes: 5 additions & 0 deletions requirements/dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ django==5.2.11
# django-filter
# django-formtools
# django-jsonform
# django-jsonsuit
# django-log-outgoing-requests
# django-markup
# django-otp
Expand Down Expand Up @@ -266,6 +267,10 @@ django-jsonform==2.22.0
# -r requirements/ci.txt
# mozilla-django-oidc-db
# open-api-framework
django-jsonsuit==0.5.0
# via
# -c requirements/ci.txt
# -r requirements/ci.txt
django-log-outgoing-requests==0.6.1
# via
# -c requirements/ci.txt
Expand Down
5 changes: 5 additions & 0 deletions src/objects/accounts/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class Params:
)


class SuperUserFactory(UserFactory):
is_staff = True
is_superuser = True


class StaffUserFactory(UserFactory):
is_staff = True

Expand Down
54 changes: 8 additions & 46 deletions src/objects/api/fields.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.utils.encoding import smart_str
from django.utils.translation import gettext_lazy as _

from rest_framework import serializers
from vng_api_common.serializers import CachedHyperlinkedIdentityField
from vng_api_common.utils import get_uuid_from_path
from zgw_consumers.models import Service

from objects.core.models import ObjectRecord
from objects.core.models import ObjectRecord, ObjectType


class ObjectSlugRelatedField(serializers.SlugRelatedField):
def get_queryset(self):
queryset = ObjectRecord.objects.select_related(
"object",
"object__object_type",
"object__object_type__service",
"correct",
"corrected",
).order_by("-pk")
Expand All @@ -27,18 +22,21 @@ def get_queryset(self):
return queryset.filter(object=record_instance.object)


class ObjectTypeField(serializers.RelatedField):
class ObjectTypeField(serializers.HyperlinkedRelatedField):
default_error_messages = {
"max_length": _("The value has too many characters"),
"min_length": _("The value has too few characters"),
"does_not_exist": _("ObjectType with url={value} is not configured."),
"invalid": _("Invalid value."),
}

def __init__(self, **kwargs):
self.max_length = kwargs.pop("max_length", None)
self.min_length = kwargs.pop("min_length", None)

kwargs.setdefault("queryset", ObjectType.objects.all())
kwargs.setdefault("view_name", "objecttype-detail")
kwargs.setdefault("lookup_field", "uuid")
kwargs.setdefault("lookup_url_kwarg", "uuid")

super().__init__(**kwargs)

def to_internal_value(self, data):
Expand All @@ -48,43 +46,7 @@ def to_internal_value(self, data):
if self.min_length and len(data) < self.min_length:
self.fail("min_length")

try:
return self.get_queryset().get_by_url(data)
except ObjectDoesNotExist:
# if service is configured, but object_type is missing
# let's try to create an ObjectType
service = Service.get_service(data)
if not service:
self.fail("does_not_exist", value=smart_str(data))

uuid = get_uuid_from_path(data)
object_type = self.get_queryset().model(service=service, uuid=uuid)

try:
object_type.clean()
except ValidationError:
self.fail("does_not_exist", value=smart_str(data))

object_type.save()
return object_type

except (TypeError, ValueError):
self.fail("invalid")

def to_representation(self, obj):
return obj.url


class ObjectUrlField(serializers.HyperlinkedIdentityField):
lookup_field = "uuid"

def get_url(self, obj, view_name, request, format):
if hasattr(obj, "pk") and obj.pk in (None, ""):
return None

lookup_value = getattr(obj.object, "uuid")
kwargs = {self.lookup_url_kwarg: lookup_value}
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
return super().to_internal_value(data)


class CachedObjectUrlField(CachedHyperlinkedIdentityField):
Expand Down
6 changes: 5 additions & 1 deletion src/objects/api/kanalen.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from rest_framework.request import Request

from objects.core.models import ObjectRecord
from objects.tests.v2.utils import reverse


class ObjectKanaal(Kanaal):
Expand All @@ -32,7 +33,10 @@ def get_kenmerken(
data = data or {}
return {
kenmerk: (
data.get("type") or obj._object_type.url
data.get("type")
or request.build_absolute_url(
reverse("objecttype-detail", args=[data.object_type.uuid])
)
if kenmerk == "object_type"
else data.get(kenmerk, getattr(obj, kenmerk))
)
Expand Down
26 changes: 22 additions & 4 deletions src/objects/api/metrics.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
from opentelemetry import metrics

meter = metrics.get_meter("objects.api")
object_meter = metrics.get_meter("objects.api")

objects_create_counter = meter.create_counter(
objects_create_counter = object_meter.create_counter(
"objects.object.creates",
description="Amount of objects created (via the API).",
unit="1",
)
objects_update_counter = meter.create_counter(
objects_update_counter = object_meter.create_counter(
"objects.object.updates",
description="Amount of objects updated (via the API).",
unit="1",
)
objects_delete_counter = meter.create_counter(
objects_delete_counter = object_meter.create_counter(
"objects.object.deletes",
description="Amount of objects deleted (via the API).",
unit="1",
)

objecttype_meter = metrics.get_meter("objecttypes.api.v2")

objecttype_create_counter = objecttype_meter.create_counter(
"objecttypes.objecttype.creates",
description="Amount of objecttypes created (via the API).",
unit="1",
)
objecttype_update_counter = objecttype_meter.create_counter(
"objecttypes.objecttype.updates",
description="Amount of objecttypes updated (via the API).",
unit="1",
)
objecttype_delete_counter = objecttype_meter.create_counter(
"objecttypes.objecttype.deletes",
description="Amount of objecttypes deleted (via the API).",
unit="1",
)
17 changes: 17 additions & 0 deletions src/objects/api/mixins.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django.core.exceptions import ValidationError
from django.db import models
from django.http import Http404

from notifications_api_common.viewsets import (
NotificationCreateMixin,
Expand All @@ -8,6 +10,7 @@
)
from rest_framework.exceptions import NotAcceptable
from rest_framework.renderers import BrowsableAPIRenderer
from rest_framework_nested.viewsets import NestedViewSetMixin as _NestedViewSetMixin
from vng_api_common.exceptions import PreconditionFailed
from vng_api_common.geo import (
DEFAULT_CRS,
Expand All @@ -18,6 +21,20 @@
)


class NestedViewSetMixin(_NestedViewSetMixin):
def get_queryset(self):
"""
catch validation errors if parent_lookup_kwargs have incorrect format
and return 404
"""
try:
queryset = super().get_queryset()
except ValidationError:
raise Http404

return queryset


class GeoMixin(_GeoMixin):
def perform_crs_negotation(self, request):
# don't cripple the browsable API...
Expand Down
Loading