"""Logic for permissions.""" from owsrequest.constants import headers as owsrequest_headers from sound_recordings import features from sound_recordings.config import FEED_IDS from sound_recordings.connectors import redis from sound_recordings.constants import cache as cache_constants from sound_recordings.services import ows_permissions from sound_recordings.services.ows_permissions import ( ARTIST_INFO_RESOURCE, LABEL_RESOURCE, SUBACCOUNT_RESOURCE_TYPE, VENDOR_RESOURCE_TYPE, ) from sound_recordings.utils.cache import create_permissions_key ENCODING = "utf-8" DELIMITER = "," def _encode_int_array(array): """Decode an array of integers from a byte array.""" return DELIMITER.join(map(lambda x: str(x), array)).encode(ENCODING) def _decode_int_array(bytes_): """Encode an array of integers into a byte array.""" return list( map( lambda x: None if x == "None" else int(x), bytes_.decode(ENCODING).split(DELIMITER), ) ) def get_artist_info_ids(profile_type, profile_id): """Return artist info ids for a given profile type and id. Args: profile_type (str): The profile type. profile_id (int): The profile id. Returns: array (int): An array of accessible artist profile ids """ if profile_type is None or profile_id is None: return [] redis_key = create_permissions_key(profile_type, profile_id, ARTIST_INFO_RESOURCE) result = redis.client.get(redis_key) if result: return _decode_int_array(result) response = ows_permissions.get_artist_info_resources(profile_type, profile_id) if not response: return [] artist_info_ids = list(map(lambda item: item["id"], response.message["items"])) redis.client.set( redis_key, _encode_int_array(artist_info_ids), ex=cache_constants.PERMISSIONS_CACHE_TTL, ) return artist_info_ids def get_vendor_and_subaccount(profile_type, profile_id): """Return vendor_id and subaccount_id for a provided profile. Args: profile_type (str): The profile type. profile_id (int): The profile id. Returns: (int, int): An tuple of ordered vendor_id, subaccount_id """ if profile_type is None or profile_id is None: return None, None redis_key = create_permissions_key(profile_type, profile_id, LABEL_RESOURCE) result = redis.client.get(redis_key) if result: vendor_subaccount_pair = _decode_int_array(result) return vendor_subaccount_pair[0], vendor_subaccount_pair[1] response = ows_permissions.get_label_resources(profile_type, profile_id) # Empty response, so no vendor_id, subaccount_id if not response: return None, None # Pull the first reference to a vendor or subaccount resource from result resource = next( ( item for item in response.message["items"] if item["type"].lower() in (SUBACCOUNT_RESOURCE_TYPE.lower(), VENDOR_RESOURCE_TYPE.lower()) ), None, ) # If no vendor or subaccount resources, return no vendor_id, subaccount_id if not resource: return None, None # If the resource is a vendor, return only vendor_id if resource["type"] == VENDOR_RESOURCE_TYPE: vendor_subaccount_pair = [resource["id"], None] redis.client.set( redis_key, _encode_int_array(vendor_subaccount_pair), ex=cache_constants.PERMISSIONS_CACHE_TTL, ) return vendor_subaccount_pair[0], vendor_subaccount_pair[1] # Return vendor_id, subaccount_id vendor_subaccount_pair = [None, resource["id"]] redis.client.set( redis_key, _encode_int_array(vendor_subaccount_pair), ex=cache_constants.PERMISSIONS_CACHE_TTL, ) return vendor_subaccount_pair[0], vendor_subaccount_pair[1] def get_permissions_filter(request_context, filter_by_feed_ids=True, **kwargs): """Return a dict containing resource permissions based on request context. Args: request_context (RequestContext): request context filter_by_feed_ids (bool): If True, add a list of available to this user feed ids to the permissions filter. Returns: dict: a dict containing resources the user has access to """ feed_ids = [] if filter_by_feed_ids: available_feeds = FEED_IDS[:] feed_ids = available_feeds result = { "artist_ids": None, "label_ids": None, "subaccount_ids": None, "label_participant_ids": None, "feed_ids": feed_ids, } service_access_profile_types = [ owsrequest_headers.PROFILE_TYPE_INSIGHTS, owsrequest_headers.PROFILE_TYPE_PUBLISHING, owsrequest_headers.PROFILE_TYPE_CONTENT, ] if request_context.context_type != owsrequest_headers.CONTEXT_TYPE_PROFILE: return result profile_type = request_context.profile_type profile_id = request_context.profile_id if profile_type == owsrequest_headers.PROFILE_TYPE_ARTIST: result["artist_ids"] = get_artist_info_ids(profile_type, profile_id) return result elif profile_type == owsrequest_headers.PROFILE_TYPE_LABEL: vendor_id, subaccount_id = get_vendor_and_subaccount(profile_type, profile_id) result["label_ids"] = [vendor_id] result["subaccount_ids"] = [subaccount_id] if subaccount_id else None return result elif profile_type in service_access_profile_types: profile_permissions = get_all_permissions_for_profile(profile_type, profile_id) profile_permissions.update({"feed_ids": feed_ids}) return {**result, **profile_permissions} return result def _parse_profile_permissions(permissions): if not permissions or not permissions.get("items"): return None, None, None, None artist_ids = [] label_ids = [] subaccount_ids = [] label_participant_ids = [] for item in permissions.get("items"): item_type = item.get("type") if item_type == "ArtistInfo": artist_ids.append(item.get("id")) elif item_type == "Vendor": if item.get("id") == "*": return [], [], [], [] label_ids.append(item.get("id")) elif item_type in ["Subaccount", "SubAccount"]: subaccount_ids.append(item.get("id")) elif item_type == "LabelParticipant": label_participant_ids.append(item.get("id")) if not any([artist_ids, label_ids, subaccount_ids, label_participant_ids]): return None, None, None, None return artist_ids, label_ids, subaccount_ids, label_participant_ids def get_all_permissions_for_profile(profile_type, profile_id): """Return a dict containing resource permissions based on insighs profile. Args: profile_type (str): The profile type. profile_id (int): The profile id. Returns: dict: a dict containing resources the user has access to """ if profile_id is None or profile_type is None: return { "artist_ids": None, "label_ids": None, "subaccount_ids": None, "label_participant_ids": None, } response = ows_permissions.get_all_resources(profile_type, profile_id) ( artist_ids, label_ids, subaccount_ids, label_participant_ids, ) = _parse_profile_permissions(response.message) return { "artist_ids": artist_ids, "label_ids": label_ids, "subaccount_ids": subaccount_ids, "label_participant_ids": label_participant_ids, }