From 2d78114ad2bd3d5d00711bc8981400a26eec0959 Mon Sep 17 00:00:00 2001 From: Nico Virkki Date: Mon, 29 Apr 2024 09:10:17 +0300 Subject: [PATCH] feat: add FieldNotAllowedError Refs HP-2319 --- open_city_profile/consts.py | 1 + open_city_profile/exceptions.py | 4 ++++ open_city_profile/graphene.py | 25 +++++++++++++++++++++++++ open_city_profile/views.py | 3 +++ 4 files changed, 33 insertions(+) diff --git a/open_city_profile/consts.py b/open_city_profile/consts.py index ff535cf3..89ed4411 100644 --- a/open_city_profile/consts.py +++ b/open_city_profile/consts.py @@ -23,6 +23,7 @@ PROFILE_ALREADY_EXISTS_FOR_USER_ERROR = "PROFILE_ALREADY_EXISTS_FOR_USER_ERROR" PROFILE_MUST_HAVE_PRIMARY_EMAIL = "PROFILE_MUST_HAVE_PRIMARY_EMAIL" INSUFFICIENT_LOA_ERROR = "INSUFFICIENT_LOA_ERROR" +FIELD_NOT_ALLOWED_ERROR = "FIELD_NOT_ALLOWED_ERROR" # Service specific GDPR errors SERVICE_GDPR_API_REQUEST_ERROR = "SERVICE_GDPR_API_REQUEST_ERROR" diff --git a/open_city_profile/exceptions.py b/open_city_profile/exceptions.py index 766209d9..6d45d7f6 100644 --- a/open_city_profile/exceptions.py +++ b/open_city_profile/exceptions.py @@ -73,3 +73,7 @@ class TokenExchangeError(Exception): class InsufficientLoaError(ProfileGraphQLError): """The requester has insufficient level of authentication to retrieve this data""" + + +class FieldNotAllowedError(ProfileGraphQLError): + """Field are not allowed for the service""" diff --git a/open_city_profile/graphene.py b/open_city_profile/graphene.py index 6bad7d7a..54c59036 100644 --- a/open_city_profile/graphene.py +++ b/open_city_profile/graphene.py @@ -5,12 +5,14 @@ from django.conf import settings from django.forms import MultipleChoiceField from django_filters import MultipleChoiceFilter +from graphene.utils.str_converters import to_snake_case from graphene_django import DjangoObjectType from graphene_django.forms.converter import convert_form_field from graphene_django.types import ALL_FIELDS from graphql_sync_dataloaders import SyncDataLoader from parler.models import TranslatableModel +from open_city_profile.exceptions import FieldNotAllowedError, ServiceNotIdentifiedError from profiles.loaders import ( addresses_by_profile_id_loader, emails_by_profile_id_loader, @@ -178,3 +180,26 @@ def __init_subclass_with_meta__( _meta=_meta, **options, ) + + +class AllowedDataFieldsMiddleware: + def resolve(self, next, root, info, **args): + try: + is_my_profile = ( + info.operation.selection_set.selections[0].name.value == "myProfile" + ) + node = info.parent_type.graphene_type + except AttributeError: + is_my_profile = False + node = None + + if is_my_profile and getattr(node, "check_allowed_data_fields", False): + field_name = to_snake_case(getattr(info, "field_name", "")) + + if not getattr(info.context, "service", False): + raise ServiceNotIdentifiedError("Service not identified") + + if not node.is_field_allowed_for_service(field_name, info.context.service): + raise FieldNotAllowedError("Field is not allowed for service.") + + return next(root, info, **args) diff --git a/open_city_profile/views.py b/open_city_profile/views.py index d373637e..5fae9184 100644 --- a/open_city_profile/views.py +++ b/open_city_profile/views.py @@ -12,6 +12,7 @@ CONNECTED_SERVICE_DELETION_FAILED_ERROR, CONNECTED_SERVICE_DELETION_NOT_ALLOWED_ERROR, DATA_CONFLICT_ERROR, + FIELD_NOT_ALLOWED_ERROR, GENERAL_ERROR, INSUFFICIENT_LOA_ERROR, INVALID_EMAIL_FORMAT_ERROR, @@ -34,6 +35,7 @@ ConnectedServiceDeletionFailedError, ConnectedServiceDeletionNotAllowedError, DataConflictError, + FieldNotAllowedError, InsufficientLoaError, InvalidEmailFormatError, MissingGDPRApiTokenError, @@ -74,6 +76,7 @@ ServiceConnectionDoesNotExist: SERVICE_CONNECTION_DOES_NOT_EXIST_ERROR, ServiceNotIdentifiedError: SERVICE_NOT_IDENTIFIED_ERROR, InsufficientLoaError: INSUFFICIENT_LOA_ERROR, + FieldNotAllowedError: FIELD_NOT_ALLOWED_ERROR, } sentry_ignored_errors = (