Exemple #1
0
    def _create_additional_records(self, service: Service, metadata: Metadata,
                                   group: MrMapGroup):
        """ Creates additional records like linked service metadata, keywords or MimeTypes/Formats

        Args:
            service (Service): The service record
            metadata (Metadata): THe metadata record
        Returns:

        """
        # Keywords
        for kw in self.service_identification_keywords:
            if kw is None:
                continue
            keyword = Keyword.objects.get_or_create(keyword=kw)[0]
            metadata.keywords.add(keyword)

        # MimeTypes / Formats
        for operation, formats in self.operation_format_map.items():
            for format in formats:
                mime_type = MimeType.objects.get_or_create(operation=operation,
                                                           mime_type=format,
                                                           created_by=group)[0]
                metadata.formats.add(mime_type)

        # Check for linked service metadata that might be found during parsing
        if self.linked_service_metadata is not None:
            service.linked_service_metadata = self.linked_service_metadata.to_db_model(
                MetadataEnum.SERVICE.value, created_by=metadata.created_by)
            metadata.add_metadata_relation(
                to_metadata=service.linked_service_metadata,
                relation_type=MetadataRelationEnum.VISUALIZES.value,
                origin=ResourceOriginEnum.CAPABILITIES.value)
Exemple #2
0
def _add_iso_metadata(metadata: Metadata, md_links: list,
                      existing_iso_links: list):
    """ Adds iso metadata that is found in the newer md_links list but not 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
    """
    # iterate over all links from the form and check if we need to persist them
    for link in md_links:
        if len(link) == 0:
            continue
        # check if this is already an existing uri and skip if so
        if link in existing_iso_links:
            continue
        # ... otherwise create a new iso metadata object
        iso_md = ISOMetadata(link, ResourceOriginEnum.EDITOR.value)
        iso_md = iso_md.to_db_model(created_by=metadata.created_by)
        iso_md.save()
        metadata.add_metadata_relation(
            to_metadata=iso_md,
            origin=iso_md.origin,
            relation_type=MetadataRelationEnum.DESCRIBES.value)
Exemple #3
0
    def done(self, form_list, **kwargs):
        """ Iterates over all forms and fills the Metadata/Dataset records accordingly

        Args:
            form_list (FormList): An iterable list of forms
            kwargs:
        Returns:

        """
        # Create instances
        self.metadata = Metadata()
        self.metadata.metadata_type = MetadataEnum.DATASET.value
        self.metadata.is_active = True

        self.dataset = Dataset()
        self.dataset.is_active = True
        self.dataset.md_identifier_code = self.metadata.identifier
        self.dataset.metadata_standard_name = "ISO 19115 Geographic information - Metadata"
        self.dataset.metadata_standard_version = "ISO 19115:2003(E)"

        # Pre-save objects to be able to add M2M relations
        self.metadata.save()
        self.metadata.identifier = self.metadata.id
        self.dataset.metadata = self.metadata
        self.dataset.save()
        self.metadata.metadata_url = reverse("resource:get-dataset-metadata",
                                             args=(self.dataset.id, ))

        return super().done(form_list=form_list, **kwargs)
Exemple #4
0
    def _fill_metadata_dataset_identification_form(data: dict, metadata: Metadata, dataset: Dataset, user: MrMapUser):
        """ Fills form data into Metadata/Dataset records

        Args:
            data (dict): Cleaned form data
            metadata (dict): The metadata record
            dataset (dict): The dataset record
            user: The performing user
        Returns:

        """
        metadata.title = data.get("title", None)
        metadata.abstract = data.get("abstract", None)
        metadata.created = data.get("date_stamp", None)
        metadata.created_by = data.get("created_by", None)

        dataset.language_code = data.get("language_code", None)
        dataset.character_set_code = data.get("character_set_code", None)
        dataset.date_stamp = data.get("date_stamp", None)

        ref_systems = data.get("reference_system", [])
        metadata.reference_system.clear()
        for ref_system in ref_systems:
            metadata.reference_system.add(ref_system)

        additional_related_objects = data.get("additional_related_objects", [])
        MetadataRelation.objects.filter(to_metadata=metadata, origin=ResourceOriginEnum.EDITOR.value).delete()
        for additional_object in additional_related_objects:
            additional_object.add_metadata_relation(to_metadata=metadata,
                                                    relation_type=MetadataRelationEnum.DESCRIBES.value,
                                                    internal=True,
                                                    origin=ResourceOriginEnum.EDITOR.value)
Exemple #5
0
    def _fill_metadata_dataset_licence_form(data: dict, metadata: Metadata, dataset: Dataset, user: MrMapUser):
        """ Fills form data into Metadata/Dataset records

        Args:
            data (dict): Cleaned form data
            metadata (dict): The metadata record
            dataset (dict): The dataset record
            user: The performing user
        Returns:

        """
        metadata.licence = data.get("licence", None)
        metadata.access_constraints = data.get("access_constraints", None)
    def to_db_model(self,
                    type=MetadataEnum.DATASET.value,
                    created_by: MrMapGroup = None):
        """ Get corresponding metadata object from database or create it if not found!

        Returns:
            metadata (Metadata): A db model Metadata object
        """
        update = False
        new = False
        # try to find the object by uuid and uri. If not existing yet, create a new record
        try:
            metadata = Metadata.objects.get(identifier=self.file_identifier,
                                            metadata_url=self.uri)
            # check if the parsed metadata might be newer
            # make sure both date time objects will be comparable
            persisted_change = metadata.last_remote_change.replace(tzinfo=utc)
            new_change = self.last_change_date.replace(tzinfo=utc)
            if persisted_change > new_change:
                # Nothing to do here
                return metadata
            else:
                update = True
        except ObjectDoesNotExist:
            # object does not seem to exist -> create it!
            metadata = Metadata()
            md_type = type
            metadata.metadata_type = md_type
            if metadata.is_dataset_metadata:
                metadata.dataset = Dataset()
                metadata.dataset.created_by = created_by
            metadata.created_by = created_by
            new = True

        if update or new:

            # In case of a dataset, we need to fill the information into the dataset object
            if metadata.is_dataset_metadata:
                metadata.dataset = self._fill_dataset_db_model(
                    metadata.dataset)

            metadata = self._fill_metadata_db_model(metadata)
            metadata.save()
            metadata.dataset.save()

            orig_document = Document.objects.get_or_create(
                metadata=metadata,
                document_type=DocumentEnum.METADATA.value,
                is_original=True,
            )[0]
            orig_document.content = self.raw_metadata
            orig_document.save()

            if update:
                metadata.keywords.clear()
            for kw in self.keywords:
                keyword = Keyword.objects.get_or_create(keyword=kw)[0]
                metadata.keywords.add(keyword)
        return metadata
Exemple #7
0
    def _create_dublin_core_summary_elem(self, md: Metadata):
        """ Creates the SummaryRecord in Dublin core syntax

        Args:
            md (Metadata): The metadata object providing the data
        Returns:
             elem (_Element): The lxml element
        """
        record_elem = Element(
            "{}SummaryRecord".format(self.csw_ns),
            nsmap=self.dc_ns_map,
        )

        # Perform xml creation for simple elements
        attribute_element_map = OrderedDict()
        attribute_element_map[IDENTIFIER_TEMPLATE.format(
            self.dc_ns)] = md.identifier
        attribute_element_map[TITLE_TEMPLATE.format(self.dc_ns)] = md.title
        attribute_element_map[TYPE_TEMPLATE.format(
            self.dc_ns
        )] = md.metadata_type if md.metadata_type == MetadataEnum.DATASET.value else MetadataEnum.SERVICE.value
        kws = md.keywords.all()
        formats = md.get_formats()
        attribute_element_map["{}subject".format(
            self.dc_ns)] = [kw.keyword for kw in kws]
        attribute_element_map["{}format".format(
            self.dc_ns)] = [format.mime_type for format in formats]
        attribute_element_map["{}modified".format(
            self.dct_ns)] = md.last_modified.strftime(DATE_STRF)
        attribute_element_map["{}abstract".format(self.dct_ns)] = md.abstract

        # Create xml elements from mapped information
        self._create_xml_from_map(record_elem, attribute_element_map)

        return record_elem
Exemple #8
0
    def get_table(self, **kwargs):
        # set some custom attributes for template rendering
        table = super(WmsIndexView, self).get_table(**kwargs)
        # whether whole services or single layers should be displayed, we have to exclude some columns
        filter_by_show_layers = self.filterset.form_prefix + '-' + 'service__is_root'
        if filter_by_show_layers in self.filterset.data and self.filterset.data.get(
                filter_by_show_layers) == 'on':
            table.exclude = (
                'layers',
                'featuretypes',
                'harvest_results',
                'collected_harvest_records',
                'harvest_duration',
            )
        else:
            table.exclude = (
                'parent_service',
                'featuretypes',
                'harvest_results',
                'collected_harvest_records',
                'harvest_duration',
            )

        render_helper = RenderHelper(user_permissions=list(
            filter(None, self.request.user.get_all_permissions())))
        table.actions = [
            render_helper.render_item(item=Metadata.get_add_resource_action())
        ]
        return table
Exemple #9
0
    def create_metadata_elem(self, returned_md: Metadata):
        """ Returns existing service/dataset metadata as xml elements

        Args:
            returned_md (Metadata): The processing metadata
        Returns:
             xml (Element): The xml element
        """
        if returned_md.is_dataset_metadata:
            doc = Document.objects.get(
                metadata=returned_md,
                document_type=DocumentEnum.METADATA.value,
            )
            xml = doc.content
        else:
            xml = returned_md.get_service_metadata_xml()

        xml = xml_helper.parse_xml(xml)
        xml = xml_helper.try_get_single_element_from_xml(
            xml_elem=xml,
            elem="//" + GENERIC_NAMESPACE_TEMPLATE.format("MD_Metadata"))

        # Reduce the amount of information returned based on the requested elementSetName parameter
        xml = self.reduce_information(xml)

        return xml
Exemple #10
0
    def _fill_metadata_dataset_responsible_party_form(data: dict,
                                                      metadata: Metadata,
                                                      dataset: Dataset,
                                                      user: MrMapUser):
        """ Fills form data into Metadata/Dataset records

        Args:
            data (dict): Cleaned form data
            metadata (dict): The metadata record
            dataset (dict): The dataset record
            user: The performing user
        Returns:

        """
        # Check on an existing organization
        org = data.get("organization")
        if org is None:
            # A new org has to be created with minimal contact details
            org = Organization.objects.get_or_create(
                organization_name=data.get("organization_name"),
                is_auto_generated=True,
                person_name=data.get("person_name"),
                phone=data.get("phone"),
                email=data.get("mail"),
                facsimile=data.get("facsimile"),
                created_by=user,
            )[0]
        metadata.contact = org
Exemple #11
0
    def _fill_metadata_dataset_spatial_extent_form(data: dict, metadata: Metadata, dataset: Dataset, user: MrMapUser):
        """ Fills form data into Metadata/Dataset records

        Args:
            data (dict): Cleaned form data
            metadata (dict): The metadata record
            dataset (dict): The dataset record
            user: The performing user
        Returns:

        """
        try:
            bounding_geometry = json.loads(data.get("bounding_geometry", "{}"))
        except JSONDecodeError:
            bounding_geometry = {}
        if bounding_geometry.get("features", None) is not None:
            # A list of features
            geoms = [GEOSGeometry(str(feature["geometry"]), srid=DEFAULT_SRS) for feature in
                     bounding_geometry.get("features")]
            geom = GeometryCollection(geoms, srid=DEFAULT_SRS).unary_union
        elif bounding_geometry.get("feature", None) is not None:
            geom = GEOSGeometry(str(bounding_geometry.get("feature")["geometry"]), srid=DEFAULT_SRS)
        else:
            try:
                geom = GEOSGeometry(str(bounding_geometry), srid=DEFAULT_SRS)
            except Exception:
                # No features provided
                return
        metadata.bounding_geometry = geom
Exemple #12
0
def _overwrite_capabilities_iso_metadata_links(xml_obj: _Element,
                                               metadata: Metadata):
    """ Overwrites links in capabilities document

    Args:
        xml_obj (_Element): The xml_object of the document
        metadata (Metadata): The metadata object, holding the data
    Returns:

    """
    # get list of all iso md links that really exist (from the metadata object)
    iso_md_links = metadata.get_related_metadata_uris()

    # get list of all MetadataURL elements from the capabilities element
    xml_links = xml_helper.try_get_element_from_xml("./MetadataURL", xml_obj)
    for xml_link in xml_links:
        xml_online_resource_elem = xml_helper.try_get_element_from_xml(
            "./OnlineResource", xml_link)
        xml_link_attr = xml_helper.try_get_attribute_from_xml_element(
            xml_online_resource_elem, "xlink:href")
        if xml_link_attr in iso_md_links:
            # we still use this, so we are good
            # Remove this link from iso_md_links to get an overview of which links are left over in the end
            # These links must be new then!
            iso_md_links.remove(xml_link_attr)
            continue
        else:
            # this does not seem to exist anymore -> remove it from the xml
            xml_helper.remove_element(xml_link)
    # what is left over in iso_md_links are new links that must be added to the capabilities doc
    for new_link in iso_md_links:
        xml_helper.add_iso_md_element(xml_obj, new_link)
Exemple #13
0
    def _fill_form_list(form_list, metadata: Metadata, dataset: Dataset,
                        user: MrMapUser):
        """ Iterates over all forms and applies the metadata changes on the objects

        Args:
            form_list: The list of forms
            metadata: The metadata record
            dataset: The dataset record
            user: The performing user
        Returns:

        """
        function_map = {
            "DatasetIdentificationForm":
            DatasetWizard._fill_metadata_dataset_identification_form,
            "DatasetResponsiblePartyForm":
            DatasetWizard._fill_metadata_dataset_responsible_party_form,
            "DatasetClassificationForm":
            DatasetWizard._fill_metadata_dataset_classification_form,
            "DatasetSpatialExtentForm":
            DatasetWizard._fill_metadata_dataset_spatial_extent_form,
            "DatasetLicenseConstraintsForm":
            DatasetWizard._fill_metadata_dataset_licence_form,
            "DatasetQualityForm":
            DatasetWizard._fill_metadata_dataset_quality_form,
        }

        for form in form_list:
            form_class = type(form).__name__
            function_map[form_class](form.cleaned_data, metadata, dataset,
                                     user)

        dataset.save()
        metadata.is_custom = True
        metadata.save()

        try:
            doc = Document.objects.get(
                metadata__id=metadata.id,
                document_type=DocumentEnum.METADATA.value,
                is_original=False,
            )
            doc.is_active = metadata.is_active
            DatasetWizard._overwrite_dataset_document(metadata, doc)
        except ObjectDoesNotExist:
            DatasetWizard._create_dataset_document(metadata)
Exemple #14
0
class NewDatasetWizard(PermissionRequiredMixin, DatasetWizard):
    permission_required = PermissionEnum.CAN_ADD_DATASET_METADATA.value
    raise_exception = True
    permission_denied_message = NO_PERMISSION

    def __init__(self, *args, **kwargs):
        super().__init__(action_url=reverse(
            'editor:dataset-metadata-wizard-new', ),
                         title=_(format_html('<b>Add New Dataset</b>')),
                         *args,
                         **kwargs)

    def get_form_kwargs(self, step=None):
        return {'request': self.request}

    def done(self, form_list, **kwargs):
        """ Iterates over all forms and fills the Metadata/Dataset records accordingly

        Args:
            form_list (FormList): An iterable list of forms
            kwargs:
        Returns:

        """
        # Create instances
        self.metadata = Metadata()
        self.metadata.metadata_type = MetadataEnum.DATASET.value
        self.metadata.is_active = True

        self.dataset = Dataset()
        self.dataset.is_active = True
        self.dataset.md_identifier_code = self.metadata.identifier
        self.dataset.metadata_standard_name = "ISO 19115 Geographic information - Metadata"
        self.dataset.metadata_standard_version = "ISO 19115:2003(E)"

        # Pre-save objects to be able to add M2M relations
        self.metadata.save()
        self.metadata.identifier = self.metadata.id
        self.dataset.metadata = self.metadata
        self.dataset.save()
        self.metadata.metadata_url = reverse("resource:get-dataset-metadata",
                                             args=(self.dataset.id, ))

        return super().done(form_list=form_list, **kwargs)
Exemple #15
0
    def _create_additional_records(self, metadata: Metadata, layer: Layer,
                                   group: MrMapGroup, epsg_api: EpsgApi):
        """ Creates additional records such as Keywords, ReferenceSystems, Dimensions, ...

        Args:
            metadata (Metadata): The layer's metadata object
            layer (Layer): The Layer record object
            group (MrMapGroup): The owner/creator group
            epsg_api (EpsgApi): A epsg_api object
        Returns:

        """
        # Keywords
        for kw in self.capability_keywords:
            keyword = Keyword.objects.get_or_create(keyword=kw)[0]
            metadata.keywords.add(keyword)

        # handle reference systems
        for sys in self.capability_projection_system:
            parts = epsg_api.get_subelements(sys)
            # check if this srs is allowed for us. If not, skip it!
            if parts.get("code") not in ALLOWED_SRS:
                continue
            ref_sys = ReferenceSystem.objects.get_or_create(
                code=parts.get("code"), prefix=parts.get("prefix"))[0]
            metadata.reference_system.add(ref_sys)

        for iso_md in self.iso_metadata:
            iso_md = iso_md.to_db_model(created_by=group)
            metadata.add_metadata_relation(
                to_metadata=iso_md,
                relation_type=MetadataRelationEnum.DESCRIBES.value,
                origin=iso_md.origin)

        # Dimensions
        for dimension in self.dimension_list:
            dim = Dimension.objects.get_or_create(
                type=dimension.get("type"),
                units=dimension.get("units"),
                extent=dimension.get("extent"),
            )[0]
            layer.metadata.dimensions.add(dim)
Exemple #16
0
 def get_table(self, **kwargs):
     # set some custom attributes for template rendering
     table = super(DatasetIndexView, self).get_table(**kwargs)
     render_helper = RenderHelper(user_permissions=list(
         filter(None, self.request.user.get_all_permissions())),
                                  update_url_qs=get_current_view_args(
                                      self.request))
     table.actions = [
         render_helper.render_item(item=Metadata.get_add_dataset_action())
     ]
     return table
Exemple #17
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()
Exemple #18
0
    def _create_service_record(self, group: MrMapGroup,
                               orga_published_for: Organization, md: Metadata,
                               is_update_candidate_for: Service):
        """ Creates a Service object from the OGCWebFeatureService object

        Args:
            group (MrMapGroup): The owner/creator group
            orga_published_for (Organization): The organization for which the service is published
            orga_publisher (Organization): THe organization that publishes
            md (Metadata): The describing metadata
        Returns:
             service (Service): The persisted service object
        """
        service = Service()
        service_type = ServiceType.objects.get_or_create(
            name=self.service_type.value.lower(),
            version=self.service_version.value)[0]

        service.service_type = service_type
        service.created_by = group
        service.published_for = orga_published_for

        service.availability = 0.0
        service.is_available = False
        service.is_root = True
        md.service = service
        service.is_update_candidate_for = is_update_candidate_for

        # Save record to enable M2M relations
        service.save()

        operation_urls = []
        for operation, parsed_operation_url, method in self.operation_urls:
            # todo: optimize as bulk create
            try:
                operation_urls.append(
                    ServiceUrl.objects.get_or_create(operation=operation,
                                                     url=getattr(
                                                         self,
                                                         parsed_operation_url),
                                                     method=method)[0])
            except IntegrityError:
                # empty/None url values will be ignored
                pass

        service.operation_urls.add(*operation_urls)

        # Persist capabilities document
        service.persist_original_capabilities_doc(
            self.service_capabilities_xml)

        return service
Exemple #19
0
 def get_table(self, **kwargs):
     # set some custom attributes for template rendering
     table = super(CswIndexView, self).get_table(**kwargs)
     table.exclude = ('parent_service', 'layers', 'featuretypes',
                      'service__published_for')
     render_helper = RenderHelper(user_permissions=list(
         filter(None, self.request.user.get_all_permissions())),
                                  update_url_qs=get_current_view_args(
                                      self.request))
     table.actions = [
         render_helper.render_item(item=Metadata.get_add_resource_action())
     ]
     return table
Exemple #20
0
    def _create_dublin_core_full_elem(self, md: Metadata):
        """ Creates the default (full) record in Dublin core syntax

        Args:
            md (Metadata): The metadata object providing the data
        Returns:
             elem (_Element): The lxml element
        """
        record_elem = Element(
            "{}Record".format(self.csw_ns),
            nsmap=self.dc_ns_map,
        )

        # Perform xml creation for simple elements
        attribute_element_map = OrderedDict()
        attribute_element_map[IDENTIFIER_TEMPLATE.format(
            self.dc_ns)] = md.identifier
        attribute_element_map["{}date".format(
            self.dc_ns)] = md.created.strftime(DATE_STRF)
        attribute_element_map[TITLE_TEMPLATE.format(self.dc_ns)] = md.title
        attribute_element_map["{}abstract".format(self.dct_ns)] = md.abstract
        attribute_element_map["{}description".format(self.dc_ns)] = md.abstract
        attribute_element_map[TYPE_TEMPLATE.format(
            self.dc_ns
        )] = md.metadata_type if md.metadata_type == MetadataEnum.DATASET.value else MetadataEnum.SERVICE.value
        kws = md.keywords.all()
        formats = md.get_formats()
        attribute_element_map["{}subject".format(
            self.dc_ns)] = [kw.keyword for kw in kws]
        attribute_element_map["{}format".format(
            self.dc_ns)] = [format.mime_type for format in formats]
        attribute_element_map["{}modified".format(
            self.dct_ns)] = md.last_modified.strftime(DATE_STRF)
        attribute_element_map["{}rights".format(self.dc_ns)] = "ToDo"  # ToDo

        # Create xml elements from mapped information
        self._create_xml_from_map(record_elem, attribute_element_map)

        # Perform xml creation for more complex elements
        # URI
        elem = xml_helper.create_subelement(record_elem,
                                            "{}URI".format(self.dc_ns),
                                            attrib={
                                                "protocol": "",
                                                "name": md.identifier or "",
                                                "description": md.abstract
                                                or "",
                                            })
        elem.text = md.capabilities_uri

        return record_elem
Exemple #21
0
    def get_table(self, **kwargs):
        # set some custom attributes for template rendering
        table = super(WfsIndexView, self).get_table(**kwargs)
        table.exclude = ('parent_service', 'layers', 'harvest_results',
                         'collected_harvest_records', 'harvest_duration')

        render_helper = RenderHelper(user_permissions=list(
            filter(None, self.request.user.get_all_permissions())),
                                     update_url_qs=get_current_view_args(
                                         self.request))
        table.actions = [
            render_helper.render_item(item=Metadata.get_add_resource_action())
        ]
        return table
Exemple #22
0
    def _fill_metadata_dataset_spatial_extent_form(data: dict,
                                                   metadata: Metadata,
                                                   dataset: Dataset,
                                                   user: MrMapUser):
        """ Fills form data into Metadata/Dataset records

        Args:
            data (dict): Cleaned form data
            metadata (dict): The metadata record
            dataset (dict): The dataset record
            user: The performing user
        Returns:

        """
        metadata.bounding_geometry = data.get("bounding_geometry", None)
Exemple #23
0
def collect_metadata_related_objects(md: Metadata, request: HttpRequest,):
    params = {}

    # get all related Metadata objects from type dataset
    related_metadatas = md.get_related_dataset_metadatas()
    if related_metadatas:
        # build django tables2 table
        related_metadatas_table = CoupledMetadataTable(
            queryset=related_metadatas,
            order_by='title',
            show_header=True,
            request=request,
            param_lead='rm-t')

        params['related_metadatas'] = related_metadatas

    return params
Exemple #24
0
def resolve_iso_metadata_links(metadata: Metadata, editor_form):
    """ Iterate over all provided iso metadata links and create metadata from it which will be related to the metadata

    Args:
        metadata (Metadata): The edited metadata
        editor_form: The editor form
    Returns:
         nothing
    """
    # iterate over iso metadata links and create IsoMetadata objects
    md_links = editor_form.data.get("iso_metadata_url", "").split(",")

    # create list of all persisted and related iso md links
    existing_iso_links = metadata.get_related_metadata_uris()

    try:
        _remove_iso_metadata(metadata, md_links, existing_iso_links)
        _add_iso_metadata(metadata, md_links, existing_iso_links)
    except MissingSchema as e:
        editor_logger.error(msg=EDITOR_INVALID_ISO_LINK.format(e.link))
        editor_logger.exception(e, exc_info=True, stack_info=True)
    except Exception as e:
        editor_logger.exception(e, exc_info=True, stack_info=True)
Exemple #25
0
def overwrite_metadata(original_md: Metadata, custom_md: Metadata,
                       editor_form):
    """ Overwrites the original data with the custom date

    Args:
        original_md (Metadata): The original Metadata object
        custom_md (Metadata): The custom Metadata object
        editor_form: The editor form which holds additional data
    Returns:
        nothing
    """
    original_md.title = custom_md.title
    original_md.abstract = custom_md.abstract
    original_md.access_constraints = custom_md.access_constraints
    # we need the metadata_url to reset dataset metadatas
    # original_md.metadata_url = custom_md.metadata_url
    original_md.licence = custom_md.licence
    # get db objects from values

    # Keyword updating
    keywords = editor_form.cleaned_data["keywords"]
    original_md.keywords.clear()
    for kw in keywords:
        keyword = Keyword.objects.get_or_create(keyword=kw)[0]
        original_md.keywords.add(keyword)

    # Language updating
    original_md.language_code = editor_form.cleaned_data["language_code"]

    # Categories updating
    # Categories are provided as id's to prevent language related conflicts
    try:
        categories = editor_form.cleaned_data["categories"]
        original_md.categories.clear()
        for category in categories:
            original_md.categories.add(category)
    except KeyError:
        pass

    # Categories are inherited by subelements
    subelements = original_md.get_described_element().get_subelements(
    ).select_related('metadata')
    for subelement in subelements:
        subelement.metadata.categories.clear()
        for category in categories:
            subelement.metadata.categories.add(category)

    # change capabilities document so that all sensitive elements (links) are proxied
    if original_md.use_proxy_uri != custom_md.use_proxy_uri:
        if custom_md.use_proxy_uri == 'on':
            original_md.set_proxy(True)
        else:
            original_md.set_proxy(False)

    # save metadata
    original_md.is_custom = True
    original_md.save()

    if original_md.is_dataset_metadata:
        overwrite_dataset_metadata_document(original_md)
    else:
        overwrite_capabilities_document(original_md)
Exemple #26
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)
Exemple #27
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)
Exemple #28
0
    def _create_metadata_record(self, parent_service: Service,
                                group: MrMapGroup):
        """ Creates a Metadata record from the OGCLayer object

        Args:
            self (OGCLayer): The OGCLayer object (result of parsing)
            parent_service (Service): The parent Service object 
            group (MrMapGroup): The creator/owner group
        Returns:
             metadata (Metadata): The persisted metadata object
        """
        metadata = Metadata()
        md_type = MetadataEnum.LAYER.value
        metadata.metadata_type = md_type
        metadata.title = self.title
        metadata.abstract = self.abstract
        metadata.online_resource = parent_service.metadata.online_resource
        metadata.capabilities_original_uri = parent_service.metadata.capabilities_original_uri
        metadata.identifier = self.identifier
        metadata.contact = parent_service.metadata.contact
        metadata.access_constraints = parent_service.metadata.access_constraints
        metadata.is_active = False
        metadata.created_by = group

        # Save metadata to use id afterwards
        metadata.save()

        # create bounding box polygon
        bounding_points = ((float(self.capability_bbox_lat_lon["minx"]),
                            float(self.capability_bbox_lat_lon["miny"])),
                           (float(self.capability_bbox_lat_lon["minx"]),
                            float(self.capability_bbox_lat_lon["maxy"])),
                           (float(self.capability_bbox_lat_lon["maxx"]),
                            float(self.capability_bbox_lat_lon["maxy"])),
                           (float(self.capability_bbox_lat_lon["maxx"]),
                            float(self.capability_bbox_lat_lon["miny"])),
                           (float(self.capability_bbox_lat_lon["minx"]),
                            float(self.capability_bbox_lat_lon["miny"])))
        metadata.bounding_geometry = Polygon(bounding_points)

        metadata.save()

        return metadata
    def _fill_metadata_db_model(self, metadata: Metadata):
        """ Fills a Metadata db record from the ISOMetadata data

        Args:
            metadata (Metadata): The old/empty object
        Returns:
             metadata (Metadata): The metadata object
        """
        metadata.identifier = self.file_identifier
        metadata.abstract = self.abstract
        metadata.access_constraints = self.access_constraints

        # Take the polygon with the largest area as bounding geometry
        if len(self.polygonal_extent_exterior) > 0:
            max_area_poly = None
            for poly in self.polygonal_extent_exterior:
                if max_area_poly is None:
                    max_area_poly = poly
                if max_area_poly.area < poly.area:
                    max_area_poly = poly
            metadata.bounding_geometry = max_area_poly

        try:
            metadata.contact = Organization.objects.get_or_create(
                organization_name=self.responsible_party,
                email=self.contact_email,
            )[0]
        except MultipleObjectsReturned:
            # okay, we need to create a unique organization
            # "unique" since it will only be identified using organization_name and email
            metadata.contact = Organization.objects.get_or_create(
                organization_name="{}#1".format(self.responsible_party),
                email=self.contact_email,
            )[0]

        metadata.is_inspire_conform = self.inspire_interoperability
        metadata.metadata_url = self.uri
        metadata.last_remote_change = self.last_change_date
        metadata.spatial_res_type = self.spatial_res_type
        metadata.spatial_res_value = self.spatial_res_val
        if self.title is None:
            self.title = "BROKEN"
        metadata.title = self.title
        metadata.origin = self.origin
        metadata.is_broken = self.is_broken
        metadata.save()

        # save legal dates and reports
        for report in self.legal_reports:
            report.date.save()
            report.save()
            metadata.legal_reports.add(report)
        for date in self.legal_dates:
            date.save()
            metadata.legal_dates.add(date)

        metadata.save()

        return metadata
Exemple #30
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