diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java index f00b5eba2f327885d7f84e74097d412e0ab5a341..62f095c82e79df65bd5a9407f735a432dedd502c 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java @@ -33,7 +33,7 @@ public class MariaDbContainerConfig { public static synchronized CustomMariaDBContainer getInstance() { if (instance == null) { - instance = new CustomMariaDBContainer("mariadb:11.2.2-debian-11-r0"); + instance = new CustomMariaDBContainer("mariadb:11.2.2"); instance.withImagePullPolicy(PullPolicy.alwaysPull()); instance.addFixedExposedPort(BaseTest.CONTAINER_1_PORT, BaseTest.IMAGE_1_PORT); instance.withUsername(BaseTest.CONTAINER_1_PRIVILEGED_USERNAME); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java index e404fb8947b195f432f325fb291d5923e1c4fc58..5129b49c0ff1b00e9c1ebc0f7488f2f45e0bbc39 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java @@ -34,7 +34,7 @@ public class MariaDbContainerConfig { public static synchronized CustomMariaDBContainer getInstance() { if (instance == null) { - instance = new CustomMariaDBContainer("mariadb:11.2.2-debian-11-r0"); + instance = new CustomMariaDBContainer("mariadb:11.2.2"); instance.withImagePullPolicy(PullPolicy.alwaysPull()); instance.addFixedExposedPort(BaseTest.CONTAINER_1_PORT, BaseTest.IMAGE_1_PORT); instance.withUsername(BaseTest.CONTAINER_1_PRIVILEGED_USERNAME); diff --git a/dbrepo-ui/api/database.mapper.js b/dbrepo-ui/api/database.mapper.js index c62122aebeb995e0ccd94ca6e64e67bb1ce6ffdf..85e4c53d5c0e21dce4e9f36e5ed4ddc3611e11a8 100644 --- a/dbrepo-ui/api/database.mapper.js +++ b/dbrepo-ui/api/database.mapper.js @@ -1,4 +1,5 @@ import UserMapper from '@/api/user.mapper' +const baseUrl = `${location.protocol}//${location.host}` class DatabaseMapper { databaseToOwner (database) { @@ -14,6 +15,31 @@ class DatabaseMapper { } return UserMapper.userToFullName(database.contact) } + + databaseToJsonLd (database) { + const jsonLd = { + '@context': 'https://schema.org/', + '@type': 'Dataset', + name: database.name, + description: 'Relational database hosted by the database repository.', + url: `${baseUrl}/database/${database.id}/info`, + isAccessibleForFree: database.is_public, + creator: { + '@type': 'Person' + } + } + jsonLd.creator.name = database.owner.name ? database.owner.name : database.owner.username + if (database.owner.given_name) { + jsonLd.creator.givenName = database.owner.given_name + } + if (database.owner.family_name) { + jsonLd.creator.familyName = database.owner.family_name + } + if (database.owner.attributes.orcid) { + jsonLd.creator.sameAs = database.owner.attributes.orcid + } + return jsonLd + } } export default new DatabaseMapper() diff --git a/dbrepo-ui/api/identifier.mapper.js b/dbrepo-ui/api/identifier.mapper.js index 34c8ca134c5560f4970f59363bcac2c2611443ff..868535f88d2b9ec96a3a797b1eba27ffe503d5f0 100644 --- a/dbrepo-ui/api/identifier.mapper.js +++ b/dbrepo-ui/api/identifier.mapper.js @@ -1,4 +1,5 @@ import store from '@/store' +const baseUrl = `${location.protocol}//${location.host}` class IdentifierMapper { identifierToCreators (identifier) { @@ -102,6 +103,13 @@ class IdentifierMapper { return null } + identifierToPreferFirstLicenseUri (identifier) { + if (!identifier || !identifier.licenses || identifier.licenses.length === 0) { + return null + } + return identifier.licenses[0].uri + } + identifierPreferEnglishDescription (identifier) { if (!identifier || !identifier.descriptions || identifier.descriptions.length === 0) { return null @@ -148,7 +156,7 @@ class IdentifierMapper { } return `${store().state.doiUrl}/${identifier.doi}` } - return `/pid/${identifier.id}` + return `${baseUrl}/pid/${identifier.id}` } identifierToDisplayName (identifier) { @@ -161,7 +169,7 @@ class IdentifierMapper { } return identifier.doi } - return `/pid/${identifier.id}` + return `${baseUrl}/pid/${identifier.id}` } identifierToDisplayAcronym (identifier) { @@ -170,6 +178,71 @@ class IdentifierMapper { } return identifier.doi !== null ? 'DOI' : 'URI' } + + creatorToCreatorJsonLd (creator) { + const jsonLd = { + name: creator.creator_name + } + if (creator.name_type === 'Personal') { + jsonLd['@type'] = 'Person' + if (creator.name_identifier) { + jsonLd.sameAs = creator.name_identifier + } + if (creator.firstname) { + jsonLd.givenName = creator.firstname + } + if (creator.lastname) { + jsonLd.familyName = creator.lastname + } + } else { + jsonLd['@type'] = 'Organization' + if (creator.affiliation_identifier) { + jsonLd.sameAs = creator.affiliation_identifier + } + } + return jsonLd + } + + identifierToHasPartJsonLd (identifier) { + return { + '@type': 'Dataset', + name: this.identifierPreferEnglishTitle(identifier), + description: this.identifierPreferEnglishDescription(identifier), + identifier: this.identifierToUrl(identifier), + citation: this.identifierToUrl(identifier), + temporalCoverage: identifier.publication_year, + version: identifier.created + } + } + + identifiersToJsonLd (database) { + const identifier = database.identifiers[0] + const partIdentifiers = [] + if (database.subsets.length > 0) { + database.subsets.forEach((s) => { if (s.identifiers.length > 0) { s.identifiers.forEach(i => partIdentifiers.push(i)) } }) + } + if (database.tables.length > 0) { + database.tables.forEach((t) => { if (t.identifiers.length > 0) { t.identifiers.forEach(i => partIdentifiers.push(i)) } }) + } + if (database.views.length > 0) { + database.views.forEach((v) => { if (v.identifiers.length > 0) { v.identifiers.forEach(i => partIdentifiers.push(i)) } }) + } + return { + '@context': 'https://schema.org/', + '@type': 'Dataset', + name: this.identifierPreferEnglishTitle(identifier), + description: this.identifierPreferEnglishDescription(identifier), + url: `${baseUrl}/database/${identifier.database_id}/info`, + identifier: database.identifiers.map(i => this.identifierToUrl(i)), + license: this.identifierToPreferFirstLicenseUri(identifier), + isAccessibleForFree: database.is_public, + creator: identifier.creators.map(c => this.creatorToCreatorJsonLd(c)), + citation: this.identifierToUrl(identifier), + hasPart: partIdentifiers.map(i => this.identifierToHasPartJsonLd(i)), + temporalCoverage: identifier.publication_year, + version: identifier.created + } + } } export default new IdentifierMapper() diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue index cfeece7cbc6ac33394e606378a11e474b412f616..d52ff87dd60acced367f8749b2c8c7be076979e0 100644 --- a/dbrepo-ui/layouts/default.vue +++ b/dbrepo-ui/layouts/default.vue @@ -125,6 +125,7 @@ <nuxt /> </v-container> </v-main> + <script v-if="hasDataset" type="application/ld+json" v-text="datasetJsonLd" /> </v-app> </template> @@ -133,6 +134,8 @@ import DatabaseService from '@/api/database.service' import TableService from '@/api/table.service' import AuthenticationService from '@/api/authentication.service' import AuthenticationMapper from '@/api/authentication.mapper' +import DatabaseMapper from '@/api/database.mapper' +import IdentifierMapper from '@/api/identifier.mapper' export default { data () { @@ -182,6 +185,18 @@ export default { }, logo () { return this.$config.logo + }, + hasDataset () { + return this.$route.path.startsWith('/database') + }, + datasetJsonLd () { + if (!this.hasDataset || !this.database) { + return {} + } + if (!('identifiers' in this.database) || this.database.identifiers.length === 0) { + return DatabaseMapper.databaseToJsonLd(this.database) + } + return IdentifierMapper.identifiersToJsonLd(this.database) } }, watch: { diff --git a/dbrepo-ui/pages/database/_database_id/info.vue b/dbrepo-ui/pages/database/_database_id/info.vue index c7ca194eb70876178263b2e35a61ef0fcf1fd590..299c55470ee8a6918e3a68a3b9559ec656d64ec4 100644 --- a/dbrepo-ui/pages/database/_database_id/info.vue +++ b/dbrepo-ui/pages/database/_database_id/info.vue @@ -25,9 +25,14 @@ </v-list-item-title> <v-list-item-content v-if="!loading" v-text="internal_name" /> <v-list-item-title class="mt-2"> - Database Creator + Database Owner </v-list-item-title> - <v-list-item-content v-if="!loading" v-text="creator" /> + <v-list-item-content v-if="!loading"> + <p class="mb-0"> + <OrcidIcon v-if="database.owner.attributes.orcid" :orcid="database.owner.attributes.orcid" /> + <span v-text="owner" /> + </p> + </v-list-item-content> <v-list-item-title class="mt-2"> Database Creation </v-list-item-title> @@ -53,7 +58,10 @@ Database Contact </v-list-item-title> <v-list-item-content v-if="contact"> - <span v-if="!loading" v-text="contact" /> + <p class="mb-0"> + <OrcidIcon v-if="database.contact.attributes.orcid" :orcid="database.contact.attributes.orcid" /> + <span v-text="contact" /> + </p> </v-list-item-content> </v-list-item-content> </v-list-item> @@ -100,9 +108,11 @@ import { formatTimestampUTCLabel } from '@/utils' import DatabaseMapper from '@/api/database.mapper' import Summary from '@/components/identifier/Summary' import Select from '@/components/identifier/Select' +import OrcidIcon from '@/components/icons/OrcidIcon.vue' export default { components: { + OrcidIcon, DatabaseToolbar, Summary, Select @@ -190,12 +200,9 @@ export default { contact () { return DatabaseMapper.databaseToContact(this.database) }, - creator () { + owner () { return DatabaseMapper.databaseToOwner(this.database) }, - creatorVerified () { - return this.database.creator.email_verified - }, hasIdentifier () { return this.identifiers.length > 0 },