""" Interface to the ows-track microservice. The model is responsible to make a call to a ows-track microservice. It makes a request to ows-track endpoints ('/track//', methods=['GET']) and returns a result of the request. """ import time from typing import Any from owsrequest import request from requests.exceptions import HTTPError from assets.constants import error as error_constants, service from assets.exceptions import TrackNotFound _cached_tracks: list[dict[str, Any]] = [] CACHE_TTL = 30 # 30 seconds def _clean_cached_tracks() -> None: """Clean overdue cached tracks.""" for i, item in enumerate(_cached_tracks): if item["created"] < time.time() - CACHE_TTL: _cached_tracks.pop(i) def _add_track_to_cache(track: dict[str, Any]) -> None: """Add track info to short cache. Args: track (dict): Track information. """ _cached_tracks.append( {"id": track.get("tuid", 0), "track": track, "created": time.time()} ) def _get_track_from_cache(track_id: int) -> dict[str, Any] | None: """Get track from cached tracks list by track id. Args: track_id (int): Unique track id. Returns: dict: Track info or None. """ _clean_cached_tracks() return next( (track["track"] for track in _cached_tracks if track["id"] == track_id), None ) def get_track_by_id(track_id: int, exclude: list[Any] | None = None) -> dict[str, Any]: """Get track details by track id. Args: track_id (int): Unique track id. exclude (list, optional): List of fields to exclude from response. Defaults to None. Returns: dict: Track details. """ exclude = exclude or [] track_details = _get_track_from_cache(track_id) if track_details is not None: return track_details resource = service.OWS_TRACK_BY_TRACK_ID.format(track_id=track_id) try: track_response = request.get( service.OWS_TRACK, resource, params={"exclude": ",".join(exclude)} ) track_response.raise_for_status() track_details = track_response.json() _add_track_to_cache(track_details) return track_details # type: ignore[no-any-return] except HTTPError as e: if e.response.status_code == 404: error_msg = f"{error_constants.ERROR_TRACK_NOT_FOUND} {track_id}" raise TrackNotFound(error_msg) from e raise def get_tracks_by_product_id(product_id: int) -> dict[str, Any]: """Get all track unique ids for product. Args: product_id (int): Product Id to get tracks. Returns: dict: product tracks info from ows-product. """ resource = service.OWS_TRACKS_BY_PRODUCT_ID.format(product_id=product_id) track_response = request.get(service.OWS_TRACK, resource) track_response.raise_for_status() return track_response.json() # type: ignore[no-any-return] def check_profile_track_access(profile_uuid: str, tuid: int) -> None: """Check profile track access.""" url = f"/profile/uuid/{profile_uuid}/resource/track/id/{tuid}" try: track_response = request.head(service.OWS_TRACK, url) track_response.raise_for_status() except HTTPError as e: if e.response.status_code == 404: raise TrackNotFound(error_constants.ERROR_TRACK_NOT_FOUND) from e raise