123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- import logging
- from flask import Response
- from memoization import cached
- from lakesuperior import env as lsenv
- from lakesuperior.api import query as qry_api
- from lakesuperior.api import resource as rsrc_api
- from lakesuperior.dictionaries.namespaces import ns_collection as nsc
- from rdflib import Literal
- from grayspread import store
- from grayspread.config import config
- from grayspread.store import txn_ctx
- logger = logging.getLogger(__name__)
- def uri_to_uid(uri):
- """ Convert a lsup URI to an internal UID. """
- return uri.replace(nsc['fcres'], '')
- # # # Blueprint helpers # # #
- def fmt_dimensions(rsrc):
- """
- Format a resource dimensions.
- Return:
- list: A list of tuples containig:
- - Literal rendition of the dimensions
- - Dictionary of numeric values to plug into drawing functions.
- The list is sorted alphabetically by the literal description.
- """
- dim_nodes = rsrc.imr[rsrc.uri: nsc['lii']['measurement']]
- dims = []
- for dnode in dim_nodes:
- dim_parts = []
- logger.info(f'Dim node: {dnode}')
- unit = rsrc.imr[dnode: nsc['lii']['unit']].pop()
- labels = rsrc.imr[dnode: nsc['skos']['prefLabel']]
- try:
- di = rsrc.imr[dnode: nsc['lii']['diameter']].pop()
- except KeyError:
- di = 0
- try:
- w = rsrc.imr[dnode: nsc['lii']['width']].pop()
- except KeyError:
- w = 0
- try:
- h = rsrc.imr[dnode: nsc['lii']['height']].pop()
- except KeyError:
- h = 0
- try:
- d = rsrc.imr[dnode: nsc['lii']['depth']].pop()
- except KeyError:
- d = 0
- dim_values = {
- 'w': float(w), 'h': float(h), 'd': float(d), 'di': float(di)}
- if di:
- dim_parts.append(f'Ø: {di} {unit}')
- if w:
- dim_parts.append(f'width: {w} {unit}')
- if h:
- dim_parts.append(f'height: {h} {unit}')
- if d:
- dim_parts.append(f'depth: {d} {unit}')
- for label in labels: # There should be one, but you never know...
- dims.append((
- (f'{label}: ' + '; '.join(dim_parts).capitalize()),
- dim_values
- ))
- return sorted(dims, key=lambda x: x[0])
- def inv_rel(rsrc, p):
- """
- Set of resources pointing to this resource based on predicate.
- """
- return rsrc.imr[:p:rsrc.uri]
- def get_values(rsrc, pred):
- """ Return a set of values for a resource predicate. """
- return {str(o) for o in rsrc.imr[rsrc.uri: pred]}
- def get_value(rsrc, pred):
- """ Return a single value for a resource predicate. """
- ret = rsrc.imr.value(pred)
- return str(ret) if ret else ''
- @cached(ttl=60)
- def link_meta(uri):
- """
- Get basic metadata for a resource to be used to build a hyperlink.
- Return:
- tuple: uid and preferred label.
- """
- rsrc = rsrc_api.get(uri_to_uid(uri))
- if get_lii_type(rsrc) == nsc['lii']['Document']:
- return (
- rsrc.uid,
- get_value(rsrc, nsc['skos'].prefLabel),
- rsrc.uid,
- )
- else:
- return (
- rsrc.uid,
- get_value(rsrc, nsc['skos'].prefLabel),
- get_value(rsrc, nsc['lii'].hasPreferredRepresentation).replace(
- nsc['fcres'], ''),
- )
- @cached(ttl=60)
- def type_meta(type_id):
- """
- Get metadata about a lii type (class) from a resource stored in LS.
- Args:
- type_id (str): Type ID i.e. class name, e.g. ``Artifact`` or ``Place``.
- """
- uris = qry_api.triple_match(p=nsc['owl'].sameAs, o=nsc['lii'][type_id])
- return rsrc_api.get(uri_to_uid(uris.pop()))
- def get_lii_type(rsrc):
- """
- Get main LII type for a resource.
- There should be only one.
- :rtype: URIRef
- """
- main_types = {nsc['lii'][t] for t in store.highlight_types}
- lii_types = store.get_lii_types(rsrc) & main_types
- if len(lii_types):
- # There should be only one!
- return lii_types.pop()
- @cached(ttl=60)
- def get_related_media(rsrc):
- """
- Get related media as set of ordered aggregation resources.
- """
- media = []
- for uri in get_values(rsrc, nsc['lii'].hasRelatedMedium):
- uid = uri_to_uid(uri)
- media.append((rsrc_api.get(uid), tuple(aggregation_list(uid))))
- from pprint import pformat
- logger.info(f'media: {pformat(media)}')
- return media
- @cached(ttl=60)
- def uid_from_local_uid(local_uid):
- """
- Get a resource by its local UID,
- """
- uri = qry_api.triple_match(
- p=nsc['lii'].localUid, o=Literal(local_uid)).pop()
- return uri.replace(nsc['fcres'], '')
- def aggregation_list(uid):
- """
- Build an ordered list of resources from an aggregation UID.
- """
- agg = rsrc_api.get(uid)
- ars = []
- px_uri = agg.imr.value(nsc['nav']['first'])
- while px_uri:
- ar_match = qry_api.triple_match(
- s=px_uri, p=nsc['ore'].proxyFor, return_full=True)
- ars.append(link_meta(ar_match.pop()[2]))
- px_match = qry_api.triple_match(
- s=px_uri, p=nsc['nav']['next'], return_full=True)
- px_uri = px_match.pop()[2] if px_match else None
- return ars
- def local_path(uid):
- """ Get the local file path of a LDP-NR relative to the root path. """
- rsrc = rsrc_api.get(uid)
- with txn_ctx():
- path = rsrc.local_path
- return path.replace(lsenv.app_globals.nonrdfly.root, '')
- def image_iiif_url(uid, params):
- """ Get full IIIF URL from a public image UID. """
- local_uid = local_path(uid)
- url = f'{config["iiif_image_root_url"]}{local_uid}/{params}'
- logger.info(f"IIIF URL: {url}")
- return url
- def stream(data, mimetype='application/octet-stream', headers={}):
- """ Stream out data from an incoming streaming request. """
- def _stream_contents(rsp):
- for chunk in rsp.iter_content(config["chunk_size"]):
- yield chunk
- return Response(_stream_contents(data), mimetype=mimetype, headers=headers)
|