Example #1
0
 def delete(self, current_user_id: UserIDT, coll_id: CollectionIDT) -> int:
     # TODO, for now only admins
     _user = RightsBO.user_has_role(self.ro_session, current_user_id,
                                    Role.APP_ADMINISTRATOR)
     CollectionBO.delete(self.session, coll_id)
     self.session.commit()
     return 0
Example #2
0
 def query_by_short_title(self, title: str) -> CollectionBO:
     # Return a unique collection from its title, short one
     qry = self.ro_session.query(Collection).filter(
         Collection.short_title == title)
     ret = [CollectionBO(a_rec).enrich() for a_rec in qry.all()]
     assert len(ret) == 1, NOT_FOUND
     return ret[0]
Example #3
0
 def query(self, current_user_id: UserIDT,
           coll_id: CollectionIDT) -> Optional[CollectionBO]:
     # TODO, for now only admins
     _user = RightsBO.user_has_role(self.session, current_user_id,
                                    Role.APP_ADMINISTRATOR)
     ret = CollectionBO.get_one(self.session, coll_id)
     return ret
Example #4
0
 def search(self, current_user_id: UserIDT,
            title: str) -> List[CollectionBO]:
     # TODO, for now only admins
     _user = RightsBO.user_has_role(self.ro_session, current_user_id,
                                    Role.APP_ADMINISTRATOR)
     qry = self.ro_session.query(Collection).filter(
         Collection.title.ilike(title))
     ret = [CollectionBO(a_rec).enrich() for a_rec in qry.all()]
     return ret
Example #5
0
 def create(self, current_user_id: UserIDT,
            req: CreateCollectionReq) -> Union[CollectionIDT, str]:
     """
         Create a collection.
     """
     # TODO, for now only admins
     _user = RightsBO.user_has_role(self.ro_session, current_user_id,
                                    Role.APP_ADMINISTRATOR)
     coll_id = CollectionBO.create(self.session, req.title, req.project_ids)
     return coll_id
Example #6
0
    def add_events(self, arch: DwC_Archive):
        """
            Add DwC events into the archive.
                We produce sample-type events.
        """
        # TODO: Dup code
        the_collection: CollectionBO = CollectionBO(self.collection).enrich()

        ds_name = self.sanitize_title(self.collection.title)
        for a_prj_id in the_collection.project_ids:
            samples = Sample.get_orig_id_and_model(self.ro_session,
                                                   prj_id=a_prj_id)
            a_sample: Sample
            events = arch.events
            for orig_id, a_sample in samples.items():
                assert a_sample.latitude is not None and a_sample.longitude is not None
                event_id = orig_id
                evt_type = RecordTypeEnum.sample
                summ = Sample.get_sample_summary(self.session,
                                                 a_sample.sampleid)
                if summ[0] is None or summ[1] is None:
                    self.empty_samples.append((a_prj_id, a_sample.orig_id))
                    continue
                evt_date = self.event_date(summ[0], summ[1])
                latitude = self.geo_to_txt(float(a_sample.latitude))
                longitude = self.geo_to_txt(float(a_sample.longitude))
                evt = DwC_Event(eventID=event_id,
                                type=evt_type,
                                institutionCode=self.institution_code,
                                datasetName=ds_name,
                                eventDate=evt_date,
                                decimalLatitude=latitude,
                                decimalLongitude=longitude,
                                minimumDepthInMeters=str(summ[2]),
                                maximumDepthInMeters=str(summ[3]))
                events.add(evt)
                self.add_eMoFs_for_sample(sample=a_sample,
                                          arch=arch,
                                          event_id=event_id)
                nb_added = self.add_occurences(sample=a_sample,
                                               arch=arch,
                                               event_id=event_id)
                if nb_added == 0:
                    self.warnings.append(
                        "No occurrence added for sample '%s' in %d" %
                        (a_sample.orig_id, a_prj_id))
Example #7
0
    def build_meta(self) -> Optional[EMLMeta]:
        """
            Various queries/copies on/from the projects for getting metadata.
        """
        ret = None
        the_collection: CollectionBO = CollectionBO(self.collection).enrich()

        identifier = EMLIdentifier(packageId=the_collection.external_id,
                                   system=the_collection.external_id_system)

        title = EMLTitle(title=the_collection.title)

        creators: List[EMLPerson] = []
        for a_user in the_collection.creator_users:
            person, errs = self.user_to_eml_person(
                a_user, "creator '%s'" % a_user.name)
            if errs:
                self.warnings.extend(errs)
            else:
                assert person is not None
                creators.append(person)
        for an_org in the_collection.creator_organisations:
            creators.append(self.organisation_to_eml_person(an_org))
        if len(creators) == 0:
            self.errors.append(
                "No valid data creator (user or organisation) found for EML metadata."
            )

        contact, errs = self.user_to_eml_person(the_collection.contact_user,
                                                "contact")
        if contact is None:
            self.errors.append("No valid contact user found for EML metadata.")

        provider, errs = self.user_to_eml_person(the_collection.provider_user,
                                                 "provider")
        if provider is None:
            self.errors.append(
                "No valid metadata provider user found for EML metadata.")

        associates: List[EMLAssociatedPerson] = []
        for a_user in the_collection.associate_users:
            person, errs = self.user_to_eml_person(
                a_user, "associated person %d" % a_user.id)
            if errs:
                self.warnings.extend(errs)
            else:
                assert person is not None
                associates.append(
                    self.eml_person_to_associated_person(person, "originator"))
        for an_org in the_collection.associate_organisations:
            # noinspection PyTypeChecker
            associates.append(self.organisation_to_eml_person(an_org))

        # TODO if needed
        # EMLAssociatedPerson = EMLPerson + specific role

        # TODO: a marine regions substitute
        (min_lat, max_lat, min_lon,
         max_lon) = ProjectBO.get_bounding_geo(self.session,
                                               the_collection.project_ids)
        geo_cov = EMLGeoCoverage(
            geographicDescription="See coordinates",
            westBoundingCoordinate=self.geo_to_txt(min_lon),
            eastBoundingCoordinate=self.geo_to_txt(max_lon),
            northBoundingCoordinate=self.geo_to_txt(min_lat),
            southBoundingCoordinate=self.geo_to_txt(max_lat))

        (min_date,
         max_date) = ProjectBO.get_date_range(self.session,
                                              the_collection.project_ids)
        time_cov = EMLTemporalCoverage(beginDate=timestamp_to_str(min_date),
                                       endDate=timestamp_to_str(max_date))

        publication_date = date.today().isoformat()

        abstract = the_collection.abstract
        if not abstract:
            self.errors.append("Collection 'abstract' field is empty")
        elif len(abstract) < self.MIN_ABSTRACT_CHARS:
            self.errors.append(
                "Collection 'abstract' field is too short (%d chars) to make a good EMLMeta abstract. Minimum is %d"
                % (len(abstract), self.MIN_ABSTRACT_CHARS))

        additional_info = None  # Just to see if it goes thru QC
        # additional_info = """  marine, harvested by iOBIS.
        # The OOV supported the financial effort of the survey.
        # We are grateful to the crew of the research boat at OOV that collected plankton during the temporal survey."""

        coll_license: LicenseEnum = cast(LicenseEnum, the_collection.license)
        if coll_license not in self.OK_LICENSES:
            self.errors.append(
                "Collection license should be one of %s to be accepted, not %s."
                % (self.OK_LICENSES, coll_license))
        else:
            lic_url = DataLicense.EXPORT_EXPLANATIONS[
                coll_license] + "legalcode"
            lic_txt = DataLicense.NAMES[coll_license]
            lic_txt = lic_txt.replace("International Public ", "")
            # ipt.gbif.org does not find the full license name, so adjust a bit
            version = "4.0"
            if version in lic_txt:
                lic_txt = lic_txt.replace(
                    version,
                    "(%s) " % DataLicense.SHORT_NAMES[coll_license] + version)
            licence = "This work is licensed under a <ulink url=\"%s\"><citetitle>%s</citetitle></ulink>." % (
                lic_url, lic_txt)

        # Preferably one of https://www.emodnet-biology.eu/contribute?page=list&subject=thestdas&SpColID=552&showall=1#P
        keywords = EMLKeywordSet(
            keywords=[
                "Plankton",
                "Imaging",
                "EcoTaxa"  # Not in list above
                # "Ligurian sea" TODO: Geo area?
                # TODO: ZooProcess (from projects)
            ],
            keywordThesaurus="GBIF Dataset Type Vocabulary: "
            "http://rs.gbif.org/vocabulary/gbif/dataset_type.xml")

        taxo_cov = self.get_taxo_coverage(the_collection.project_ids)

        now = datetime.now().replace(microsecond=0)
        meta_plus = EMLAdditionalMeta(dateStamp=now.isoformat())

        coll_title = the_collection.title
        info_url = "https://ecotaxa.obs-vlfr.fr/api/collections/by_title?q=%s" % quote_plus(
            coll_title)

        if len(self.errors) == 0:
            # The research project
            # noinspection PyUnboundLocalVariable
            # project = EMLProject(title=the_collection.title,
            #                      personnel=[])  # TODO: Unsure about duplicated information with metadata
            # noinspection PyUnboundLocalVariable
            ret = EMLMeta(
                identifier=identifier,
                titles=[title],
                creators=creators,
                contacts=[contact],
                metadataProviders=[provider],
                associatedParties=associates,
                pubDate=publication_date,
                abstract=[abstract],
                keywordSet=keywords,
                additionalInfo=additional_info,
                geographicCoverage=geo_cov,
                temporalCoverage=time_cov,
                taxonomicCoverage=taxo_cov,
                intellectualRights=licence,
                # project=project,
                maintenance="periodic review of origin data",
                maintenanceUpdateFrequency="unknown",  # From XSD
                additionalMetadata=meta_plus,
                informationUrl=info_url)
        return ret