Esempio n. 1
0
def _remove_iso_metadata(metadata: Metadata, md_links: list,
                         existing_iso_links: list):
    """ Remove iso metadata that is not found in the newer md_links list but still lives in the persisted existing_iso_links list

    Args:
        metadata (Metadata): The edited metadata
        md_links (list): The new iso metadata links
        existing_iso_links (list): The existing metadata links, related to the metadata object
    Returns:
         nothing
    """
    # remove iso metadata from capabilities document
    rel_md = metadata
    service_type = metadata.service_type
    if not metadata.is_root():
        if service_type == OGCServiceEnum.WMS:
            rel_md = metadata.service.parent_service.metadata
        elif service_type == OGCServiceEnum.WFS:
            rel_md = metadata.featuretype.parent_service.metadata
    cap_doc = Document.objects.get(
        metadata=rel_md,
        is_original=False,
        document_type=DocumentEnum.CAPABILITY.value,
    )
    cap_doc_txt = cap_doc.content
    xml_cap_obj = xml_helper.parse_xml(cap_doc_txt).getroot()

    # if there are links in existing_iso_links that do not show up in md_links -> remove them
    for link in existing_iso_links:
        if link not in md_links:
            missing_md = metadata.get_related_metadatas(
                filters={'to_metadatas__to_metadata__metadata_url': link})
            missing_md.delete()
            # remove from capabilities
            xml_iso_element = xml_helper.find_element_where_attr(
                xml_cap_obj, "xlink:href", link)
            for elem in xml_iso_element:
                xml_helper.remove_element(elem)
    cap_doc_txt = xml_helper.xml_to_string(xml_cap_obj)
    cap_doc.content = cap_doc_txt
    cap_doc.save()
Esempio n. 2
0
def _overwrite_capabilities_keywords(xml_obj: _Element, metadata: Metadata,
                                     _type: str):
    """ Overwrites existing capabilities keywords with metadata editor input

    Args:
        xml_obj (_Element): The parent xml object which holds the KeywordList element
        metadata (Metadata): The metadata object which holds the edited keyword data
        _type (str): Defines if this is a wms or wfs
    Returns:
         nothing
    """
    ns_prefix = ""
    keyword_container_tag = "KeywordList"
    keyword_prefix = ""
    keyword_ns_map = {}

    if _type == 'wfs':
        ns_keyword_prefix_s = "ows"
        ns_prefix = "wfs:"
        if metadata.is_root():
            # for the <ows:ServiceIdentification> element we need the prefix "ows:"
            ns_prefix = "ows:"
        keyword_container_tag = "Keywords"
        keyword_prefix = "{" + XML_NAMESPACES[ns_keyword_prefix_s] + "}"
        keyword_ns_map[ns_keyword_prefix_s] = XML_NAMESPACES[
            ns_keyword_prefix_s]

    xml_keywords_list_obj = xml_helper.try_get_single_element_from_xml(
        "./" + GENERIC_NAMESPACE_TEMPLATE.format(keyword_container_tag),
        xml_obj)

    if xml_keywords_list_obj is None:
        # there are no keywords in this capabilities for this element yet
        # we need to add an element first!
        try:
            xml_keywords_list_obj = xml_helper.create_subelement(
                xml_obj,
                "{}{}".format(keyword_prefix, keyword_container_tag),
                after="{}Abstract".format(ns_prefix),
                nsmap=keyword_ns_map)
        except (TypeError, ValueError) as e:
            # there seems to be no <Abstract> element. We add simply after <Title> and also create a new Abstract element
            xml_keywords_list_obj = xml_helper.create_subelement(
                xml_obj,
                "{}{}".format(keyword_prefix, keyword_container_tag),
                after="{}Title".format(ns_prefix))
            xml_helper.create_subelement(xml_obj,
                                         "{}".format("Abstract"),
                                         after="{}Title".format(ns_prefix))

    xml_keywords_objs = xml_helper.try_get_element_from_xml(
        "./" + GENERIC_NAMESPACE_TEMPLATE.format("Keyword"),
        xml_keywords_list_obj) or []

    # first remove all persisted keywords
    for kw in xml_keywords_objs:
        xml_keywords_list_obj.remove(kw)

    # then add all edited
    for kw in metadata.keywords.all():
        xml_keyword = xml_helper.create_subelement(
            xml_keywords_list_obj,
            "{}Keyword".format(keyword_prefix),
            nsmap=keyword_ns_map)
        xml_helper.write_text_to_element(xml_keyword, txt=kw.keyword)
Esempio n. 3
0
def overwrite_capabilities_document(metadata: Metadata):
    """ Overwrites the capabilities document which is related to the provided metadata.

    If a subelement of a service has been edited, the service root capabilities will be changed since this is the
    most requested document of the service.
    All subelements capabilities documents above the edited element will be reset to None and cached documents will be
    cleared. This forces an automatic creation of the correct capabilities on the next request for these elements,
    which will result in correct information about the edited subelement.

    Args:
        metadata (Metadata):
    Returns:
         nothing
    """
    is_root = metadata.is_root()
    if is_root:
        parent_metadata = metadata
    elif metadata.is_metadata_type(MetadataEnum.LAYER):
        parent_metadata = metadata.service.parent_service.metadata
    elif metadata.is_metadata_type(MetadataEnum.FEATURETYPE):
        parent_metadata = metadata.featuretype.parent_service.metadata

    # Make sure the Document record already exist by fetching the current capability xml
    # This is a little trick to auto-generate Document records which did not exist before!
    parent_metadata.get_current_capability_xml(
        parent_metadata.get_service_version().value)
    cap_doc = Document.objects.get(
        metadata=parent_metadata,
        document_type=DocumentEnum.CAPABILITY.value,
        is_original=False,
    )

    # overwrite all editable data
    xml_obj_root = xml_helper.parse_xml(cap_doc.content)

    # find matching xml element in xml doc
    _type = metadata.service_type.value
    _version = metadata.get_service_version()

    identifier = metadata.identifier
    if is_root:
        if metadata.is_service_type(OGCServiceEnum.WFS):
            if _version is OGCServiceVersionEnum.V_2_0_0 or _version is OGCServiceVersionEnum.V_2_0_2:
                XML_NAMESPACES["wfs"] = "http://www.opengis.net/wfs/2.0"
                XML_NAMESPACES["ows"] = "http://www.opengis.net/ows/1.1"
                XML_NAMESPACES["fes"] = "http://www.opengis.net/fes/2.0"
                XML_NAMESPACES["default"] = XML_NAMESPACES["wfs"]
            identifier = metadata.title

    xml_obj = xml_helper.find_element_where_text(xml_obj_root, txt=identifier)
    if len(xml_obj) > 0:
        xml_obj = xml_obj[0]

    # handle keywords
    _overwrite_capabilities_keywords(xml_obj, metadata, _type)

    # handle iso metadata links
    _overwrite_capabilities_iso_metadata_links(xml_obj, metadata)

    # overwrite data
    _overwrite_capabilities_data(xml_obj, metadata)

    # write xml back to Document record
    # Remove service_metadata_document as well, so it needs to be generated again!
    xml = xml_helper.xml_to_string(xml_obj_root)
    cap_doc.content = xml
    cap_doc.save()
    service_metadata_doc = Document.objects.filter(
        metadata=metadata,
        document_type=DocumentEnum.METADATA.value,
    )
    service_metadata_doc.delete()

    # Delete all cached documents, which holds old state!
    metadata.clear_cached_documents()

    # Delete all cached documents of root service, which holds old state!
    parent_metadata.clear_cached_documents()

    # Remove existing document contents from upper elements (children of root element), which holds old state!
    metadata.clear_upper_element_capabilities(clear_self_too=True)
Esempio n. 4
0
def get_resource_capabilities(request: HttpRequest, md: Metadata):
    """ Logic for retrieving a capabilities document.

    If no capabilities document can be provided by the given parameter, a fallback document will be returned.

    Args:
        request:
        md:
    Returns:

    """
    from service.tasks import async_increase_hits
    stored_version = md.get_service_version().value
    # move increasing hits to background process to speed up response time!
    # todo: after refactoring of md.increase_hits() maybe we don't need to start async tasks... test it!!!
    async_increase_hits.delay(md.id)

    if not md.is_active:
        return HttpResponse(content=SERVICE_DISABLED, status=423)

    # check that we have the requested version in our database
    version_param = None
    version_tag = None

    request_param = None
    request_tag = None

    use_fallback = None

    for k, v in request.GET.dict().items():
        if k.upper() == "VERSION":
            version_param = v
            version_tag = k
        elif k.upper() == "REQUEST":
            request_param = v
            request_tag = k
        elif k.upper() == "FALLBACK":
            use_fallback = resolve_boolean_attribute_val(v)

    # No version parameter has been provided by the request - we simply use the one we have.
    if version_param is None or len(version_param) == 0:
        version_param = stored_version

    if version_param not in [data.value for data in OGCServiceVersionEnum]:
        # version number not valid
        return HttpResponse(content=PARAMETER_ERROR.format(version_tag), status=404)

    elif request_param is not None and request_param != OGCOperationEnum.GET_CAPABILITIES.value:
        # request not valid
        return HttpResponse(content=PARAMETER_ERROR.format(request_tag), status=404)

    else:
        pass

    if md.is_catalogue_metadata:
        doc = md.get_remote_original_capabilities_document(version_param)

    elif stored_version == version_param or use_fallback is True or not md.is_root():
        # This is the case if
        # 1) a version is requested, which we have in our database
        # 2) the fallback parameter is set explicitly
        # 3) a subelement is requested, which normally do not have capability documents

        # We can check the cache for this document or we need to generate it!
        doc = md.get_current_capability_xml(version_param)
    else:
        # we have to fetch the remote document
        # fetch the requested capabilities document from remote - we do not provide this as our default (registered) one
        xml = md.get_remote_original_capabilities_document(version_param)
        tmp = xml_helper.parse_xml(xml)

        if tmp is None:
            raise ValueError("No xml document was retrieved. Content was :'{}'".format(xml))
        # we fake the persisted service version, so the document setters will change the correct elements in the xml
        # md.service.service_type.version = version_param
        doc = Document(
            content=xml,
            metadata=md,
            document_type=DocumentEnum.CAPABILITY.value,
            is_original=True
        )
        doc.set_capabilities_secured(auto_save=False)

        if md.use_proxy_uri:
            doc.set_proxy(True, auto_save=False, force_version=version_param)
        doc = doc.content

    return doc