class UserModelWithRights(_UserModelFromDB): # type:ignore can_do: List[int] = Field( title= "Actions allowed to this user, 1=create project, 2=administrate the app", default=[]) last_used_projects: List[ProjectSummaryModel] = Field( title="The last used projects for this user", default=[])
class EMLTitle(BaseModel): """ EML title with optional lang. """ title: str = Field(title="Descriptive title(s) - not too short") """ A good title allows a user to a first assessment whether the dataset is useful for the intended purpose. EMODnet Biology recommends including the region and time period of sampling.""" lang: str = Field(title="Title language, ISO-639.2", default="eng")
class DirectoryEntryModel(BaseModel): """ Something inside a directory, i.e. a sub-directory or a file """ name: str = Field(title="atomic entry name") type: str = Field(title="entry type, 'D' for directory, 'F' for file") size: int = Field(Title="Entry size, for zips") mtime: str = Field(Title="Modification time, in ISO format")
class EMLIdentifier(BaseModel): """ EML unique identifier for the document """ packageId: str = Field(title="Unique ID for this dataset in the system.") system: str = Field(title="The system providing unicity, e.g. https://doi.org") scope: Optional[str] = Field(title="The scope of the ID inside the system", default="system")
class DirectoryModel(BaseModel): """ A path + list of entries inside. The path is relative to an implied root. """ path: str = Field(title="A /-separated path from root to this directory") entries: List[DirectoryEntryModel] = Field( title="Entries, i.e. subdirectories or contained files. " "All entries are readable, i.e. can be used as input or navigated into." )
class SimpleImportReq(BaseModel): """ Simple Import request. """ source_path: str = Field(title="Source path on server, to zip or plain directory") values: Dict[SimpleImportFields, str] = Field( title="Constant values, per field, to write for all images. If a field has no value don't include it.", description=":" + ", ".join(SimpleImportFields)) # TODO: How to transmit a constant via OpenApi+FastApi ? # possible_values: List[str] = Field(title="Possible field values", const=True, # default=[v for v in PossibleSimpleImportFields.__members__]) possible_values: List[str] = [v for v in SimpleImportFields.__members__]
class EMODnetExportRsp(BaseModel): """ EMODNet format export response. """ errors: List[str] = Field(title="Showstopper problems found while building the archive.", default=[]) warnings: List[str] = Field(title="Problems found while building the archive, which do not prevent producing it.", default=[]) task_id: int = Field(title="The created task, 0 if there were problems.", default=0)
class SimpleImportReq(BaseModel): """ Simple Import preparation, request. """ task_id: int = Field(title="The existing task to use, if 0 then it's a dry run") source_path: str = Field(title="Source path on server, to zip or plain directory") values: Dict[SimpleImportFields, Optional[str]] = Field( title="Constant values, per field, to write for all images.", description=":" + ", ".join(SimpleImportFields)) # TODO: How to transmit a constant via OpenApi+FastApi ? # possible_values: List[str] = Field(title="Possible field values", const=True, # default=[v for v in PossibleSimpleImportFields.__members__]) possible_values: List[str] = [v for v in SimpleImportFields.__members__]
class ImportReq(BaseModel): """ Import request, from UI choices. """ source_path: str = Field(title="Source path on server, to zip or plain directory." " The path can be returned by a file upload (absolute)," " otherwise it's relative to shared file area root.") taxo_mappings: Dict[str, str] = Field( title="Optional taxonomy mapping, key=taxo ID found in file, value=final taxo ID to write", default={}) skip_loaded_files: bool = Field(default=False) skip_existing_objects: bool = Field(default=False) update_mode: str = Field(title="Update data ('Yes'), including classification ('Cla')", default="")
class Constants(BaseModel): """ Values which can be considered identical over the lifetime of the back-end """ license_texts: Dict[str, str] = Field( title="The supported licenses and help text/links", default={ short: expl for short, expl in DataLicense.EXPLANATIONS.items() }) app_manager: List[str] = Field( title="The application manager identity (name, mail), from config file", default=["", ""], min_items=2, max_items=2)
class EMLAdditionalMeta(BaseModel): """ EML additional metadata """ dateStamp: str """ The dateTime the metadata document was created or modified (ISO 8601).""" metadataLanguage: str = Field(title="Title language, ISO-639.2", default="eng") """ The language in which the metadata document (as opposed to the resource being described by the metadata) is written. """ citation: Optional[str] """ A single citation for use when citing the dataset. The IPT can also auto-generate a citation based on the metadata (people, title, organization, onlineURL, DOI etc).""" bibliography: Optional[str] """ A list of citations that form a bibliography on literature related / used in the dataset """ resourceLogoUrl: Optional[str] """ URL of the logo associated with a dataset.""" parentCollectionIdentifier: Optional[str] collectionIdentifier: Optional[str] formationPeriod: Optional[str] """ Text description of the time period during which the collection was assembled. E.g., “Victorian”, or “1922 - 1932”, or “c. 1750”. """ livingTimePeriod: Optional[str] """ Time period during which biological material was alive (for palaeontological collections). """ specimenPreservationMethod: Optional[str] """ """
class ImportRsp(BaseModel): """ Import response. """ job_id: int = Field(title="The job which was created for the run") # OrderedDict is not available in typings of python 3.6 # mappings: Dict[str, OrderedDict[str, str]] = Field(title="Fields mapping", default={}) # mappings: Dict[str, Dict[str, str]] = Field(title="Fields mapping", default={}) # found_users: Dict[str, Dict] = Field(title="Users found in TSV files", # description="key = user name; value = " # "dict with (key = 'id' if resolved, else 'email')", # default={}) # found_taxa: Dict[str, Optional[int]] = Field(title="Taxa found without ID in TSV files", # description="key = taxon NAME; value = " # "taxon ID if resolved, else None", # default={}) # warnings: List[str] = Field(title="Warnings from analysis", # default=[]) errors: List[str] = Field(title="Errors from analysis", default=[])
class _AddedToCollection(BaseModel): """ What's added to Collection comparing to the plain DB record. """ project_ids: List[int] = Field(title="The composing project IDs", min_items=1) provider_user: Optional[UserModel] = Field( title= """Is the person who is responsible for the content of this metadata record. Writer of the title and abstract.""") contact_user: Optional[UserModel] = Field( title= """Is the person who should be contacted in cases of questions regarding the content of the dataset or any data restrictions. This is also the person who is most likely to stay involved in the dataset the longest.""") creator_users: List[UserModel] = Field( title="""All people who are responsible for the creation of the collection. Data creators should receive credit for their work and should therefore be included in the citation.""", default=[]) creator_organisations: List[str] = Field( title="""All organisations who are responsible for the creation of the collection. Data creators should receive credit for their work and should therefore be included in the citation.""", default=[]) associate_users: List[UserModel] = Field( title="Other person(s) associated with the collection", default=[]) associate_organisations: List[str] = Field( title="Other organisation(s) associated with the collection", default=[])
class EMLMeta(BaseModel): """ EML metadata """ identifier: EMLIdentifier = Field(title="The unique identifier for the collection") titles: List[EMLTitle] = Field(title="Titles, at least 1", min_items=1) creators: List[EMLPerson] = Field(title="Creators, at least 1", min_items=1) metadataProviders: List[EMLPerson] = Field(title="Metadata providers, at least 1", min_items=1) associatedParties: List[EMLAssociatedPerson] = Field(title="Associated parties, at least 1", min_items=0) contacts: List[EMLPerson] = Field(title="Contacts, at least 1", min_items=1) pubDate: str """ The date that the resource was published. Use ISO 8601. """ language: str = Field(title="Resource language, ISO-639.2", default="eng") """ The language in which the resource (not the metadata document) is written. Use ISO language code. """ abstract: List[str] = Field(title="Paragraphs forming the abstract", min_items=1) """ The abstract or description of a dataset provides basic information on the content of the dataset. The information in the abstract should improve understanding and interpretation of the data. It is recommended that the description indicates whether the dataset is a subset of a larger dataset and – if so – provide a link to the parent metadata and/or dataset. If the data provider or OBIS node require bi- or multilingual entries for the description (e.g. due to national obligations) then the following procedure can be followed: Indicate English as metadata language Enter the English description first Type a slash (/) Enter the description in the second language Example The Louis-Marie herbarium grants a priority to the Arctic-alpine, subarctic and boreal species from the province of Quebec and the northern hemisphere. This dataset is mainly populated with specimens from the province of Quebec. / L’Herbier Louis-Marie accorde une priorité aux espèces arctiques-alpines, subarctiques et boréales du Québec, du Canada et de l’hémisphère nord. Ce jeu présente principalement des spécimens provenant du Québec. """ keywordSet: EMLKeywordSet additionalInfo: Optional[str] """ OBIS checks this EML field for harvesting. It should contain marine, harvested by iOBIS. """ geographicCoverage: EMLGeoCoverage temporalCoverage: EMLTemporalCoverage generalTaxonomicCoverage: Optional[str] taxonomicCoverage: List[EMLTaxonomicClassification] intellectualRights: str """ AKA licence """ informationUrl: str """ A back-link to the dataset origin """ purpose: Optional[str] """ A description of the purpose of this dataset. """ methods: Optional[EMLMethod] """ Methods - sort of deprecated """ project: Optional[EMLProject] # TODO: is it project_s_ i.e. a list ? """ Project """ maintenanceUpdateFrequency: Optional[str] maintenance: Optional[str] """ Meta of meta""" additionalMetadata: EMLAdditionalMeta
class DwcExtendedMeasurementOrFact(BaseModel): """ In case of doubt, eMoF table is better as more precise. E.g. prefer eMoF for samplingProtocol rather than DwC field. """ # Unicity eventID: str = Field(term="http://rs.tdwg.org/dwc/terms/eventID", is_id=True) # If related to the whole event, occurrenceID must not be present occurrenceID: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/occurrenceID") # Note: although measurementType, measurementValue and measurementUnit are free text fields, # it is recommended to fill them in with the "preferred label" given by the BODC parameter. measurementValue: str = Field( title="measurement value, free text", term="http://rs.tdwg.org/dwc/terms/measurementValue") # https://www.bodc.ac.uk/resources/vocabularies/vocabulary_search/L22/ measurementType: str = Field( title="measurement type, free text", term="http://rs.tdwg.org/dwc/terms/measurementType") measurementUnit: Optional[str] = Field( title="measurement unit, free text", term="http://rs.tdwg.org/dwc/terms/measurementUnit") # Controlled vocabulary # https://www.bodc.ac.uk/resources/vocabularies/vocabulary_search/P01/ # examples: # Temperature of the water body: search for "temperature%water%body" # Salinity of the water body with CTD: search for "salinity%CTD" # Measurements related to lithology (sediment characteristics): "lithology" # http://seadatanet.maris2.nl/bandit/browse_step.php for just P01 measurementValueID: Optional[str] = Field( title="controlled vocabulary value ID", term="http://rs.iobis.org/obis/terms/measurementValueID") measurementTypeID: str = Field( title="controlled vocabulary type ID", term="http://rs.iobis.org/obis/terms/measurementTypeID") # http://vocab.nerc.ac.uk/collection/P06/current/ measurementUnitID: Optional[str] = Field( title="controlled vocabulary unit ID", term="http://rs.iobis.org/obis/terms/measurementUnitID") measurementRemarks: Optional[str] = Field( title="free text", term="http://rs.iobis.org/obis/terms/measurementRemarks")
class ImportRealReq(BaseModel): """ Import for real, request. """ task_id: int = Field(title="The existing task to use") source_path: str = Field(title="Source path on server, to plain directory") taxo_mappings: Dict[str, str] = Field(title="Optional taxonomy mapping", default={}) skip_loaded_files: bool = Field(default=False) skip_existing_objects: bool = Field(default=False) update_mode: str = Field(title="Update data ('Yes'), including classification ('Cla')", default="") # From step 1 # TODO: Avoid duplication mappings: Dict[str, Dict[str, str]] = Field(title="Fields mapping", default={}) found_users: Dict[str, Dict] = Field(title="Users found in TSV files", description="key = user name; value = " "dict with (key = 'id' if resolved, else 'email')", default={}) found_taxa: Dict[str, Optional[int]] = Field(title="Taxa found in TSV files", description="key = taxon NAME; value = " "taxon ID if resolved, else None", default={}) rowcount: int = Field(title="Number of TSV rows, counted during validation", default=0)
class ImportPrepReq(BaseModel): """ Import preparation, request. """ task_id: int = Field(title="The existing task to use") source_path: str = Field(title="Source path on server, to zip or plain directory") taxo_mappings: Dict[str, str] = Field(title="Optional taxonomy mapping", default={}) skip_loaded_files: bool = Field(default=False) skip_existing_objects: bool = Field(default=False) update_mode: str = Field(title="Update data ('Yes'), including classification ('Cla')", default="")
class SubsetReq(BaseModel): """ Subset request. """ task_id: int = Field(title="The existing task to use.") filters: Dict[str, str] = Field(title="The filters to apply to project", default={}) dest_prj_id: int = Field(title="The destination project ID.") limit_type: LimitMethods = Field( title= "The type of limit_value: P for %, V for constant, both per category.") limit_value: float = Field( title="Limit value, e.g. 20% or 5 per copepoda.") do_images: bool = Field(title="If set, also clone images.")
class ProjectTaxoStatsModel(BaseModel): projid: int = Field(title="The project id") used_taxa: List[int] = Field( title="The taxa/category ids used inside the project", default=[]) nb_unclassified: int = Field( title="The number of unclassified objects inside the project") nb_validated: int = Field( title="The number of validated objects inside the project") nb_dubious: int = Field( title="The number of dubious objects inside the project") nb_predicted: int = Field( title="The number of predicted objects inside the project")
class _AddedToJob(BaseModel): """ What's added to a Job compared to the plain DB record. """ params: Dict[str, Any] = Field(title="Creation parameters", default={}) result: Dict[str, Any] = Field(title="Final result of the run", default={}) errors: List[str] = Field(title="The errors seen during last step", default=[]) question: Dict[str, Any] = Field( title="The data provoking job move to Asking state", default={}) reply: Dict[str, Any] = Field( title="The data provided as a reply to the question", default={}) inside: Dict[str, Any] = Field(title="Internal state of the job", default={})
class SubsetReq(BaseModel): """ Subset request. """ filters: Dict[str, str] = Field(title="The filters to apply to project", default={}) dest_prj_id: int = Field(title="The destination project ID.") group_type: GroupDefinitions = Field( title= "Define the groups in which to apply limits. C for categories, S for samples, A for acquisitions." ) limit_type: LimitMethods = Field( title= "The type of limit_value: P for %, V for constant, both per group.") limit_value: float = Field( title="Limit value, e.g. 20% or 5 per copepoda or 5% per sample.") do_images: bool = Field(title="If set, also clone images.")
class ImportPrepRsp(BaseModel): """ Import preparation, response. """ source_path: str = Field(title="Eventually amended source path on server") # OrderedDict is not available in typings of python 3.6 # mappings: Dict[str, OrderedDict[str, str]] = Field(title="Fields mapping", default={}) mappings: Dict[str, Dict[str, str]] = Field(title="Fields mapping", default={}) found_users: Dict[str, Dict] = Field(title="Users found in TSV files", description="key = user name; value = " "dict with (key = 'id' if resolved, else 'email')", default={}) found_taxa: Dict[str, Optional[int]] = Field(title="Taxa found without ID in TSV files", description="key = taxon NAME; value = " "taxon ID if resolved, else None", default={}) warnings: List[str] = Field(title="Warnings from analysis", default=[]) errors: List[str] = Field(title="Errors from analysis", description="Do NOT proceed to real import if not empty.", default=[]) rowcount: int = Field(title="Number of TSV rows, counted during validation", default=0)
class EMODNetMeta(BaseModel): """ The dataset metadata. Not to be confused with DwC metadata, which describes how data is organized. """ provider: str = Field( title="Person providing the metadata: name, institute, email") title: str = Field(title="Dataset title in English") orig_title: Optional[str] = Field( title="Dataset title in original language (and language)") contact: str = Field( title="Contact person for the dataset: name, institute, email") creator: List[str] = Field(title="Data creator(s): (name), institute", min_items=1) other_persons: List[str] = Field( title="Other person(s) associated with the dataset - Highly recommended" ) citation: str = Field(title="Dataset citation") license: str = Field(title="License or terms of use") abstract: str = Field(title="Abstract") extended_description: Optional[str] = Field( title="Extended description-Highly recommended") geo_coverage: str = Field(title="Geographical coverage") temporal_coverage: str = Field(title="Temporal coverage") taxonomic_coverage: str = Field(title="Taxonomic coverage") themes: List[str] = Field(title="Themes", min_items=1) keywords: List[str] = Field(title="Keywords") websites: List[Url] = Field(title="Websites") related_publications: List[str] = Field( title="Publications related to the dataset - Highly recommended")
class DwcOccurrence(BaseModel): # Unicity eventID: str = Field(term="http://rs.tdwg.org/dwc/terms/eventID", is_id=True) occurrenceID: str = Field(term="http://rs.tdwg.org/dwc/terms/occurrenceID") # Identification fields scientificName: str = Field( term="http://rs.tdwg.org/dwc/terms/scientificName") # LSID from WoRMS for EMODnet scientificNameID: str = Field( term="http://rs.tdwg.org/dwc/terms/scientificNameID") # Count field individualCount: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/individualCount") # Taxon fields kingdom: Optional[str] = Field(term="http://rs.tdwg.org/dwc/terms/kingdom") taxonRank: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/taxonRank") scientificNameAuthorship: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/scientificNameAuthorship") # Occurrence fields occurrenceStatus: OccurrenceStatusEnum = Field( term="http://rs.tdwg.org/dwc/terms/occurrenceStatus") # Record-level fields basisOfRecord: BasisOfRecordEnum = Field( term="http://rs.tdwg.org/dwc/terms/basisOfRecord") # For museum collectionCode: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/collectionCode") catalogNumber: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/catalogNumber") # Identification fields, eg. "cf." identificationQualifier: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/identificationQualifier") # Record DwC fields modified: Optional[str] = Field(term="http://purl.org/dc/terms/modified")
class ExportReq(BaseModel): """ Export request. """ project_id: int = Field(title="The project to export") exp_type: ExportTypeEnum = Field( title="The export type: 'TSV', 'BAK', 'DOI' or 'SUM'.") tsv_entities: str = Field( title="For 'TSV' type, the entities to export, one letter for each of " "O(bject), P(rocess), A(cquisition), S(ample), " "classification H(istory), C(omments).") split_by: str = Field( title="For 'TSV' type, inside archives, split in one directory per... " "'sample', 'taxo' or '' (no split)") coma_as_separator: bool = Field( title="For 'TSV' type, use a , instead of . for decimal separator.") format_dates_times: bool = Field( title= "For 'TSV' type, format dates and times using - and : respectively.") with_images: bool = Field( title="For 'BAK' and 'DOI' types, export images as well.") with_internal_ids: bool = Field( title="For 'BAK' and 'DOI' types, export internal DB IDs.") only_first_image: bool = Field( title="For 'DOI' type, export only first (displayed) image.") sum_subtotal: str = Field( title="For 'SUM' type, how subtotals should be calculated. " "Per A(cquisition) or S(ample) or ''") out_to_ftp: bool = Field( title="Copy result file to FTP area. Original file is still available." )
class EMODnetExportReq(BaseModel): """ EMODNet format export request. """ # meta: EMLMeta = Field(title="EML meta for the produced archive") project_ids: List[int] = Field(title="The projects to export", min_items=1)
class SubsetRsp(BaseModel): """ Subset response. """ job_id: int = Field(title="The job created for this operation.")
class MergeRsp(BaseModel): """ Merge response. """ errors: List[str] = Field(title="The errors found during processing.", default=[])
class DwcEvent(BaseModel): # Unicity eventID: str = Field(term="http://rs.tdwg.org/dwc/terms/eventID", is_id=True) parentEventID: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/parentEventID") institutionCode: str = Field( term="http://rs.tdwg.org/dwc/terms/institutionCode") """ The name (or acronym) in use by the institution having custody of the object(s) or information referred to in the record. Examples `MVZ`, `FMNH`, `CLO`, `UCMP`""" datasetName: str = Field(term="http://rs.tdwg.org/dwc/terms/datasetName") # Can be date, date+time or date range using "/" eventDate: str = Field(term="http://rs.tdwg.org/dwc/terms/eventDate") # Location DwC fields decimalLatitude: str = Field( term="http://rs.tdwg.org/dwc/terms/decimalLatitude") decimalLongitude: str = Field( term="http://rs.tdwg.org/dwc/terms/decimalLongitude") geodeticDatum: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/geodeticDatum") coordinateUncertaintyInMeters: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/coordinateUncertaintyInMeters") minimumDepthInMeters: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/minimumDepthInMeters") maximumDepthInMeters: Optional[str] = Field( term="http://rs.tdwg.org/dwc/terms/maximumDepthInMeters") footprintWKT: Optional[str] = Field(term="http://purl.org/dc/terms/type") # Record DwC fields type: RecordTypeEnum = Field(term="http://purl.org/dc/terms/type") modified: Optional[str] = Field(term="http://purl.org/dc/terms/modified")
class _AddedToProject(BaseModel): obj_free_cols: FreeColT = Field(title="Object free columns", default={}) sample_free_cols: FreeColT = Field(title="Sample free columns", default={}) acquisition_free_cols: FreeColT = Field(title="Acquisition free columns", default={}) process_free_cols: FreeColT = Field(title="Process free columns", default={}) init_classif_list: List[int] = Field( title="Favorite taxa used in classification", default=[]) managers: List[UserModel] = Field(title="Managers of this project", default=[]) annotators: List[UserModel] = Field( title="Annotators of this project, if not manager", default=[]) viewers: List[UserModel] = Field( title="Viewers of this project, if not manager nor annotator", default=[]) contact: Optional[UserModel] = Field( title= "The contact person is a manager who serves as the contact person for other users and EcoTaxa's managers." ) highest_right: str = Field( title= "The highest right for requester on this project. One of 'Manage', 'Annotate', 'View'.", default="") license: LicenseEnum = Field(title="Data licence", default=LicenseEnum.Copyright) # owner: UserModel = Field(title="Owner of this project") class Config: schema_extra = { "example": { "obj_free_cols": { "area": "n01", "esd": "n02" }, "sample_free_cols": { "barcode": "t01" }, "acquisition_free_cols": { "flash_delay": "t01" }, "process_free_cols": { "nb_images": "t01" }, } }