Upgrade to latest shacl-vue state, and accompanying config #18

Merged
jsheunis merged 8 commits from sv-upgrade into main 2026-03-30 14:03:19 +00:00
8 changed files with 814 additions and 233 deletions

View file

@ -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)/

View file

@ -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:

View file

@ -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

261
plugins/doi/DOIFetcher.vue Normal file
View file

@ -0,0 +1,261 @@
<template>
<v-row align="stretch">
<v-col cols="10">
<v-text-field v-model="doiText" label="DOI" variant="outlined" density="compact"></v-text-field>
<v-card v-if="showError" flat style="margin-top: 0">
<v-card-text>
<v-icon color="error">mdi-alert</v-icon> <em>{{ errorTitle }}:</em> {{ errorMessage }}
<v-btn @click="clearError" density="compact">Ok</v-btn>
</v-card-text>
</v-card>
</v-col>
<v-col>
<v-btn @click="checkThenImportMetadata">Import</v-btn>
</v-col>
</v-row>
<v-card flat variant="text" v-if="modelVals['title'] && modelVals['authors']">
<h2>Imported metadata</h2>
<br>
<h3>Title</h3>
<v-text-field
variant="outlined"
v-model="modelVals['title']"
density="compact">
</v-text-field>
<h3>Abstract</h3>
<v-textarea
variant="outlined"
v-model="modelVals['abstract']"
density="compact">
</v-textarea>
<h3>Authors</h3>
<v-card-text>
<span v-if="modelVals['authors'].length">
<v-row>
<v-col cols="2"><strong>Given Name</strong></v-col>
<v-col cols="2"><strong>Family Name</strong></v-col>
<v-col cols="3"><strong>Role</strong></v-col>
<v-col cols="3" class="d-flex justify-center align-center"><strong>Linked Record</strong></v-col>
<v-col cols="1" class="d-flex justify-center align-center"><strong>Type</strong></v-col>
<v-col></v-col>
</v-row>
<v-divider opacity=".7" thickness="1" style="margin-top: 1em; margin-bottom: 1em"></v-divider>
<v-row
no-gutters align="center" class="author-row"
v-for="(a, idx) in modelVals['authors']"
:disabled="a.type == 'matched'"
:class="a.type == 'matched' ? 'author-matched': ''"
:key="a.row_key"
>
<v-col cols="2">
<v-text-field
variant="outlined"
v-model="a.given_name"
density="compact"
hide-details="auto"
:disabled="a.type == 'matched'"
/>
</v-col>
<v-col cols="2">
<v-text-field
variant="outlined"
v-model="a.family_name"
density="compact"
hide-details="auto"
:disabled="a.type == 'matched'"
/>
</v-col>
<v-col cols="3">
<InstancesSelectEditor4Wiz
v-model="a.role"
:property_shape="prop_shape_role"
:allow_add="false"
:disabled="a.type == 'matched'"
/>
</v-col>
<v-col cols="3">
<InstancesSelectEditor4Wiz
v-model="a.pid"
:property_shape="prop_shape_person"
:allow_add="false"
:disabled="a.type == 'matched'"
/>
</v-col>
<v-col cols="1" class="d-flex justify-center align-center">
<span v-if="a.type == 'matched'">
<v-tooltip text="Matched">
<template v-slot:activator="{ props }">
<v-icon v-bind="props" color="success">mdi-check-all</v-icon>
</template>
</v-tooltip>
</span>
<span v-else-if="a.type == 'new' && a.pid">
<v-tooltip text="Selected">
<template v-slot:activator="{ props }">
<v-icon v-bind="props">mdi-account-check</v-icon>
</template>
</v-tooltip>
</span>
<span v-else>
<v-tooltip text="New">
<template v-slot:activator="{ props }">
<v-icon v-bind="props">mdi-account</v-icon>
</template>
</v-tooltip>
</span>
</v-col>
<v-col>
<v-btn variant="text" icon="mdi-trash-can" @click="removeAuthor(idx)"></v-btn>
</v-col>
</v-row>
<br>
<v-btn
@click="addAuthor()"
prepend-icon="mdi-plus"
density="compact"
>Add author</v-btn>
</span>
</v-card-text>
</v-card>
</template>
<script setup>
import { ref, inject, toRaw, onMounted, watch} from 'vue'
import { SHACL } from '@/modules/namespaces';
import InstancesSelectEditor4Wiz from '@/components/InstancesSelectEditor4Wiz.vue';
import { namespace } from 'shacl-tulip';
const TRR379RI = namespace('https://concepts.trr379.de/s/research-information/unreleased/');
const props = defineProps({
config: Object,
disabled: Boolean,
});
const modelVals = defineModel('modelVals')
const emit = defineEmits(['uploadComplete', 'init-form'])
const plugins = inject('runtimePlugins')
const fetchFromService = inject('fetchFromService')
const allPrefixes = inject('allPrefixes')
const rdfDS = inject('rdfDS')
const doiText = ref('')
const prop_shape_person = {
[SHACL.class.value]: TRR379RI.TRR379Person.value,
[SHACL.nodeKind.value]: SHACL.IRI.value,
[SHACL.path.value]:'',
[SHACL.description.value]:'',
}
const prop_shape_role = {
[SHACL.class.value]: TRR379RI.TRR379AgentRole.value,
[SHACL.nodeKind.value]: SHACL.IRI.value,
[SHACL.path.value]:'',
[SHACL.description.value]:'',
}
const showError = ref(false);
const errorTitle = ref('');
const errorMessage = ref('');
onMounted(() => {
})
function clearError() {
showError.value = false;
errorTitle.value = '';
errorMessage.value = '';
}
function loadError(title, message) {
showError.value = true;
errorTitle.value = title;
errorMessage.value = message;
}
function addAuthor() {
modelVals.value['authors'].push(
{
pid: null,
given_name: null,
family_name: null,
role: null,
row_key: crypto.randomUUID(),
}
)
}
function removeAuthor(idx) {
modelVals.value['authors'].splice(idx,1)
}
async function checkThenImportMetadata() {
// First check if a publication with the doi is already in the pool
// if so: instruct user to rather edit the existing record
// First do a constrained fetch for all publication records referencing the doi
const result = await fetchFromService(
'get-paginated-records-constrained',
TRR379RI.TRR379Publication.value,
allPrefixes,
doiText.value
);
if (result.status === null) {
console.error(result.error);
}
// Now we find a publication with said DOI, either in identifiers or as pid
let pub = await plugins['doi'].api.findPublicationWithDOI(doiText.value, rdfDS)
if (pub) {
let title = 'Known DOI'
let message = `A publication record with the specified DOI (${doiText.value}) already exists in the knowledge base. Please edit the existing record rather than importing a new one.`
loadError(title, message)
return
}
// Otherwise we continue
importMetadata()
}
// Validate file type and read it
const importMetadata = async () => {
clearError()
emit('init-form')
try {
let result = await plugins['doi'].api.importMetadata(
{
doi: doiText.value,
rdfDS: rdfDS,
}
)
modelVals.value['authors'] = result.authors;
modelVals.value['title'] = result.title;
modelVals.value['abstract'] = result.abstract;
modelVals.value['doi'] = doiText.value;
for (const a of modelVals.value['authors']) {
if (a.pid) {
a.type = 'matched';
} else {
a.type = 'new';
}
a.row_key = a.given_name+a.family_name;
}
} catch (error) {
let title = 'DOI Fetch Error'
let message = error
loadError(title, message)
console.error(error)
}
}
</script>
<style scoped>
.author-row:hover {
background-color: #7f7d7de5;
align-items: center;
}
.author-matched {
background-color: #7f7d7de5;
}
</style>

201
plugins/doi/index.js Normal file
View file

@ -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,
}
}

@ -1 +1 @@
Subproject commit 718ab3bca7c9caf6dfcb475bfb7cf5b2ae77700e
Subproject commit c219907f5a87bf1940fc580faba9521c34fb3a17

View file

@ -0,0 +1,49 @@
@prefix trr379: <https://trr379.de/ns/> .
@prefix trr379ri: <https://concepts.trr379.de/s/research-information/unreleased/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix dlthings: <https://concepts.datalad.org/s/things/v2/>.
@prefix obo: <http://purl.obolibrary.org/obo/>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix sio: <http://semanticscience.org/resource/>.
@prefix dcterms: <http://purl.org/dc/terms/>.
@prefix skos: <http://www.w3.org/2004/02/skos/core#>.
@prefix orcid: <https://orcid.org/>.
{% 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 -%}

View file

@ -0,0 +1,30 @@
@prefix dcat: <http://www.w3.org/ns/dcat#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix dldi: <https://pid.datalad.org/distributions/> .
@prefix dlthings: <https://concepts.datalad.org/s/things/v2/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix spdx: <http://spdx.org/rdf/terms#> .
@prefix trr379: <https://trr379.de/ns/> .
@prefix trr379ri: <https://concepts.trr379.de/s/research-information/unreleased/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
{% 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 <https://trr379.de/ns/depiction-types/e9a34f7d-d05e-4591-bb45-f8a0c499e07b>;
dlthings:distributions dldi:{{ file.annexKey }}.
<{{ pid }}> dlthings:depiction <{{ depictionURI }}>.