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
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]
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
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
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
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))
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