"""New neo4j resource access check handlers. These endpoints are - similar to the ones in handlers.py - better names, type hinting, reusable and more readable - stop gap endpoints before a proper PDP adoption """ from dataclasses import asdict from uuid import UUID from flask import g from owsrequest import error_response from owsresponse import response from owsresponse.adaptors.flask import flaskify from permissions.api import app from permissions.constants import constants from permissions.logic import ( subaccount as subaccount_logic, vendor as vendor_logic, ) from permissions.models import profile as profile_model from permissions.utils import api_utils @app.route('/v2/profile/self/vendors/direct-access', methods=['GET']) @api_utils.jwt_check def get_my_directly_accessible_vendors_by_profile() -> response.Response: """ Get all vendors that the authenticated profile has direct access to. This endpoint retrieves a list of all vendors to which the authenticated profile has direct access permissions. The endpoint requires a valid JWT token and the context type must be 'profile'. Authorization: Requires a valid JWT token with profile context Required Headers: Authorization: Bearer JWT token (required) Orchard-Profile-Type Orchard-Profile-Id Response: 200 OK: Returns a list of all accessible vendors { "vendors": [ {"vendor_uuid": "vendor_uuid_1", "vendor_id": 123}, {"vendor_uuid": "vendor_uuid_2", "vendor_id": 456}, ... ] } 401 Unauthorized: - If JWT token is missing or invalid 403 Forbidden: - If profile information is incomplete Notes: - The function validates that the request context_type is set to `profile`. - The function checks the profile specified in the request context. - Returns an empty list if the profile does not exist or has no Vendor access. - Will return Vendor * along with other vendors that the profile has direct access to. """ # ensure context_type is profile if g.request_context.context_type != constants.PROFILE_CONTEXT_TYPE: return flaskify(error_response.create_error_forbidden()) # get identity and profile identity_id = UUID(g.request_context.jwt_identity_id) profile_id = int(g.request_context.profile_id) profile_type = g.request_context.profile_type accessible_vendors = vendor_logic.get_directly_accessible_vendors_by_profile( identity_id=identity_id, profile_id=profile_id, profile_type=profile_type, ) return flaskify(response.Response({'vendors': [asdict(v) for v in accessible_vendors]})) @app.route('/v2/profile/self/all-label-access', methods=['GET']) def check_profile_all_label_access() -> response.Response: """ Check if the profile has access to all labels. This endpoint checks if the profile specified in the headers has access to all labels. It returns a boolean indicating whether the profile has such access. It returns false if the profile does not exist or has no access. It is meant to be a replacement endpoint for cypher access checks before a proper PDP adoption. Required Headers: Orchard-Identity-Id Orchard-Profile-Type Orchard-Profile-Id Response: 200 OK: Returns a boolean indicating access to all labels. { "has_access": true | false } """ # ensure context_type is profile if g.request_context.context_type != constants.PROFILE_CONTEXT_TYPE: return flaskify(error_response.create_error_forbidden()) # get identity and profile from request context. identity_id = UUID(g.request_context.identity_id) profile_id = int(g.request_context.profile_id) profile_type = g.request_context.profile_type has_access = profile_model.check_vendor_star_access_v2( identity_id=identity_id, profile_id=profile_id, profile_type=profile_type, ) return flaskify(response.Response({'has_access': has_access})) @app.route('/v2/profile/self/subaccounts/direct-access', methods=['GET']) @api_utils.jwt_check def get_my_directly_accessible_subaccounts_by_profile() -> response.Response: """ Get all subaccounts that the authenticated profile has direct access to. This endpoint retrieves a list of all subaccounts to which the authenticated profile has direct access permissions. The endpoint requires a valid JWT token and the context type must be 'profile'. Authorization: Requires a valid JWT token with profile context Required Headers: Authorization: Bearer JWT token (required) Orchard-Profile-Type Orchard-Profile-Id Response: 200 OK: Returns a list of all accessible subaccounts { "subaccounts": [ {"subaccount_uuid": "subaccount_uuid_1", "subaccount_id": 123}, {"subaccount_uuid": "subaccount_uuid_2", "subaccount_id": 456}, ... ] } 401 Unauthorized: - If JWT token is missing or invalid 403 Forbidden: - If profile information is incomplete Notes: - The function validates that the request context_type is set to `profile`. - The function checks the profile specified in the request context. - Returns an empty list if the profile does not exist or has no Subaccount access. """ # ensure context_type is profile if g.request_context.context_type != constants.PROFILE_CONTEXT_TYPE: return flaskify(error_response.create_error_forbidden()) # get identity and profile identity_id = UUID(g.request_context.jwt_identity_id) profile_id = int(g.request_context.profile_id) profile_type = g.request_context.profile_type accessible_subaccounts = subaccount_logic.get_directly_accessible_subaccounts_by_profile( identity_id=identity_id, profile_id=profile_id, profile_type=profile_type, ) return flaskify(response.Response({'subaccounts': [asdict(s) for s in accessible_subaccounts]}))