"""Route handlers for Profile endpoints.""" from flask import g from owsresponse import response from owsresponse.adaptors.flask import flaskify from permissions import config from permissions.api import app from permissions.connectors import redis from permissions.logic import profile, resource from permissions.utils.api_utils import validate_request_data from permissions.utils.cache_utils import bust_by_identity, get_resources_key from permissions.validations.schemas.resource_to_profile import ResourceToProfileSchema @app.route('/profile/uuid//resource/label/id/', methods=['HEAD']) def check_profile_access(profile_uuid, label_id): """Check if a profile has access to a specific resource.""" redis_key = '_'.join(['profile_resource_access_check', profile_uuid, 'label', label_id]) status_code = redis.get(redis_key) if status_code is None: status_code = resource.check_label_access_for_profile(profile_uuid, label_id) redis.set(redis_key, str(status_code)) return flaskify(response.Response(status=int(status_code))) @app.route( '/admin/profile-type//profile//resource/', methods=['GET'], ) @app.route( '/admin/profile-type//profile//resource/', methods=['GET'], defaults={'profile_id': 0}, ) @app.route( '/admin/profile//resource/', methods=['GET'], defaults={'profile_id': 0, 'profile_type': 'InsightsProfile'}, ) def get_resources_for_profile(profile_type, profile_id, resource_type, profile_uuid=None): """GET all resources or type resource_type for this profile. This is meant to be called from other microservices. Args: profile_type (str): Type of profile. profile_id (int): Profile Identifier. resource_type (str): Type of resource eg: product, artistinfo or all. profile_uuid (str): Optionally you can send only profile's 'uuid. """ redis_key = get_resources_key(profile_type, profile_uuid or profile_id, resource_type) cached_data = redis.get(redis_key) if cached_data: return cached_data if profile_uuid: result = resource.get_resources_for_profile_uuid(profile_uuid, resource_type) else: g.log.info(f'Using get_resources_for_profile with profile_id: {profile_type}:{profile_id}') result = resource.get_resources_for_profile(profile_type, profile_id, resource_type) if not result: return flaskify(result) return_result = { 'items': result.message, 'pagination': {'type': 'none', 'total_records': len(result.message)}, } redis.set(redis_key, return_result, config.REDIS_CACHE_TTL) return flaskify(response.Response(return_result)) @app.route( '/ows/profile///has-access-to/resource//', methods=['POST'], ) @app.route( '/ows/profile//has-access-to/resource//', methods=['POST'], defaults={'profile_id': 0, 'profile_type': 'InsightsProfile'}, ) @validate_request_data(ResourceToProfileSchema()) def add_resource_to_profile( profile_type, profile_id, resource_type, resource_id, deserialize_schema, profile_uuid=None ): """Give an existing profile access to an existing resources. Args: profile_type (str): Type of profile eg: ArtistProfile, LabelProfile. profile_id (int): Profile Identifier. resource_type (str): Type of resource eg: ArtistInfo, Product. resource_id (int): Resource Identifier. deserialize_schema (dict): field names mapped to deserialized values. profile_uuid (str): Optionally you can send only profile's 'uuid. Json body: dict: containing access roles for that relationship. Eg: { "roles": ["analytics"] } """ if not deserialize_schema['resource_id'] == '*': deserialize_schema['resource_id'] = int(resource_id) result = resource.add_resource_to_profile(deserialize_schema) if result: try: identity_uuids = profile.get_identities_by_profile( profile_type, profile_id, profile_uuid ) if identity_uuids: bust_by_identity(identity_uuids, resource_types=['all_admin']) except Exception as e: g.log.warning( f'Failed to bust identity all_admin cache for Profile Type {profile_type}, Profile Id {profile_id}, Profile UUID {profile_uuid}: {e}' ) return flaskify(result) @app.route( '/ows/profile///has-access-to/resource//', methods=['DELETE'], ) @app.route( '/ows/profile//has-access-to/resource//', methods=['DELETE'], defaults={'profile_id': 0, 'profile_type': 'InsightsProfile'}, ) @validate_request_data(ResourceToProfileSchema()) def delete_resource_to_profile( profile_type, profile_id, resource_type, resource_id, deserialize_schema, profile_uuid=None ): """Delete an existing relationship between a profile and a resources. Args: profile_type (str): Type of profile eg: ArtistProfile, LabelProfile. profile_id (int): Profile Identifier. resource_type (str): Type of resource eg: ArtistInfo, Product. resource_id (int): Resource Identifier. deserialize_schema (dict): field names mapped to deserialized values. profile_uuid (str): Optionally you can send only profile's 'uuid. """ if not deserialize_schema['resource_id'] == '*': deserialize_schema['resource_id'] = int(resource_id) return flaskify(resource.delete_resource_to_profile(deserialize_schema))