def get_mid(self, obj: SolrResult) -> str: req = self.context.get('request') cfg = self.context.get('config') manifest_id: str = obj.get('id') manifest_id_tmpl: str = cfg['templates']['manifest_id_tmpl'] return get_identifier(req, manifest_id, manifest_id_tmpl)
def get_manifests(self, obj: SolrResult) -> Optional[List]: coll_id: str = obj.get('collection_id') req = self.context.get('request') cfg = self.context.get('config') manager: SolrManager = SolrManager(SolrConnection) # The 'All' collection is for every object in the collection, so we # don't need to restrict it by collection. if coll_id == 'all': fq = ["type:object"] else: fq = ["type:object", f"all_collections_id_sm:{coll_id}"] sort: str = "institution_label_s asc, shelfmark_sort_ans asc" rows: int = 100 fl = ["id", "title_s", "full_shelfmark_s", "thumbnail_id"] manager.search("*:*", fq=fq, sort=sort, fl=fl, rows=rows) if manager.hits == 0: return None return CollectionManifest(manager.results, many=True, context={ 'request': req, 'config': cfg }).data
def get_collections(self, obj: SolrResult) -> Optional[List]: coll_id: str = obj.get('collection_id') req = self.context.get('request') cfg = self.context.get('config') manager: SolrManager = SolrManager(SolrConnection) fq: List = ["type:collection", f"parent_collection_id:{coll_id}"] fl: List = [ 'id', 'name_s', 'description_s', 'collection_id', 'parent_collection_id' ] sort: str = "name_s asc" rows: int = 100 manager.search("*:*", fq=fq, fl=fl, sort=sort, rows=rows) if manager.hits == 0: return None return CollectionCollection(manager.results, many=True, context={ 'request': req, 'config': cfg }).data
def get_cid(self, obj: SolrResult) -> str: req = self.context.get('request') cfg = self.context.get('config') tmpl: str = cfg['templates']['collection_id_tmpl'] cid: str = obj.get('collection_id') return get_identifier(req, cid, tmpl)
def get_id(self, obj: SolrResult) -> str: req = self.context.get('request') cfg = self.context.get('config') activity_create_id_tmpl: str = cfg['templates'][ 'activitystream_create_id_tmpl'] return get_identifier(req, obj.get('id'), activity_create_id_tmpl)
def get_service(self, obj: SolrResult) -> Dict: req = self.context.get('request') cfg = self.context.get('config') image_tmpl = cfg['templates']['image_id_tmpl'] identifier = re.sub(IMAGE_ID_SUB, "", obj.get("id")) image_id = get_identifier(req, identifier, image_tmpl) return {"type": "ImageService2", "profile": "level1", "id": image_id}
def get_aid(self, obj: SolrResult) -> str: req = self.context.get('request') cfg = self.context.get('config') annotation_tmpl: str = cfg['templates']['annotation_id_tmpl'] # The substitution here is only needed for image annotations, but won't affect other annotations annotation_id: str = re.sub(IMAGE_ID_SUB, "", obj.get("id")) return get_identifier(req, annotation_id, annotation_tmpl)
def get_required_statement(self, obj: SolrResult) -> Dict: return { "label": { "en": ["Terms of Use"] }, "value": { "en": [obj.get("use_terms_sni", None)] } }
def get_cid(self, obj: SolrResult) -> str: req = self.context.get('request') cfg = self.context.get('config') canvas_tmpl = cfg['templates']['canvas_id_tmpl'] # Surfaces have the suffix "_surface" in Solr. Strip it off for this identifier canvas_id = re.sub(SURFACE_ID_SUB, "", obj.get("id")) return get_identifier(req, canvas_id, canvas_tmpl)
def get_iid(self, obj: SolrResult) -> str: cfg = self.context.get('config') req = self.context.get('request') image_tmpl = cfg['templates']['image_id_tmpl'] # Images have the suffix "_image" in Solr. identifier = re.sub(IMAGE_ID_SUB, "", obj.get("id")) return get_identifier(req, identifier, image_tmpl) # type: ignore
def get_metadata(self, obj: SolrResult) -> Optional[List[Dict]]: # Talbot manifests are a bit different, so exclude their metadata if 'talbot' in obj.get('all_collections_id_sm', []): # type: ignore return None req = self.context.get('request') cfg = self.context.get('config') tmpl: str = cfg['templates']['digital_bodleian_permalink_tmpl'] ident: str = get_identifier(req, obj.get('id'), tmpl) val: str = '<span><a href="{0}">View on Digital Bodleian</a></span>'.format( ident) metadata: List = [{"label": "Homepage", "value": val}] metadata += get_links(obj, 2) metadata += v2_metadata_block(obj) return metadata
def get_ranges(self, obj: SolrResult) -> Optional[List]: hierarchy = self.context.get('hierarchy') wk_id = obj.get("work_id") # If the work ID is not in the hierarchy, it contains # a list of canvases; return None. if wk_id not in hierarchy: return None return hierarchy[wk_id]
def get_width(self, obj: SolrResult) -> int: """ Width and Height are not stored on the canvas, but on the child documents. Assume that the first child document, if there is one, contains the width/height for the canvas. """ if "_childDocuments_" not in obj: return 0 return obj.get('_childDocuments_')[0]['width_i']
def get_aid(self, obj: SolrResult) -> str: req = self.context.get('request') cfg = self.context.get('config') annopage_tmpl: str = cfg['templates']['annopage_id_tmpl'] # Surfaces have the suffix "_surface" in Solr. Strip it off for this identifier # this isn't necessary for annotationpage ids, but also won't affect them annopage_id: str = re.sub(SURFACE_ID_SUB, "", obj.get("id")) return get_identifier(req, annopage_id, annopage_tmpl)
def get_height(self, obj: SolrResult) -> int: """ See the comment for width above. :param obj: A Solr result :return: An integer representing the height of the canvas. """ if "_childDocuments_" not in obj: return 0 return obj.get("_childDocuments_")[0]['height_i']
def get_viewing_hint(self, obj: SolrResult) -> str: """ The viewing types are controlled in the silo indexer; returns 'paged' by default :param obj: :return: """ vtype: str = obj.get('viewing_type_s') if vtype and vtype in ["map", "sheet", "binding", "photo"]: return "individuals" return "paged"
def get_service(self, obj: SolrResult) -> Dict: req = self.context.get('request') cfg = self.context.get('config') image_tmpl = cfg['templates']['image_id_tmpl'] identifier = re.sub(IMAGE_ID_SUB, "", obj.get("id")) image_id = get_identifier(req, identifier, image_tmpl) # type: ignore return { "@context": "http://iiif.io/api/image/2/context.json", "profile": "http://iiif.io/api/image/2/level1.json", "@id": image_id }
def get_canvases(self, obj: SolrResult) -> Optional[List]: hierarchy = self.context.get('hierarchy') wk_id = obj.get("work_id") # If the work id is in the hierarchy, this contains # a list of ranges; return None. if wk_id in hierarchy: return None req = self.context.get('request') cfg = self.context.get('config') surfaces: List = obj.get('surfaces_sm') canvas_tmpl: str = cfg['templates']['canvas_id_tmpl'] ret: List = [] for s in surfaces: ret.append( get_identifier(req, re.sub(SURFACE_ID_SUB, "", s), canvas_tmpl)) return ret
def get_width(self, obj: SolrResult) -> int: """ Width and Height are required. If (for some reason) there is no image attached to this canvas then return a 0. This will allow manifest parsers to load the manifest so that any correct images will still be shown. :param obj: A Solr result :return: An integer representing the width of the canvas. """ if "_childDocuments_" not in obj: return 0 return obj.get('_childDocuments_')[0]['width_i']
def get_items(self, obj: SolrResult) -> List: """ Gets a list of the child items. In v3 manifests this will either be Manifest objects or Collection objects. !!! NB: A collection will ONLY have manifests or Collections. The Solr index does not support mixed manifest and sub-collections !!! Two Solr queries are necessary to determine whether what is being requested is a parent collection (in which case the parent_collection_id field will match the requested path) OR a set of Manifests (in which case the first query will return 0 results, and then we re-query for the list of objects.) :param obj: A dict representing the Solr record for that collection. :return: A list of objects for the `items` array in the Collection. """ req = self.context.get('request') cfg = self.context.get('config') manager: SolrManager = SolrManager(SolrConnection) coll_id: str = obj.get('collection_id') # first try to retrieve sub-collections (collections for which this is a parent) fq = ["type:collection", f"parent_collection_id:{coll_id}"] fl = ["id", "name_s", "description_s", "type", "collection_id"] rows: int = 100 manager.search("*:*", fq=fq, fl=fl, rows=rows, sort="name_s asc") if manager.hits > 0: # bingo! it was a request for a sub-collection. return CollectionCollection(manager.results, many=True, context={ 'request': req, 'config': cfg }).data # oh well; retrieve the manifest objects. fq = ["type:object", f"all_collections_id_sm:{coll_id}"] fl = ["id", "title_s", "full_shelfmark_s", "type"] sort = "institution_label_s asc, shelfmark_sort_ans asc" manager.search("*:*", fq=fq, fl=fl, rows=rows, sort=sort) return CollectionManifest(manager.results, many=True, context={ 'request': req, 'config': cfg }).data
def get_items(self, obj: SolrResult) -> List: # If the object has a list of child objects, # it is a range; if not, it is a canvas. req = self.context.get('request') cfg = self.context.get('config') direct = self.context.get('direct_request') if obj.get('_children'): return StructureRangeItem(obj['_children'], context={'request': req, 'config': cfg, 'direct_request': direct}, many=True).data return StructureCanvasItem(obj['surfaces_sm'], context={'request': req, 'config': cfg, 'direct_request': direct}, many=True).data
def get_within(self, obj: SolrResult) -> Optional[List]: """When requested directly, give a within parameter to point back to the parent manuscript. """ direct_request: bool = self.context.get('direct_request') if not direct_request: return None req = self.context.get('request') cfg = self.context.get('config') manifest_tmpl: str = cfg['templates']['manifest_id_tmpl'] wid: str = get_identifier(req, obj.get('object_id'), manifest_tmpl) return [{"id": wid, "type": "Manifest"}]
def get_resource(self, obj: SolrResult) -> List[Dict]: resources = [] if not obj.get('_childDocuments_'): # There's no text associated with this annotation # Mirador 2 returns 'undefined' as the text if no resources are supplied, so we supply an empty one return [{ "@type": "dctypes:Text", "chars": "", "format": "text/html" }] child_docs: List = obj['_childDocuments_'] for body in child_docs: chars = f'<p dir="{body["direction_s"]}">{html.escape(body["text_s"])}</p>' resources.append({ "@type": "dctypes:Text", "chars": chars, "format": "text/html", "language": body['language_s'] }) if len(child_docs) > 1: # Add a final item with all of the bodies concatenated. # This is to work around a Mirador 2 bug (https://github.com/ProjectMirador/mirador/issues/2663) # which only shows the last body. # Once this is fixed or we move to Mirador 3 we should remove this. concatenated_chars = "" for body in child_docs: header = LANGUAGE_TO_HEADER_MAP.get(body['language_s']) if header: # mirador 2 doesn't display h2 etc tags in annotations, so we use strong instead paragraph_contents = f'<strong>{header}</strong><br/>{html.escape(body["text_s"])}' else: paragraph_contents = html.escape(body["text_s"]) concatenated_chars += f'<p dir="{body["direction_s"]}">{paragraph_contents}</p>' resources.append({ "@type": "dctypes:Text", "chars": concatenated_chars, "format": "text/html" }) return resources
def get_part_of(self, obj: SolrResult) -> Optional[List]: colls: List[str] = obj.get('all_collections_link_smni') if not colls: return None req = self.context.get('request') cfg = self.context.get('config') tmpl: str = cfg['templates']['collection_id_tmpl'] ret: List[Dict] = [] for collection in colls: cid, label = collection.split("|") ret.append({ "id": get_identifier(req, cid, tmpl), "type": "Collection", "label": { "en": [label] } }) return ret
def get_logo(self, obj: SolrResult) -> Optional[Dict]: logo_uuid: str = obj.get("logo_id") if not logo_uuid: return None req = self.context.get('request') cfg = self.context.get('config') image_tmpl: str = cfg['templates']['image_id_tmpl'] thumbsize: str = cfg['common']['thumbsize'] logo_ident: str = get_identifier(req, logo_uuid, image_tmpl) logo_service: Dict = { "@id": f"{logo_ident}/full/{thumbsize},/0/default.jpg", "service": { "@context": "http://iiif.io/api/image/2/context.json", "profile": "http://iiif.io/api/image/2/level1.json", "@id": logo_ident } } return logo_service
def get_on(self, obj: SolrResult) -> Union[str, List[Dict]]: """ Get the base canvas uri using the BaseAnnotation super class's implementation of get_on :param obj: :return: the uri for the canvas this annotation is attached to, with an xywh parameter to show what region the annotation applies to """ target_uri = super().get_on(obj) if not obj.get('svg_s'): return f"{target_uri}#xywh={obj['ulx_i']},{obj['uly_i']},{obj['width_i']},{obj['height_i']}" req = self.context.get('request') cfg = self.context.get('config') manifest_tmpl = cfg['templates']['manifest_id_tmpl'] manifest_uri = get_identifier(req, obj['object_id'], manifest_tmpl) return [{ "@type": "oa:SpecificResource", "full": target_uri, "selector": { "@type": "oa:Choice", "default": { "@type": "oa:FragmentSelector", "value": f"xywh={obj['ulx_i']},{obj['uly_i']},{obj['width_i']},{obj['height_i']}" }, "item": { "@type": "oa:SvgSelector", "value": obj['svg_s'] } }, "within": { "@id": manifest_uri, "@type": "sc:Manifest" } }]
def get_thumbnail(self, obj: SolrResult) -> Optional[List]: image_uuid: str = obj.get('thumbnail_id') if not image_uuid: return None req = self.context.get('request') cfg = self.context.get('config') image_tmpl: str = cfg['templates']['image_id_tmpl'] image_ident: str = get_identifier(req, image_uuid, image_tmpl) thumbsize: str = cfg['common']['thumbsize'] thumb_service: List = [{ "@id": f"{image_ident}/full/{thumbsize},/0/default.jpg", "service": { "type": "ImageService2", "profile": "level1", "@id": image_ident } }] return thumb_service
def get_logo(self, obj: SolrResult) -> Optional[List]: logo_uuid: str = obj.get("logo_id") if not logo_uuid: return None req = self.context.get('request') cfg = self.context.get('config') image_tmpl: str = cfg['templates']['image_id_tmpl'] logo_ident: str = get_identifier(req, logo_uuid, image_tmpl) thumbsize: str = cfg['common']['thumbsize'] logo_service: List = [{ "id": f"{logo_ident}/full/{thumbsize},/0/default.jpg", "type": "Image", "service": { "type": "ImageService2", "profile": "level1", "id": logo_ident } }] return logo_service
def get_structures(self, obj: SolrResult) -> Optional[List[Dict]]: return create_v2_structures(self.context.get('request'), obj.get('id'), self.context.get('config'))
def get_viewing_hint(self, obj: SolrResult) -> Optional[str]: if not obj.get("parent_work_id"): return "top" return None