diff --git a/Makefile b/Makefile index 0508fb0..c041a77 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ # Important directories VUE_APP_DIR = shacl-vue DIST_DIR = dist +PLUGIN_DIR = plugins +RUNTIME_PLUGIN_DIR = $(VUE_APP_DIR)/src/runtime-plugins all: build @@ -9,9 +11,11 @@ install: npm install vite cd $(VUE_APP_DIR) && npm install +# Copy runtime plugins before build # Build shacl-vue using top-level Vite-config # Copy shacl-vue config to dist directory build: clean + cp -r $(PLUGIN_DIR) $(RUNTIME_PLUGIN_DIR) cd $(VUE_APP_DIR) && npm run build:app mv $(VUE_APP_DIR)/dist/app ./$(DIST_DIR) cp -r templates $(DIST_DIR)/ diff --git a/config.yaml b/config.yaml index 079020c..aaf3e29 100644 --- a/config.yaml +++ b/config.yaml @@ -4,6 +4,11 @@ app_name: TRR379 Knowledge Pooling Tool (v0) documentation_url: https://docs.trr379.de/howtos/pool-tool/index.html external_config_url: https://pool.v0.trr379.de/ui/config_ri_default.yaml +footer_links: + - url: https://www.fz-juelich.de/en/legal-notice + text: Legal notice + - url: https://dfg-cp-survey.trr379.de/#privacy-policy + text: Privacy policy page_title: TRR379 Knowledge source_code_url: https://hub.trr379.de/q02/pool.v0.trr379.de-ui @@ -13,14 +18,20 @@ source_code_url: https://hub.trr379.de/q02/pool.v0.trr379.de-ui content: depiction-upload-template: url: templates/depiction-upload.ttl - doi-template: - url: templates/doi.ttl + doi-import-wizard-template: + url: templates/doi-import-wizard.nunjucks.ttl doi-logo: url: https://hub.psychoinformatics.de/datalink/assets/raw/branch/main/shacl-vue/DOI_logo_24.svg + doi-template: + url: templates/doi.ttl file-upload-template: url: templates/file-upload.ttl FrontPageHTML: url: frontpage.html + orcid-logo: + url: https://hub.psychoinformatics.de/datalink/assets/raw/branch/main/shacl-vue/orcid_logo_24.svg + person-depiction-upload-template: + url: templates/person-depiction-upload.nunjucks.ttl # -------------- @@ -52,21 +63,77 @@ component_config: NodeShapeViewer: recordNumberStepSize: 5 textTruncateWidth: '85%' + hideBackLinks: + - dlthings:AnnotationTag + - dlthings:Convention + - dlthings:Property + - dlthings:Rule + - trr379ri:TRR379AgentRole + - trr379ri:TRR379Activity + - trr379ri:TRR379ActivityRole + specialButtons: + ORCID: + slot: dcterms:identifier + match: + - key: rdf:type + val: trr379ri:ORCID + return: skos:notation + template: 'https://orcid.org/{return}' + icon: content:orcid-logo + tooltip: Visit ORCID page + DOI: + slot: dcterms:identifier + match: + - key: rdf:type + val: dlthings:DOI + return: skos:notation + template: 'https://doi.org/{return}' + icon: content:doi-logo + tooltip: Go to DOI + DownloadUrl: + slot: dlthings:characterized_by + match: + - key: rdf:type + val: dlthings:Statement + - key: rdf:predicate + val: dcat:downloadUrl + return: rdf:object + template: '{return}' + icon: mdi-download + tooltip: Download + Homepage: + slot: dlthings:attributes + match: + - key: rdf:type + val: dlthings:AttributeSpecification + - key: rdf:predicate + val: foaf:homepage + return: rdf:value + template: '{return}' + icon: mdi-home + tooltip: Homepage W3CISO8601DateTimeEditor: yearStart: 1990 yearEnd: 2028 +filter_records_by: + - dlthings:short_name id_resolves_externally: - trr379root show_classes: - - https://concepts.datalad.org/s/things/v2/AnnotationTag - - https://concepts.datalad.org/s/things/v2/Convention + - dlthings:AnnotationTag + - dlthings:Convention # must list the next to get all identifiers to show - - https://concepts.datalad.org/s/things/v2/Identifier - - https://concepts.datalad.org/s/things/v2/DOI - - https://concepts.datalad.org/s/things/v2/ISSN - - https://concepts.datalad.org/s/things/v2/ORCID - - https://concepts.datalad.org/s/things/v2/Rule - - https://concepts.datalad.org/s/things/v2/Property + - dlthings:Identifier + - dlthings:DOI + - dlthings:ISSN + - dlthings:ORCID + - dlthings:Rule + - dlthings:Property +priority_classes: + - class: dlthings:Thing + icon: mdi-view-list + title: All + include_subclasses: true # ----------------------- # Service API integration @@ -76,18 +143,20 @@ service_base_url: type: write - url: https://pool.v0.trr379.de/api/public/ type: read -token_info: Please refer to the documentation on how to obtain a new token. +token_info: Please refer to the documentation on how to obtain a new token token_info_url: https://docs.trr379.de/howtos/pool-tool/setup/index.html use_service: true use_token: true service_fetch_before: - get-record: [] - get-records: [] -footer_links: - - url: https://www.fz-juelich.de/en/legal-notice - text: Legal notice - - url: https://dfg-cp-survey.trr379.de/#privacy-policy - text: Privacy policy + get-records: + - dlthings:AnnotationTag + - dlthings:Convention + - dlthings:Property + - dlthings:Rule + - trr379ri:TRR379Activity + - trr379ri:TRR379AgentRole + - trr379ri:TRR379DepictionType + - trr379ri:TRR379Person # ---------------- # Special features @@ -104,23 +173,24 @@ gitannex_p2phttp_config_wizard: - name: TRR379 Hub base_url: https://hub.trr379.de/git-annex-p2phttp/git-annex repositories: - - name: File Upload Repo + - name: Public uploads annex_uuid: d10eeb70-bb68-4ae4-8c5a-713203d86733 -# ------------- -# Update Shapes -# ------------- -# would also work for any usage of a slot via update_shapes_default + _all_property_shapes -update_shapes: - trr379ri:TRR379Person: - dlthings:depiction: - # this triggers the button - shaclvue:gitAnnexUpload: true - # ------- # Wizards # ------- wizard_editors: + DepictionUploadWizard: + name: Depiction Upload Wizard + tooltip: Upload a depiction + icon: mdi-account-box-outline + description: Upload an image of the person and hit *Save* + inputs: + - prop: file + name: File + type: upload + required: true + template: content:person-depiction-upload-template DOIWizard: name: DOI Wizard tooltip: Add a Digital Object Identifier @@ -136,6 +206,40 @@ wizard_editors: # pattern: # default: template: content:doi-template + DOIImportWizard: + name: DOI Import Wizard + tooltip: Import a publication via DOI + icon: mdi-import + description: >- + Enter the 'DOI' field and hit *Import* in order to import metadata. + This will prepopulate editable fields such as *Title* and *Authors*. + An attempt is made to match individual imported *Author*s with known + *Person* records via ORCID identifiers. These matches can be accepted + as is without editing. The dropdown next to each imported and unmatched + author can be used to manually identify the correct associated Person + record. Also, additional authors can be added to the list. If no Person + record is selected for any given author in the list, a new Person record + will be created with a random and unique identifier, associated with the + entered given and family name. + component: doi:DOIFetcher + inputs: + - prop: title + type: text + - prop: abstract + type: text-paragraph + - prop: authors + type: object + multi_valued: true + inputs: + - prop: pid + type: text + - prop: given_name + type: text + - prop: family_name + type: text + - prop: role + type: select + template: content:doi-import-wizard-template FileUploadWizard: name: File Upload Wizard tooltip: Upload a file @@ -148,7 +252,12 @@ wizard_editors: required: true template: content:file-upload-template wizard_editor_selection: + trr379ri:TRR379Person: + _record: + - DepictionUploadWizard trr379ri:TRR379Publication: + _class: + - DOIImportWizard _record: - DOIWizard _slots: diff --git a/config_ri_default.yaml b/config_ri_default.yaml index 6db9099..7c9a816 100644 --- a/config_ri_default.yaml +++ b/config_ri_default.yaml @@ -33,108 +33,40 @@ use_default_shapes: false # Identifier settings # ------------------- id_autogenerate: - https://concepts.datalad.org/s/things/v2/AnnotationTag: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: annotation-tags/ - https://concepts.datalad.org/s/things/v2/Property: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: properties/ - https://concepts.datalad.org/s/things/v2/Rule: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: rules/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Accolade: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: accolades/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Activity: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: activities/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379ActivityRole: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: activity-roles/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379AgentRole: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: agent-roles/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379BibliographicType: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: bibliographic-types/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Competition: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: competitions/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379CompetitionType: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: competition-types/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Concept: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: concepts/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Convention: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: conventions/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379DataItem: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: dataitems/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379DataType: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: datatypes/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Dataset: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: datasets/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Depiction: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: depictions/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379DepictionType: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: depiction-types/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Document: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: documents/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379EntityRole: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: entity-roles/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379File: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: files/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Grant: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: grants/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Instrument: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: instruments/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379InstrumentType: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: instrument-types/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Objective: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: objectives/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Organization: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: organizations/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Person: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: persons/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Project: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: projects/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Publication: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: publications/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379PublicationVenue: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: publication-venues/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Quality: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: qualities/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Study: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: studies/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Subject: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: subjects/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379SubjectType: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: subject-types/ - https://concepts.trr379.de/s/research-information/unreleased/TRR379Topic: - id_autogenerate_prefix: trr379 - id_autogenerate_prepend: topics/ + dlthings:AnnotationTag: 'trr379:annotation-tags/{_randomUUID}' + dlthings:Property: 'trr379:properties/{_randomUUID}' + dlthings:Rule: 'trr379:rules/{_randomUUID}' + trr379ri:TRR379Accolade: 'trr379:accolades/{_randomUUID}' + trr379ri:TRR379Activity: 'trr379:activities/{_randomUUID}' + trr379ri:TRR379ActivityRole: 'trr379:activity-roles/{_randomUUID}' + trr379ri:TRR379AgentRole: 'trr379:agent-roles/{_randomUUID}' + trr379ri:TRR379BibliographicType: 'trr379:bibliographic-types/{_randomUUID}' + trr379ri:TRR379Competition: 'trr379:competitions/{_randomUUID}' + trr379ri:TRR379CompetitionType: 'trr379:competition-types/{_randomUUID}' + trr379ri:TRR379Concept: 'trr379:concepts/{_randomUUID}' + trr379ri:TRR379Convention: 'trr379:conventions/{_randomUUID}' + trr379ri:TRR379DataItem: 'trr379:dataitems/{_randomUUID}' + trr379ri:TRR379DataType: 'trr379:datatypes/{_randomUUID}' + trr379ri:TRR379Dataset: 'trr379:datasets/{_randomUUID}' + trr379ri:TRR379Depiction: 'trr379:depictions/{_randomUUID}' + trr379ri:TRR379DepictionType: 'trr379:depiction-types/{_randomUUID}' + trr379ri:TRR379Document: 'trr379:documents/{_randomUUID}' + trr379ri:TRR379EntityRole: 'trr379:entity-roles/{_randomUUID}' + trr379ri:TRR379File: 'trr379:files/{_randomUUID}' + trr379ri:TRR379Grant: 'trr379:grants/{_randomUUID}' + trr379ri:TRR379Instrument: 'trr379:instruments/{_randomUUID}' + trr379ri:TRR379InstrumentType: 'trr379:instrument-types/{_randomUUID}' + trr379ri:TRR379Objective: 'trr379:objectives/{_randomUUID}' + trr379ri:TRR379Organization: 'trr379:organizations/{_randomUUID}' + trr379ri:TRR379Person: 'trr379:persons/{_randomUUID}' + trr379ri:TRR379Project: 'trr379:projects/{_randomUUID}' + trr379ri:TRR379Publication: 'trr379:publications/{_randomUUID}' + trr379ri:TRR379PublicationVenue: 'trr379:publication-venues/{_randomUUID}' + trr379ri:TRR379Quality: 'trr379:qualities/{_randomUUID}' + trr379ri:TRR379Study: 'trr379:studies/{_randomUUID}' + trr379ri:TRR379Subject: 'trr379:subjects/{_randomUUID}' + trr379ri:TRR379SubjectType: 'trr379:subject-types/{_randomUUID}' + trr379ri:TRR379Topic: 'trr379:topics/{_randomUUID}' id_autogenerate_override: true id_iri: https://concepts.datalad.org/s/things/v2/pid id_resolves_externally: @@ -158,80 +90,80 @@ id_resolves_externally: # ------------ allow_copy_record_urls: true allow_edit_instances: - - https://concepts.datalad.org/s/things/v2/Checksum - - https://concepts.datalad.org/s/things/v2/DOI - - https://concepts.trr379.de/s/research-information/unreleased/TRR379Communication - - https://concepts.trr379.de/s/research-information/unreleased/TRR379Influence + - dlthings:Checksum + - dlthings:DOI + - trr379ri:TRR379Communication + - trr379ri:TRR379Influence class_name_display: name class_icons: - https://concepts.trr379.de/s/research-information/unreleased/ORCID: mdi-identifier - https://concepts.trr379.de/s/research-information/unreleased/TRR379Accolade: mdi-medal - https://concepts.trr379.de/s/research-information/unreleased/TRR379Activity: mdi-run - https://concepts.trr379.de/s/research-information/unreleased/TRR379ActivityRole: mdi-washing-machine - https://concepts.trr379.de/s/research-information/unreleased/TRR379AgentRole: mdi-function - https://concepts.trr379.de/s/research-information/unreleased/TRR379BibliographicType: mdi-newspaper - https://concepts.trr379.de/s/research-information/unreleased/TRR379Communication: mdi-message-text-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379Competition: mdi-podium-gold - https://concepts.trr379.de/s/research-information/unreleased/TRR379CompetitionType: mdi-podium - https://concepts.trr379.de/s/research-information/unreleased/TRR379Concept: mdi-shape-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379DataItem: mdi-file-document-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379DataType: mdi-tape-measure - https://concepts.trr379.de/s/research-information/unreleased/TRR379Dataset: mdi-database - https://concepts.trr379.de/s/research-information/unreleased/TRR379Depiction: mdi-image - https://concepts.trr379.de/s/research-information/unreleased/TRR379DepictionType: mdi-folder-multiple-image - https://concepts.trr379.de/s/research-information/unreleased/TRR379Document: mdi-file-document-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379EntityRole: mdi-excavator - https://concepts.trr379.de/s/research-information/unreleased/TRR379File: mdi-folder-arrow-right-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379Grant: mdi-cash-100 - https://concepts.trr379.de/s/research-information/unreleased/TRR379Influence: mdi-arrow-decision - https://concepts.trr379.de/s/research-information/unreleased/TRR379Instrument: mdi-microscope - https://concepts.trr379.de/s/research-information/unreleased/TRR379InstrumentType: mdi-beaker-question-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379Objective: mdi-bullseye-arrow - https://concepts.trr379.de/s/research-information/unreleased/TRR379Organization: mdi-account-group - https://concepts.trr379.de/s/research-information/unreleased/TRR379Person: mdi-face-man - https://concepts.trr379.de/s/research-information/unreleased/TRR379Project: mdi-briefcase-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379Publication: mdi-newspaper-variant-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379PublicationVenue: mdi-office-building-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379Quality: mdi-bag-personal-tag-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379Study: mdi-school-outline - https://concepts.trr379.de/s/research-information/unreleased/TRR379Subject: mdi-account-search - https://concepts.trr379.de/s/research-information/unreleased/TRR379SubjectType: mdi-tag-search - https://concepts.trr379.de/s/research-information/unreleased/TRR379Topic: mdi-book-information-variant - https://concepts.datalad.org/s/things/v2/Annotation: mdi-tag-outline - https://concepts.datalad.org/s/things/v2/AnnotationTag: mdi-tag-outline - https://concepts.datalad.org/s/things/v2/Association: mdi-account-switch - https://concepts.datalad.org/s/things/v2/Attribution: mdi-account-star - https://concepts.datalad.org/s/things/v2/AttributeSpecification: mdi-playlist-check - https://concepts.datalad.org/s/things/v2/Checksum: mdi-file-check-outline - https://concepts.datalad.org/s/things/v2/Communication: mdi-message-text-outline - https://concepts.datalad.org/s/things/v2/Convention: mdi-script-text-outline - https://concepts.datalad.org/s/things/v2/Dataset: mdi-database - https://concepts.datalad.org/s/things/v2/DataItem: mdi-file-document-outline - https://concepts.datalad.org/s/things/v2/Delegation: mdi-badge-account - https://concepts.datalad.org/s/things/v2/Derivation: mdi-toolbox - https://concepts.datalad.org/s/things/v2/Document: mdi-file-document-outline - https://concepts.datalad.org/s/things/v2/DOI: mdi-identifier - https://concepts.datalad.org/s/things/v2/End: mdi-clock-end - https://concepts.datalad.org/s/things/v2/File: mdi-folder-arrow-right-outline - https://concepts.datalad.org/s/things/v2/Generation: mdi-auto-fix - https://concepts.datalad.org/s/things/v2/Grant: mdi-cash-100 - https://concepts.datalad.org/s/things/v2/Identifier: mdi-identifier - https://concepts.datalad.org/s/things/v2/Influence: mdi-arrow-decision - https://concepts.datalad.org/s/things/v2/Instrument: mdi-microscope - https://concepts.datalad.org/s/things/v2/Invalidation: mdi-glass-fragile - https://concepts.datalad.org/s/things/v2/Organization: mdi-account-group - https://concepts.datalad.org/s/things/v2/Person: mdi-face-man - https://concepts.datalad.org/s/things/v2/Project: mdi-briefcase-outline - https://concepts.datalad.org/s/things/v2/Property: mdi-contain-start - https://concepts.datalad.org/s/things/v2/Publication: mdi-newspaper-variant-outline - https://concepts.datalad.org/s/things/v2/Quotation: mdi-comment-quote - https://concepts.datalad.org/s/things/v2/Revision: mdi-numeric-positive-1 - https://concepts.datalad.org/s/things/v2/Rule: mdi-gavel - https://concepts.datalad.org/s/things/v2/Start: mdi-clock-start - https://concepts.datalad.org/s/things/v2/Statement: mdi-comment-text-outline - https://concepts.datalad.org/s/things/v2/Study: mdi-school-outline - https://concepts.datalad.org/s/things/v2/Subject: mdi-account-search - https://concepts.datalad.org/s/things/v2/Usage: mdi-format-list-checks + trr379ri:ORCID: mdi-identifier + trr379ri:TRR379Accolade: mdi-medal + trr379ri:TRR379Activity: mdi-run + trr379ri:TRR379ActivityRole: mdi-washing-machine + trr379ri:TRR379AgentRole: mdi-function + trr379ri:TRR379BibliographicType: mdi-newspaper + trr379ri:TRR379Communication: mdi-message-text-outline + trr379ri:TRR379Competition: mdi-podium-gold + trr379ri:TRR379CompetitionType: mdi-podium + trr379ri:TRR379Concept: mdi-shape-outline + trr379ri:TRR379DataItem: mdi-file-document-outline + trr379ri:TRR379DataType: mdi-tape-measure + trr379ri:TRR379Dataset: mdi-database + trr379ri:TRR379Depiction: mdi-image + trr379ri:TRR379DepictionType: mdi-folder-multiple-image + trr379ri:TRR379Document: mdi-file-document-outline + trr379ri:TRR379EntityRole: mdi-excavator + trr379ri:TRR379File: mdi-folder-arrow-right-outline + trr379ri:TRR379Grant: mdi-cash-100 + trr379ri:TRR379Influence: mdi-arrow-decision + trr379ri:TRR379Instrument: mdi-microscope + trr379ri:TRR379InstrumentType: mdi-beaker-question-outline + trr379ri:TRR379Objective: mdi-bullseye-arrow + trr379ri:TRR379Organization: mdi-account-group + trr379ri:TRR379Person: mdi-face-man + trr379ri:TRR379Project: mdi-briefcase-outline + trr379ri:TRR379Publication: mdi-newspaper-variant-outline + trr379ri:TRR379PublicationVenue: mdi-office-building-outline + trr379ri:TRR379Quality: mdi-bag-personal-tag-outline + trr379ri:TRR379Study: mdi-school-outline + trr379ri:TRR379Subject: mdi-account-search + trr379ri:TRR379SubjectType: mdi-tag-search + trr379ri:TRR379Topic: mdi-book-information-variant + dlthings:Annotation: mdi-tag-outline + dlthings:AnnotationTag: mdi-tag-outline + dlthings:Association: mdi-account-switch + dlthings:Attribution: mdi-account-star + dlthings:AttributeSpecification: mdi-playlist-check + dlthings:Checksum: mdi-file-check-outline + dlthings:Communication: mdi-message-text-outline + dlthings:Convention: mdi-script-text-outline + dlthings:Dataset: mdi-database + dlthings:DataItem: mdi-file-document-outline + dlthings:Delegation: mdi-badge-account + dlthings:Derivation: mdi-toolbox + dlthings:Document: mdi-file-document-outline + dlthings:DOI: mdi-identifier + dlthings:End: mdi-clock-end + dlthings:File: mdi-folder-arrow-right-outline + dlthings:Generation: mdi-auto-fix + dlthings:Grant: mdi-cash-100 + dlthings:Identifier: mdi-identifier + dlthings:Influence: mdi-arrow-decision + dlthings:Instrument: mdi-microscope + dlthings:Invalidation: mdi-glass-fragile + dlthings:Organization: mdi-account-group + dlthings:Person: mdi-face-man + dlthings:Project: mdi-briefcase-outline + dlthings:Property: mdi-contain-start + dlthings:Publication: mdi-newspaper-variant-outline + dlthings:Quotation: mdi-comment-quote + dlthings:Revision: mdi-numeric-positive-1 + dlthings:Rule: mdi-gavel + dlthings:Start: mdi-clock-start + dlthings:Statement: mdi-comment-text-outline + dlthings:Study: mdi-school-outline + dlthings:Subject: mdi-account-search + dlthings:Usage: mdi-format-list-checks component_config: # InstancesUploadEditor: InstancesSelectEditor: @@ -242,12 +174,6 @@ component_config: - trr379ri hide_classes: [] hide_classes_with_prefix: [] - InstancesUploadEditor: - trr379ri:TRR379Depiction: - pid_template: "trr379:depictions/{_randomUUID}" - # this effectively limits the use of the Depiction class to - # portrait images -- which is why we want to use the wizard approach instead - ttl_template: content:depiction-upload-template URIEditor: default: curie W3CISO8601DateTimeEditor: @@ -313,7 +239,7 @@ filter_records_by: hide_classes: [] hide_classes_with_prefix: [] no_edit_classes: - - https://concepts.trr379.de/s/research-information/unreleased/TRR379BibliographicType + - trr379ri:TRR379BibliographicType show_all_fields: false show_classes_with_prefix: - trr379ri @@ -329,6 +255,7 @@ service_endpoints: post-record: 'record/{name}?format=ttl' get-record: 'record?pid={curie}&format=ttl' get-records: 'records/{name}?format=ttl' + get-records-before: 'records/{name}?format=ttl' get-paginated-records: 'records/p/{name}?format=ttl&size=100&page={page_number}' get-paginated-records-constrained: 'records/p/{name}?format=ttl&matching=%25{match_string}%25&size=100&page={page_number}' # service_fetch_before: @@ -663,46 +590,51 @@ update_shapes_default: update_shapes: +# Things + dlthings:Thing: + rdfs:label: All types + rdfs:comment: Here you can search through records of all types (i.e. any `Thing`) + # Things that are "classifiers" (i.e., tags) without a provenance interface # Non-Things, such as association classes dlthings:Association: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole sh:or: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Person - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Organization sh:class: null dlthings:roles: - sh:class: https://concepts.trr379.de/s/research-information/unreleased/TRR379AgentRole + sh:class: trr379ri:TRR379AgentRole dlthings:Attribution: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole sh:or: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Person - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Organization sh:class: null dlthings:roles: - sh:class: https://concepts.trr379.de/s/research-information/unreleased/TRR379AgentRole + sh:class: trr379ri:TRR379AgentRole dlthings:Delegation: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole sh:or: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Person - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Organization sh:class: null dlthings:roles: - sh:class: https://concepts.trr379.de/s/research-information/unreleased/TRR379AgentRole + sh:class: trr379ri:TRR379AgentRole dlthings:Communication: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole sh:or: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Activity - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Competition @@ -710,12 +642,12 @@ update_shapes: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Study sh:class: null dlthings:roles: - sh:class: https://concepts.trr379.de/s/research-information/unreleased/TRR379ActivityRole + sh:class: trr379ri:TRR379ActivityRole dlthings:Generation: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole sh:or: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Activity - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Competition @@ -723,12 +655,12 @@ update_shapes: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Study sh:class: null dlthings:roles: - sh:class: https://concepts.trr379.de/s/research-information/unreleased/TRR379ActivityRole + sh:class: trr379ri:TRR379ActivityRole dlthings:Invalidation: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole sh:or: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Activity - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Competition @@ -736,27 +668,27 @@ update_shapes: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Study sh:class: null dlthings:roles: - sh:class: https://concepts.trr379.de/s/research-information/unreleased/TRR379ActivityRole + sh:class: trr379ri:TRR379ActivityRole dlthings:Quotation: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole dlthings:Start: sh:property: dlthings:at_time: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole dlthings:End: sh:property: dlthings:at_time: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole trr379ri:TRR379Communication: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole sh:or: - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Activity - http://www.w3.org/ns/shacl#class: https://concepts.trr379.de/s/research-information/unreleased/TRR379Competition @@ -771,13 +703,8 @@ update_shapes: trr379ri:distributions: shaclvue:gitAnnexUpload: true - trr379ri:TRR379Person: - sh:property: - dlthings:depiction: - shaclvue:gitAnnexUpload: true - trr379ri:TRR379Influence: sh:property: rdf:object: - dash:propertyRole: http://datashapes.org/dash#KeyInfoRole + dash:propertyRole: dash:KeyInfoRole diff --git a/plugins/doi/DOIFetcher.vue b/plugins/doi/DOIFetcher.vue new file mode 100644 index 0000000..abfad90 --- /dev/null +++ b/plugins/doi/DOIFetcher.vue @@ -0,0 +1,261 @@ + + + + + diff --git a/plugins/doi/index.js b/plugins/doi/index.js new file mode 100644 index 0000000..bc452ff --- /dev/null +++ b/plugins/doi/index.js @@ -0,0 +1,201 @@ +import { DLTHINGS, RDF, SKOS } from '@/modules/namespaces'; +import { namespace } from 'shacl-tulip'; +import { DataFactory } from 'n3'; + +const { namedNode, blankNode, literal, quad } = DataFactory; +const DCTERMS = namespace('http://purl.org/dc/terms/'); +const OBO = namespace('http://purl.obolibrary.org/obo/'); +const MARCREL = namespace('http://id.loc.gov/vocabulary/relators/'); +const DOI_BASE = "https://doi.org/" +const TRR379RI = namespace('https://concepts.trr379.de/s/research-information/unreleased/'); + +export async function importMetadata(args) { + const doi = args.doi; + const rdfDS = args.rdfDS; + try { + let result = await fetchCSL(doi); + const enrichedRecord = processRecord(result, rdfDS); + return enrichedRecord + } catch (error) { + throw(error) + } +} + +async function fetchCSL(doi) { + const endpoint = `${DOI_BASE}${doi}` + const response = await fetch(endpoint, { + headers: { + Accept: "application/vnd.citationstyles.csl+json" + } + }) + if (!response.ok) { + throw new Error(`DOI lookup failed ${response.status}`) + } + return await response.json() +} + +async function fetchCitation(doi) { + const endpoint = `${DOI_BASE}${doi}` + const response = await fetch(endpoint, { + headers: { + Accept: "text/x-bibliography; style=apa" + } + }) + if (!response.ok) { + return null + } + return await response.text() +} + +function getAuthors(citeprocMetadata) { + return citeprocMetadata.author ?? [] +} + +function getContributions(citeprocMetadata, rdfDS) { + const authors = getAuthors(citeprocMetadata) + const persons = []; + const contributions = []; + for (const auth of authors) { + // if record has ORCID, try to find known Person with that identifier + // if person found via ORCID, this is the pid to add to the object slot of attribution + // if person not found: create new person record + let attr = { + roles: [getAuthorRole(auth)], + } + let person_pid + let person_found_via + if (auth['ORCID']) { + person_pid = findRecordWithIdentifier(auth['ORCID'].replace('https://orcid.org/', ''), rdfDS) + person_found_via = 'orcid' + } + attr['object'] = person_pid; + contributions.push(attr) + persons.push({ + pid: person_pid, + given_name: auth['given'] ? auth['given'] : '', + family_name: auth['family'] ? auth['family'] : '', + role: getAuthorRole(auth), + found_via: person_found_via, + }) + } + + return { + persons: persons, + contributions: contributions, + } +} + +function findRecordWithIdentifier(notation, rdfDS) { + + let identifiers = rdfDS.data.graph.getQuads( + null, + namedNode(SKOS.notation.value), + literal(notation), + null + ).map(q => q.subject); + const records = identifiers.flatMap(id => + rdfDS.data.graph.getQuads( + null, + namedNode(DCTERMS.identifier.value), + id, + null + ).map(q => q.subject) + ) + if (records.length) { + return records[0].value + } + return undefined +} + +export function findPublicationWithDOI(doi, rdfDS) { + // First try and find publication records with linked identifiers + // Then try to find publications with DOI as PID + let publication = findRecordWithIdentifier(doi, rdfDS) + if (publication) { + return publication + } else { + let pubPIDs = rdfDS.data.graph.getQuads( + namedNode(`${DOI_BASE}${doi}`), + namedNode(RDF.type.value), + namedNode(TRR379RI.TRR379Publication.value), + null + ).map(q => q.subject); + if (pubPIDs.length) { + return pubPIDs[0].value; + } + } + return undefined +} + +function findPersonWithNames(givenName, familyName, rdfDS) { + // persons with matching family name + const familyMatches = rdfDS.data.graph.getQuads( + null, + namedNode(DLTHINGS.family_name.value), + literal(familyName), + null + ).map(q => q.subject.value) + // persons with matching given name + const givenMatches = rdfDS.data.graph.getQuads( + null, + namedNode(DLTHINGS.given_name.value), + literal(givenName), + null + ).map(q => q.subject.value) + // intersection + const persons = familyMatches.filter(p => givenMatches.includes(p)) + if (persons.length) { + return persons[0] + } + return undefined +} + +function getAuthorRole(author) { + let seq = author['sequence'] + if (seq) { + if (seq == 'first') { + return OBO.MS_1002034.value; + } else if (seq == 'additional') { + return OBO.MS_1002036.value; + } else { + return MARCREL.aut.value; + } + } + return MARCREL.aut.value; +} + +function htmlDecode(input) { + var doc = new DOMParser().parseFromString(input, "text/html"); + return doc.documentElement.textContent; +} + +function getTitle(citeprocMetadata) { + return citeprocMetadata.title ? htmlDecode(citeprocMetadata.title) : '' +} + +function getAbstract(citeprocMetadata) { + return citeprocMetadata.abstract ? htmlDecode(citeprocMetadata.abstract) : '' +} + +function processRecord(citeprocMetadata, rdfDS) { + // authors => attributed_to and persons + // publishing activity (date / ISSN) => generated_by + // licenses => rules + const {persons, contributions} = getContributions(citeprocMetadata, rdfDS) + const title = getTitle(citeprocMetadata, rdfDS) + const abstract = getAbstract(citeprocMetadata, rdfDS) + const pub = { + attributed_to: contributions, + generated_by: [], + about: [], + description: "", + identifiers: [], + pid:'', + title:title, + } + return { + authors: persons, + title: title, + abstract: abstract, + } +} \ No newline at end of file diff --git a/shacl-vue b/shacl-vue index 718ab3b..c219907 160000 --- a/shacl-vue +++ b/shacl-vue @@ -1 +1 @@ -Subproject commit 718ab3bca7c9caf6dfcb475bfb7cf5b2ae77700e +Subproject commit c219907f5a87bf1940fc580faba9521c34fb3a17 diff --git a/templates/doi-import-wizard.nunjucks.ttl b/templates/doi-import-wizard.nunjucks.ttl new file mode 100644 index 0000000..10ed8d7 --- /dev/null +++ b/templates/doi-import-wizard.nunjucks.ttl @@ -0,0 +1,49 @@ +@prefix trr379: . +@prefix trr379ri: . +@prefix rdf: . +@prefix dlthings: . +@prefix obo: . +@prefix xsd: . +@prefix sio: . +@prefix dcterms: . +@prefix skos: . +@prefix orcid: . + +{% set pubId = _randomUUID() -%} +{% set pubURI = "https://trr379.de/ns/publications/" + pubId -%} +<{{ pubURI }}> a trr379ri:TRR379Publication . +{% if title -%} +<{{ pubURI }}> dlthings:title {{ title | ttl }} . +{%- endif %} +{% if abstract -%} +<{{ pubURI }}> dcterms:description {{ abstract | ttl }} . +{%- endif %} + +{% if doi %} +<{{ pubURI }}> dcterms:identifier _:doiNode . +_:doiNode a dlthings:DOI ; + skos:notation {{ doi | ttl }} . +{% endif %} + +{% for author in authors -%} +{% if author.pid %} +{% set personURI = author.pid -%} +{% else -%} +{% set personId = _randomUUID() -%} +{% set personURI = "https://trr379.de/ns/persons/" + personId -%} +<{{ personURI }}> a trr379ri:TRR379Person . +{% if author.given_name -%} +<{{ personURI }}> dlthings:given_name {{ author.given_name | ttl }} . +{%- endif %} + +{% if author.family_name -%} +<{{ personURI }}> dlthings:family_name {{ author.family_name | ttl }} . +{%- endif %} +{% endif %} + +<{{ pubURI }}> dlthings:attributed_to _:attr{{ loop.index }} . +_:attr{{ loop.index }} a dlthings:Attribution ; + rdf:object <{{ personURI }}> ; + dlthings:roles <{{ author.role }}> . + +{% endfor -%} \ No newline at end of file diff --git a/templates/person-depiction-upload.nunjucks.ttl b/templates/person-depiction-upload.nunjucks.ttl new file mode 100644 index 0000000..36869de --- /dev/null +++ b/templates/person-depiction-upload.nunjucks.ttl @@ -0,0 +1,30 @@ +@prefix dcat: . +@prefix dcterms: . +@prefix dldi: . +@prefix dlthings: . +@prefix rdf: . +@prefix skos: . +@prefix spdx: . +@prefix trr379: . +@prefix trr379ri: . +@prefix xsd: . + +{% set depictionId = _randomUUID() -%} +{% set depictionURI = "https://trr379.de/ns/depictions/" + depictionId -%} +dldi:{{ file.annexKey }} a trr379ri:TRR379File; + skos:prefLabel {{ file.name | ttl }}^^xsd:string; + dlthings:distribution_of <{{ depictionURI }}>; + dlthings:byte_size {{ file.size | ttl }}^^xsd:nonNegativeInteger; + dlthings:characterized_by _:n0-1. +_:n0-1 a dlthings:Statement; + rdf:object <{{ file.downloadUrl }}>; + rdf:predicate dcat:downloadUrl. +dldi:{{ file.annexKey }} dlthings:checksums _:n0-2. +_:n0-2 a dlthings:Checksum; + skos:notation {{ file.hash | ttl }}^^xsd:hexBinary; + dcterms:creator spdx:checksumAlgorithm_sha256. +<{{ depictionURI }}> a trr379ri:TRR379Depiction; + dcterms:subject <{{ pid }}>; + dcterms:type ; + dlthings:distributions dldi:{{ file.annexKey }}. +<{{ pid }}> dlthings:depiction <{{ depictionURI }}>. \ No newline at end of file