diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..67cb59d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,22 @@
+FROM eclipse-temurin:17-jre
+
+ENV VOCABULARY_DB_SERVER vocabulary-db
+ENV VOCABULARY_DB_USER vocabulary
+ENV VOCABULARY_DB_PASSWORD vocabulary
+ENV VOCABULARY_DB_DATABASE vocabulary
+ENV VOCABULARY_SERVER_TOKEN secret
+ENV VOCABULARY_SERVER_PORT 8081
+
+RUN mkdir -p /opt/digiverso/vocabulary
+COPY module-core/target/vocabulary-server-core.jar /opt/digiverso/vocabulary/
+COPY module-core/src/main/resources/application.properties /opt/digiverso/vocabulary/
+RUN sed -re "s|^(server.port=).*|\1${VOCABULARY_SERVER_PORT}|" \
+ -e "s|^#?(security.token=).*|\1${VOCABULARY_SERVER_TOKEN}|" \
+ -e "s|^(spring.datasource.username=).*|\1${VOCABULARY_DB_USER}|" \
+ -e "s|^(spring.datasource.password=).*|\1${VOCABULARY_DB_PASSWORD}|" \
+ -e "s|^(spring.datasource.url=).*|\1jdbc:mariadb://$VOCABULARY_DB_SERVER:3306/${VOCABULARY_DB_DATABASE}|" \
+ -i /opt/digiverso/vocabulary/application.properties
+
+EXPOSE $VOCABULARY_SERVER_PORT
+WORKDIR /opt/digiverso/vocabulary
+CMD [ "java", "-jar", "vocabulary-server-core.jar"]
diff --git a/Jenkinsfile b/Jenkinsfile
index f11011e..6424f5b 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,14 +1,6 @@
+def latestTag = ''
pipeline {
-
- agent {
- docker {
- /* using a custom build image with a defined home directory for UID 1000 among other things */
- image 'nexus.intranda.com:4443/maven:3.9.3-eclipse-temurin-17'
- registryUrl 'https://nexus.intranda.com:4443'
- registryCredentialsId 'jenkins-docker'
- args '-v $HOME/.m2:/var/maven/.m2:z -v $HOME/.config:/var/maven/.config -v $HOME/.sonar:/var/maven/.sonar -u 1000 -ti -e _JAVA_OPTIONS=-Duser.home=/var/maven -e MAVEN_CONFIG=/var/maven/.m2'
- }
- }
+ agent none
options {
buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '15', daysToKeepStr: '90', numToKeepStr: '')
@@ -16,12 +8,16 @@ pipeline {
}
stages {
- stage('prepare') {
- steps {
- sh 'git reset --hard HEAD && git clean -fdx'
- }
- }
stage('build-snapshot') {
+ agent {
+ docker {
+ /* using a custom build image with a defined home directory for UID 1000 among other things */
+ image 'nexus.intranda.com:4443/maven:3.9.3-eclipse-temurin-17'
+ registryUrl 'https://nexus.intranda.com:4443'
+ registryCredentialsId 'jenkins-docker'
+ args '-v $HOME/.m2:/var/maven/.m2:z -v $HOME/.config:/var/maven/.config -v $HOME/.sonar:/var/maven/.sonar -u 1000 -ti -e _JAVA_OPTIONS=-Duser.home=/var/maven -e MAVEN_CONFIG=/var/maven/.m2'
+ }
+ }
when {
not {
anyOf {
@@ -36,10 +32,34 @@ pipeline {
}
}
steps {
+ sh 'git reset --hard HEAD && git clean -fdx'
sh 'mvn clean verify -U -P snapshot-build'
+ junit "**/target/surefire-reports/*.xml"
+ step([
+ $class : 'JacocoPublisher',
+ execPattern : '**/target/jacoco.exec',
+ classPattern : '**/target/classes/',
+ sourcePattern : 'src/main/java',
+ exclusionPattern : '**/*Test.class'
+ ])
+ recordIssues (
+ enabledForFailure: true, aggregatingResults: false,
+ tools: [checkStyle(pattern: '**/target/checkstyle-result.xml', reportEncoding: 'UTF-8')]
+ )
+ archiveArtifacts artifacts: 'module-*/target/*.jar, install/*, module-core/src/main/resources/application.properties, migration/**', fingerprint: true
+ stash includes: '**/target/*', name: 'target'
}
}
stage('build-release') {
+ agent {
+ docker {
+ /* using a custom build image with a defined home directory for UID 1000 among other things */
+ image 'nexus.intranda.com:4443/maven:3.9.3-eclipse-temurin-17'
+ registryUrl 'https://nexus.intranda.com:4443'
+ registryCredentialsId 'jenkins-docker'
+ args '-v $HOME/.m2:/var/maven/.m2:z -v $HOME/.config:/var/maven/.config -v $HOME/.sonar:/var/maven/.sonar -u 1000 -ti -e _JAVA_OPTIONS=-Duser.home=/var/maven -e MAVEN_CONFIG=/var/maven/.m2'
+ }
+ }
when {
anyOf {
branch 'master'
@@ -52,7 +72,22 @@ pipeline {
}
}
steps {
+ sh 'git reset --hard HEAD && git clean -fdx'
sh 'mvn clean verify -U -P release-build'
+ junit "**/target/surefire-reports/*.xml"
+ step([
+ $class : 'JacocoPublisher',
+ execPattern : '**/target/jacoco.exec',
+ classPattern : '**/target/classes/',
+ sourcePattern : 'src/main/java',
+ exclusionPattern : '**/*Test.class'
+ ])
+ recordIssues (
+ enabledForFailure: true, aggregatingResults: false,
+ tools: [checkStyle(pattern: '**/target/checkstyle-result.xml', reportEncoding: 'UTF-8')]
+ )
+ archiveArtifacts artifacts: 'module-*/target/*.jar, install/*, module-core/src/main/resources/application.properties, migration/**', fingerprint: true
+ stash includes: '**/target/*', name: 'target'
}
}
/*stage('sonarcloud') {
@@ -75,6 +110,15 @@ pipeline {
}
}*/
stage('deploy') {
+ agent {
+ docker {
+ /* using a custom build image with a defined home directory for UID 1000 among other things */
+ image 'nexus.intranda.com:4443/maven:3.9.3-eclipse-temurin-17'
+ registryUrl 'https://nexus.intranda.com:4443'
+ registryCredentialsId 'jenkins-docker'
+ args '-v $HOME/.m2:/var/maven/.m2:z -v $HOME/.config:/var/maven/.config -v $HOME/.sonar:/var/maven/.sonar -u 1000 -ti -e _JAVA_OPTIONS=-Duser.home=/var/maven -e MAVEN_CONFIG=/var/maven/.m2'
+ }
+ }
when {
anyOf {
branch 'master'
@@ -83,10 +127,20 @@ pipeline {
}
}
steps {
+ unstash 'target'
sh 'mvn -f module-exchange/pom.xml deploy -U'
}
}
stage('tag release') {
+ agent {
+ docker {
+ /* using a custom build image with a defined home directory for UID 1000 among other things */
+ image 'nexus.intranda.com:4443/maven:3.9.3-eclipse-temurin-17'
+ registryUrl 'https://nexus.intranda.com:4443'
+ registryCredentialsId 'jenkins-docker'
+ args '-v $HOME/.m2:/var/maven/.m2:z -v $HOME/.config:/var/maven/.config -v $HOME/.sonar:/var/maven/.sonar -u 1000 -ti -e _JAVA_OPTIONS=-Duser.home=/var/maven -e MAVEN_CONFIG=/var/maven/.m2'
+ }
+ }
when {
anyOf {
branch 'master'
@@ -94,6 +148,7 @@ pipeline {
}
}
steps {
+ unstash 'target'
withCredentials([gitUsernamePassword(credentialsId: '93f7e7d3-8f74-4744-a785-518fc4d55314',
gitToolName: 'git-tool')]) {
sh '''#!/bin/bash -xe
@@ -109,28 +164,31 @@ pipeline {
echo "${projectversion}"
git tag -a "v${projectversion}" -m "releasing v${projectversion}" && git push origin v"${projectversion}"
'''
+ script {
+ latestTag = sh(returnStdout: true, script:'git describe --tags --abbrev=0').trim()
+ }
+ }
+ }
+ }
+ stage('build and publish production image to GitHub container registry') {
+ agent any
+ steps {
+ unstash 'target'
+ script {
+ docker.withRegistry('https://ghcr.io','jenkins-github-container-registry') {
+ dockerimage_public = docker.build("intranda/goobi-vocabulary-server:${env.BUILD_ID}_${env.GIT_COMMIT}")
+ if (env.GIT_BRANCH == 'origin/develop' || env.GIT_BRANCH == 'develop') {
+ dockerimage_public.push("develop")
+ }
+ if (!latestTag == '' ) {
+ dockerimage_public.push(latestTag)
+ }
+ }
}
}
}
}
post {
- always {
- junit "**/target/surefire-reports/*.xml"
- step([
- $class : 'JacocoPublisher',
- execPattern : 'target/jacoco.exec',
- classPattern : 'target/classes/',
- sourcePattern : 'src/main/java',
- exclusionPattern : '**/*Test.class'
- ])
- recordIssues (
- enabledForFailure: true, aggregatingResults: false,
- tools: [checkStyle(pattern: 'target/checkstyle-result.xml', reportEncoding: 'UTF-8')]
- )
- }
- success {
- archiveArtifacts artifacts: 'module-*/target/*.jar, install/*, module-core/src/main/resources/application.properties, migration/**', fingerprint: true
- }
changed {
emailext(
subject: '${DEFAULT_SUBJECT}',
diff --git a/docs/de/README.md b/docs/de/README.md
index 750786c..cb47450 100644
--- a/docs/de/README.md
+++ b/docs/de/README.md
@@ -1,5 +1,5 @@
# Dokumentation
-Dieses Dokument beschreibt den neuen Vokabularserver. Bis zur Version 24.06 waren Vokabulare Teil von Goobi Workflow und wurden in der Goobi-Datenbank gespeichert. Ab Version 24.07 ist alles, was mit Vokabularen zu tun hat, in eine eigenständige Anwendung, den Vokabularserver, umgezogen. Der Vokabularserver benötigt eine eigene Datenbank, um alle Daten zu speichern, und ermöglicht den Zugriff auf die Vokabulare und Datensätze über eine REST-API. Goobi Workflow wurde aktualisiert, um den neuen Vokabularserver anstelle seiner eigenen, eingebetteten Vokabulare zu verwenden. Falls gewünscht, kann der Vokabularserver öffentlich zugänglich sein. Wenn Sie bereits vorher Vokabulare verwendet haben, lesen Sie bitte die Migrationsanleitung in dieser Dokumentation, um Ihre Daten auf den neuen Vokabularserver zu übertragen.
+Dieses Dokument beschreibt den Goobi Vokabularserver. Bis zur Version 24.06 waren Vokabulare Teil von Goobi Workflow und wurden in der Goobi-Datenbank gespeichert. Ab Version 24.07 ist alles, was mit Vokabularen zu tun hat, in eine eigenständige Anwendung, den Vokabularserver, umgezogen. Der Vokabularserver benötigt eine eigene Datenbank, um alle Daten zu speichern, und ermöglicht den Zugriff auf die Vokabulare und Datensätze über eine REST-API. Goobi Workflow wurde aktualisiert, um den neuen Vokabularserver anstelle seiner eigenen, eingebetteten Vokabulare zu verwenden. Falls gewünscht, kann der Vokabularserver öffentlich zugänglich sein. Wenn Sie bereits vorher Vokabulare verwendet haben, lesen Sie bitte die Migrationsanleitung in dieser Dokumentation, um Ihre Daten auf den neuen Vokabularserver zu übertragen.
## Installation
Bevor Sie den Vokabularserver nutzen können, folgen Sie den [Installations Anweisungen](setup.md).
diff --git a/docs/de/creation.md b/docs/de/creation.md
index 7ca6c1b..70863c1 100644
--- a/docs/de/creation.md
+++ b/docs/de/creation.md
@@ -11,7 +11,7 @@ Sie müssen den `BASE_PART` auf `localhost:8081/api/v1` setzen, den Hostnamen un
Ändern Sie nur die Teile `API_ENDPOINT` und `DATA`, abhängig von der Art der Abfrage, die Sie durchführen:
```bash
-curl -s --location "http://BASE_PART/API_ENDPOINT" --header 'Content-Type: application/json' --data "DATA"
+curl -s --location "http://BASE_PART/API_ENDPOINT" --header "Authorization: Bearer TOKEN" --header 'Content-Type: application/json' --data "DATA"
```
Wenn Sie Fehler erhalten, werden die Fehlerinformationen als komplexe JSON-Objekte zurückgegeben.
@@ -89,7 +89,7 @@ Sie können genau den gleichen Feldtypen auch erreichen, indem Sie dies durch ei
Wenn Sie es versäumt haben, die IDs zu speichern, können Sie den folgenden Befehl aufrufen, um alle vorhandenen Feldtypen mit ihren IDs abzurufen:
```bash
-curl -s --location "http://BASE_PART/types" --header 'Content-Type: application/json' | jq '._embedded .fieldTypeList .[] | "\(.id) \(.name)"'
+curl -s --location "http://BASE_PART/types" --header "Authorization: Bearer TOKEN" --header 'Content-Type: application/json' | jq '._embedded .fieldTypeList .[] | "\(.id) \(.name)"'
```
*Bitte beachten Sie den fehlenden `--data` Parameter in diesem Aufruf.*
diff --git a/docs/de/migration.md b/docs/de/migration.md
index cedb11e..4f1cf0e 100644
--- a/docs/de/migration.md
+++ b/docs/de/migration.md
@@ -29,19 +29,23 @@ Detaillierte Anweisungen hierzu werden später gegeben.
Wenn Sie keine Feldtypen erstellen wollen, können Sie die Datenmigration mit dem folgenden Befehl starten:
```bash
-python vocabulary-migrator.py --vocabulary-server-host localhost --vocabulary-server-port 8081 --goobi-database-host localhost --goobi-database-port 3306 --goobi-database-name goobi --goobi-database-user goobi --goobi-database-password goobi --continue-on-error --fallback-language eng
+python vocabulary-migrator.py --vocabulary-server-host localhost --vocabulary-server-port 8081 --vocabulary-server-token TOKEN --goobi-database-host localhost --goobi-database-port 3306 --goobi-database-name goobi --goobi-database-user goobi --goobi-database-password goobi --continue-on-error --fallback-language eng
```
### Skript
-Die obigen beiden Puntke, die virtuelle Python-Umgebung und die Migration der Vokabulardaten in einer typischen Installation:
+Die obigen beiden Puntke, die virtuelle Python-Umgebung und die Migration der Vokabulardaten in einer typischen Installation, als root:
```bash
cd /opt/digiverso/vocabulary/migration
python3 -m venv vmenv
. vmenv/bin/activate
pip install requests mysql-connector-python==8.4.0 alive_progress lxml
VOC_PORT=$(sudo grep -oP '^server.port=\K.*' /opt/digiverso/vocabulary/application.properties)
+VOC_TOKEN=$(sudo grep -oP '^security.token=\K.*' /opt/digiverso/vocabulary/application.properties)
DB_GOOBI_PW=$(sudo xmlstarlet sel -t -v '//Resource/@password' -n /etc/tomcat9/Catalina/localhost/goobi.xml)
-python vocabulary-migrator.py --vocabulary-server-host localhost --vocabulary-server-port "${VOC_PORT}" --goobi-database-host localhost --goobi-database-port 3306 --goobi-database-name goobi --goobi-database-user goobi --goobi-database-password "${DB_GOOBI_PW}" --continue-on-error --fallback-language ger
+python vocabulary-migrator.py --vocabulary-server-host localhost --vocabulary-server-port "${VOC_PORT}" --vocabulary-server-token "${VOC_TOKEN}" --goobi-database-host localhost --goobi-database-port 3306 --goobi-database-name goobi --goobi-database-user goobi --goobi-database-password "${DB_GOOBI_PW}" --continue-on-error --fallback-language ger
+
+# Test
+curl -s http://localhost:8081/api/v1/vocabularies --header "Authorization: Bearer $VOC_TOKEN" | jq -r '._embedded.vocabularyList[] .name'
```
**Hinweis** Ändern Sie die Parameter entsprechend Ihrer Konfiguration. Der Parameter `fallback-language` definiert die Standardsprache, die für ein mehrsprachiges Vokabularfeld verwendet wird, für das keine Standardsprache abgeleitet werden konnte. Die Option `continue-on-error` verhindert, dass das Migrationstool bei Fehlern bei der Datenmigration anhält. Diese Fehler können auftreten, wenn die Daten nicht in den neuen Vokabularserver eingefügt werden konnten. Mögliche Gründe dafür könnten sein:
@@ -140,11 +144,11 @@ Diese Datei ordnet allen Datensatzwerten die entsprechende Datensatz-IDs im Refe
### Test der Vokabulardaten-Migration
- Wenn eine Datenmigration stattgefunden hat, prüfen Sie, ob alle Vokabulare migriert wurden:
```bash
-curl -s http://localhost:8081/api/v1/vocabularies | jq -r '._embedded.vocabularyList[] .name'
+curl -s http://localhost:8081/api/v1/vocabularies --header "Authorization: Bearer $VOC_TOKEN" | jq -r '._embedded.vocabularyList[] .name'
```
- Prüfen Sie, ob die Links korrekt aufgelöst werden (siehe Konfiguration):
```bash
-curl http://localhost:8081/api/v1/records/1 | jq
+curl http://localhost:8081/api/v1/records/1 --header "Authorization: Bearer $VOC_TOKEN" | jq
```
Das JSON-Element `_links` sollte Verweise auf andere Ressourcen enthalten.
Diese URLs sollten gültig und auflösbar sein.
@@ -159,9 +163,9 @@ cd /opt/digiverso/vocabulary/migration
sudo -s
. vmenv/bin/activate
# dry-run:
-python metadata-migrator.py --verbose --log INFO -m migration.csv -d /opt/digiverso/goobi/metadata --dry
+python metadata-migrator.py --vocabulary-server-token "${VOC_TOKEN}" --verbose --log INFO -m migration.csv -d /opt/digiverso/goobi/metadata --dry
# metadata migration
-python metadata-migrator.py -m migration.csv -d /opt/digiverso/goobi/metadata
+python metadata-migrator.py --vocabulary-server-token "${VOC_TOKEN}" -m migration.csv -d /opt/digiverso/goobi/metadata
```
Dadurch werden alle mets-Dateien in allen Prozessverzeichnissen rekursiv verarbeitet.
diff --git a/docs/de/setup.md b/docs/de/setup.md
index bc6f0b5..b9bff1d 100644
--- a/docs/de/setup.md
+++ b/docs/de/setup.md
@@ -4,7 +4,7 @@ Diese Dokumentation beschreibt den Prozess der Installation und Ersteinrichtung
## Download und Installation
- Laden Sie die [Neuste Version](https://github.com/intranda/goobi-vocabulary-server/releases/latest) des Vokabularservers herunter.
- Laden Sie die [Konfigurationsdatei](https://github.com/intranda/goobi-vocabulary-server/releases/latest/download/application.properties) des Vokabularservers herunter.
-- Passen Sie die Konfigurationsdatei entsprechend Ihrer Konfiguration an und entfernen Sie nicht geänderte Zeilen.
+- Passen Sie die Konfigurationsdatei entsprechend Ihrer Konfiguration an:
- Datenbankanmeldeinformationen und Datenbankname.
- Basis-URL und Port.
- Sicherheitstoken (dieses muss identisch auch in Goobi konfiguriert werden).
@@ -12,7 +12,7 @@ Diese Dokumentation beschreibt den Prozess der Installation und Ersteinrichtung
## Einrichtung von Goobi Workflow zur Kommunikation mit dem Vokabularserver
- Goobi Workflow verwendet seit Version `24.07` den neuen Vokabularserver.
-- Konfigurieren Sie die Variablen `vocabularyServerHost` und `vocabularyServerPort` in der Datei `goobi_config.properties` entsprechend der Konfiguration Ihres Vokabularservers.
+- Konfigurieren Sie die Variablen `vocabularyServerHost`, `vocabularyServerPort` und `vocabularyServerToken` in der Datei `goobi_config.properties` entsprechend der Konfiguration Ihres Vokabularservers.
- Starten Sie Goobi Workflow neu, damit die Änderungen wirksam werden.
- Navigieren Sie zu `Administration` > `Vocabulare`, um zu überprüfen, ob alles funktioniert. Sie sollten eine Liste von Vokabularen sehen, wenn alles in Ordnung ist (nicht jetzt, sondern nachdem Sie einige Vokabulare erstellt oder die bestehenden migriert haben). Wenn etwas nicht funktioniert, wird eine rote Fehlermeldung angezeigt.
@@ -20,12 +20,14 @@ Diese Dokumentation beschreibt den Prozess der Installation und Ersteinrichtung
- Für den ordnungsgemäßen Betrieb benötigt der Vokabularserver einige Ausgangsdaten.
- Diese Daten enthalten Sprachangaben (wenn mehrsprachige Vokabulare verwendet werden) und Feldtypdefinitionen.
- Sie können das folgende Skript verwenden, welches einige Beispielsprachen und Feldtypen installiert.
-- Laden Sie das [Initial Data Script](https://jenkins.intranda.com/job/intranda/job/vocabulary-server/job/develop/lastSuccessfulBuild/artifact/install/default_setup.sh) herunter.
-- Ändern Sie die Variable `HOST` am Anfang entsprechend der Konfiguration des Vokabularservers, lassen Sie das Suffix `/api/v1` unverändert.
+- Laden Sie das [Initial Data Script](https://github.com/intranda/goobi-vocabulary-server/raw/develop/install/default_setup.sh) herunter.
+- Ändern Sie die Variablen `HOST` und `TOKEN` am Anfang entsprechend der Konfiguration des Vokabularservers, lassen Sie das Suffix `/api/v1` unverändert.
- Führen Sie das Skript aus.
## Installationsskript
-Für die obigen drei Punkte unter Ubuntu:
+Der Vokabularserver benötigt Java 17, der Systemd-Service geht davon aus, dass Java 17 der System-Default ist.
+
+Für die obigen drei Punkte, unter Ubuntu:
```bash
export VOC_PORT=8081
export VOC_TOKEN=$(/dev/null
sudo sed -re "s|^(server.port=).*|\1${VOC_PORT}|" \
- -e "s|^(security.token=).*|\1${VOC_TOKEN}|" \
+ -e "s|^#?(security.token=).*|\1${VOC_TOKEN}|" \
-e "s|^(spring.datasource.username=).*|\1${VOC_SQL_USER}|" \
-e "s|^(spring.datasource.password=).*|\1${PW_SQL_VOC}|" \
-e "s|^(spring.datasource.url=).*|\1jdbc:mariadb://localhost:3306/${VOC_SQL_DB}|" \
@@ -94,18 +96,16 @@ grep ^vocabularyServerHost= /opt/digiverso/goobi/config/goobi_config.properties
grep ^vocabularyServerPort= /opt/digiverso/goobi/config/goobi_config.properties || echo "vocabularyServerPort=${VOC_PORT}" | sudo tee -a /opt/digiverso/goobi/config/goobi_config.properties
grep ^vocabularyServerToken= /opt/digiverso/goobi/config/goobi_config.properties || echo "vocabularyServerToken=${VOC_TOKEN}" | sudo tee -a /opt/digiverso/goobi/config/goobi_config.properties
-# start the vocabulary server
-sudo systemctl start vocabulary.service
-## check startup
-journalctl -u vocabulary.service -f
+# start the vocabulary server and wait for startup
+sudo systemctl restart vocabulary.service & sudo journalctl -u vocabulary.service -f -n 0 | grep -q "Started VocabularyServerApplication in"
# initial set up
-wget https://github.com/intranda/goobi-vocabulary-server/releases/latest/download/default_setup.sh -O - | sudo tee ${VOC_PATH}/default_setup.sh >/dev/null
-bash ${VOC_PATH}/default_setup.sh
+wget https://github.com/intranda/goobi-vocabulary-server/raw/develop/install/default_setup.sh -O /tmp/default_setup.sh
+bash /tmp/default_setup.sh
+
## test
-curl -s http://localhost:${VOC_PORT}/api/v1/types | jq -r '._embedded.fieldTypeList[] .name'
+curl -s http://localhost:${VOC_PORT}/api/v1/types --header "Authorization: Bearer $VOC_TOKEN" | jq -r '._embedded.fieldTypeList[] .name'
```
-Der Vokabularserver benötigt Java 17, der Systemd-Service geht davon aus, dass Java 17 der System-Default ist.
## Erreichbarkeit
- Sie können den Vokabularserver von außen erreichbar machen, indem Sie einen Proxy samt Zugriffskontrolle davorschalten.
@@ -114,7 +114,7 @@ Der Vokabularserver benötigt Java 17, der Systemd-Service geht davon aus, dass
- Ändern Sie für alle Befehle Host und Port entsprechend.
- Prüfen Sie nach der Ersteinrichtung, ob die Feldtypen erfolgreich erstellt wurden:
```bash
-curl http://localhost:8081/api/v1/types | jq -r '._embedded.fieldTypeList[] .name'
+curl "http://localhost:${VOC_PORT:-8081}/api/v1/types" --header "Authorization: Bearer $VOC_TOKEN" | jq -r '._embedded.fieldTypeList[] .name'
```
- Das Ergebnis sollte wie folgt aussehen:
```bash
diff --git a/install/.gitignore b/install/.gitignore
new file mode 100644
index 0000000..3415572
--- /dev/null
+++ b/install/.gitignore
@@ -0,0 +1 @@
+/cache.txt
\ No newline at end of file
diff --git a/install/default_setup.sh b/install/default_setup.sh
index 93d8967..2b2b056 100755
--- a/install/default_setup.sh
+++ b/install/default_setup.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-HOST='localhost:8081/api/v1'
-TOKEN='secret'
+HOST="localhost:${VOC_PORT:-8081}/api/v1"
+TOKEN="${VOC_TOKEN:-CHANGEME}"
curl_call() {
curl --location "$HOST/$1" --header 'Content-Type: application/json' --header "Authorization: Bearer $TOKEN" --data "$2"
@@ -49,3 +49,6 @@ create_type "dct:title"
create_type "dct:creator"
create_type "dct:created" "\\\\d{4}\\\\-\\\\d{2}\\\\-\\\\d{2}"
create_type "dct:license" "https?.*"
+echo
+
+curl -s "${HOST}"/types --header "Authorization: Bearer $TOKEN" | jq -r '._embedded.fieldTypeList[] .name' | grep Anything -q || { echo "ERROR while executing $0"; exit 1; }
diff --git a/install/demo.sh b/install/demo.sh
deleted file mode 100755
index b73b309..0000000
--- a/install/demo.sh
+++ /dev/null
@@ -1,353 +0,0 @@
-#!/usr/bin/env bash
-METADATA_ID=$(curl --location 'localhost:8081/api/v1/schemas' \
---header 'Content-Type: application/json' \
---data '{
- "definitions": [
- {
- "name": "Title",
- "typeId": 12,
- "required": true,
- "unique": false,
- "mainEntry": true,
- "titleField": true,
- "translationDefinitions": [
- {
- "language": "eng",
- "fallback": true,
- "required": true
- },
- {
- "language": "ger",
- "fallback": false,
- "required": false
- },
- {
- "language": "fre",
- "fallback": false,
- "required": false
- }
- ]
- },
- {
- "name": "Author",
- "typeId": 13,
- "required": false,
- "unique": false,
- "mainEntry": false,
- "titleField": false,
- "multiValued": true,
- "translationDefinitions": [
- {
- "language": "eng",
- "fallback": true,
- "required": true
- },
- {
- "language": "ger",
- "fallback": false,
- "required": false
- },
- {
- "language": "fre",
- "fallback": false,
- "required": false
- }
- ]
- },
- {
- "name": "Creation Date",
- "typeId": 14,
- "required": true,
- "unique": false,
- "mainEntry": false,
- "titleField": false
- },
- {
- "name": "License",
- "typeId": 15,
- "required": false,
- "unique": false,
- "mainEntry": false,
- "titleField": false,
- "multiValued": true
- }
- ],
- "hierarchicalRecords": false,
- "singleRootElement": true
-}' | jq ".id")
-SKOS_ID=$(curl --location 'localhost:8081/api/v1/schemas' \
---header 'Content-Type: application/json' \
---data '{
- "definitions": [
- {
- "name": "Label",
- "typeId": 6,
- "required": true,
- "unique": false,
- "mainEntry": true,
- "titleField": true,
- "translationDefinitions": [
- {
- "language": "eng",
- "fallback": true,
- "required": true
- },
- {
- "language": "ger",
- "fallback": false,
- "required": false
- },
- {
- "language": "fre",
- "fallback": false,
- "required": false
- }
- ]
- },
- {
- "name": "Alternative Label",
- "typeId": 7,
- "required": false,
- "unique": false,
- "mainEntry": false,
- "titleField": false,
- "multiValued": true,
- "translationDefinitions": [
- {
- "language": "eng",
- "fallback": true,
- "required": true
- },
- {
- "language": "ger",
- "fallback": false,
- "required": false
- },
- {
- "language": "fre",
- "fallback": false,
- "required": false
- }
- ]
- },
- {
- "name": "Definition",
- "typeId": 8,
- "required": false,
- "unique": false,
- "mainEntry": false,
- "titleField": false,
- "multiValued": true,
- "translationDefinitions": [
- {
- "language": "eng",
- "fallback": true,
- "required": true
- },
- {
- "language": "ger",
- "fallback": false,
- "required": false
- },
- {
- "language": "fre",
- "fallback": false,
- "required": false
- }
- ]
- },
- {
- "name": "Editorial Note",
- "typeId": 9,
- "required": false,
- "unique": false,
- "mainEntry": false,
- "titleField": false,
- "multiValued": true,
- "translationDefinitions": [
- {
- "language": "eng",
- "fallback": true,
- "required": true
- },
- {
- "language": "ger",
- "fallback": false,
- "required": false
- },
- {
- "language": "fre",
- "fallback": false,
- "required": false
- }
- ]
- },
- {
- "name": "Related",
- "typeId": 10,
- "required": false,
- "unique": false,
- "mainEntry": false,
- "titleField": false,
- "multiValued": true
- },
- {
- "name": "Close Match",
- "typeId": 11,
- "required": false,
- "unique": false,
- "mainEntry": false,
- "titleField": false,
- "multiValued": true
- },
- {
- "name": "Exact Match",
- "typeId": 12,
- "required": false,
- "unique": false,
- "mainEntry": false,
- "titleField": false,
- "multiValued": true
- }
- ],
- "hierarchicalRecords": true
-}' | jq ".id")
-curl --location 'localhost:8081/api/v1/vocabularies' \
---header 'Content-Type: application/json' \
---data "{
- \"schemaId\": $SKOS_ID,
- \"metadataSchemaId\": $METADATA_ID,
- \"name\": \"SKOS\",
- \"description\": \"SKOS example vocabulary.\"
-}"
-RATING_ID=$(curl --location 'localhost:8081/api/v1/types' \
---header 'Content-Type: application/json' \
---data '{
- "name": "Rating",
- "validation": "\\d+",
- "selectableValues": [
- "1", "2", "3", "4", "5"
- ]
-}' | jq ".id")
-MOVIE_SCHEMA_ID=$(curl --location 'localhost:8081/api/v1/schemas' \
---header 'Content-Type: application/json' \
---data "{
- \"definitions\": [
- {
- \"name\": \"Name\",
- \"typeId\": 5,
- \"required\": true,
- \"unique\": true,
- \"mainEntry\": true,
- \"titleField\": true
- },
- {
- \"name\": \"Description\",
- \"typeId\": 1,
- \"required\": false,
- \"unique\": false,
- \"mainEntry\": false,
- \"titleField\": false,
- \"translationDefinitions\": [
- {
- \"language\": \"eng\",
- \"fallback\": true,
- \"required\": true
- },
- {
- \"language\": \"ger\",
- \"fallback\": false,
- \"required\": true
- }
- ]
- },
- {
- \"name\": \"Rating\",
- \"typeId\": $RATING_ID,
- \"required\": false,
- \"unique\": false,
- \"mainEntry\": false,
- \"titleField\": false
- }
- ],
- \"hierarchicalRecords\": true
-}" | jq ".id")
-MOVIE_VOCAB_ID=$(curl --location 'localhost:8081/api/v1/vocabularies' \
---header 'Content-Type: application/json' \
---data "{
- \"schemaId\": $MOVIE_SCHEMA_ID,
- \"name\": \"MovieDB\",
- \"description\": \"Personal movie database.\"
-}" | jq ".id")
-HOBBY_SCHEMA_ID=$(curl --location 'localhost:8081/api/v1/schemas' \
---header 'Content-Type: application/json' \
---data '{
- "definitions": [
- {
- "name": "Description",
- "typeId": 1,
- "required": true,
- "unique": true,
- "mainEntry": true,
- "titleField": true,
- "translationDefinitions": [
- {
- "language": "eng",
- "fallback": true,
- "required": true
- },
- {
- "language": "ger",
- "fallback": false,
- "required": false
- }
- ]
- }
- ],
- "hierarchicalRecords": false
-}' | jq ".id")
-HOBBY_VOCAB_ID=$(curl --location 'localhost:8081/api/v1/vocabularies' \
---header 'Content-Type: application/json' \
---data "{
- \"schemaId\": $HOBBY_SCHEMA_ID,
- \"name\": \"Hobbies\",
- \"description\": \"Collection of typical hobbies.\"
-}" | jq ".id")
-FACEBOOK_ID=$(curl --location 'localhost:8081/api/v1/schemas' \
---header 'Content-Type: application/json' \
---data "{
- \"definitions\": [
- {
- \"name\": \"Full Name\",
- \"typeId\": 1,
- \"required\": true,
- \"unique\": true,
- \"mainEntry\": true,
- \"titleField\": true
- },
- {
- \"name\": \"Favorite Movie\",
- \"referenceVocabularyId\": $MOVIE_VOCAB_ID,
- \"required\": true,
- \"unique\": false,
- \"mainEntry\": false,
- \"titleField\": true
- },
- {
- \"name\": \"Hobbies\",
- \"referenceVocabularyId\": $HOBBY_VOCAB_ID,
- \"required\": false,
- \"unique\": false,
- \"mainEntry\": false,
- \"titleField\": false,
- \"multiValued\": true
- }
- ]
-}" | jq ".id")
-curl --location 'localhost:8081/api/v1/vocabularies' \
---header 'Content-Type: application/json' \
---data "{
- \"schemaId\": $FACEBOOK_ID,
- \"name\": \"Facebook\",
- \"description\": \"My best friends with their favorite movies.\"
-}"
diff --git a/install/install_samples.sh b/install/install_samples.sh
new file mode 100755
index 0000000..09a37fe
--- /dev/null
+++ b/install/install_samples.sh
@@ -0,0 +1,115 @@
+#!/usr/bin/env bash
+MY_PATH="$(dirname -- "${BASH_SOURCE[0]}")"
+SAMPLES_DIR=$MY_PATH/samples
+CACHE_FILE=$MY_PATH/cache.txt
+
+# Check for parameters
+FAIL=0
+if [ -z $HOST ]; then
+ echo "Missing \"HOST\" parameter!"
+ FAIL=1
+fi
+if [ -z $PORT ]; then
+ echo "Missing \"PORT\" parameter!"
+ FAIL=1
+fi
+if [ -z $TOKEN ]; then
+ echo "Missing \"TOKEN\" parameter!"
+ FAIL=1
+fi
+if [ $FAIL == "1" ]; then
+ echo "Please call this script like the following way (sample call):"
+ echo "$ HOST=localhost PORT=8081 TOKEN=yoursecrettoken $MY_PATH/install_samples.sh"
+ exit 1
+fi
+
+SAMPLE=$1
+if [ -z $SAMPLE ]; then
+ echo "Please chose a sample to install:"
+ ls $SAMPLES_DIR
+ read SAMPLE
+fi
+SAMPLE_PATH=$SAMPLES_DIR/$SAMPLE
+if [ ! -e $SAMPLE_PATH ]; then
+ echo "Sample \"$SAMPLE\" does not exist!"
+ exit 1
+fi
+
+curl_call() {
+ curl --location "$HOST:$PORT/api/v1/$1" \
+ --header 'Content-Type: application/json' \
+ --header "Authorization: Bearer $TOKEN" \
+ --fail \
+ --silent \
+ --data "$2"
+}
+
+curl_file_upload_call() {
+ curl --location "$HOST:$PORT/api/v1/$1" \
+ --header "Authorization: Bearer $TOKEN" \
+ --fail \
+ --silent \
+ --form "file=@\"$2\""
+}
+
+for INSTALL_DIR in $(ls $SAMPLE_PATH); do
+ ENDPOINT=$(echo $INSTALL_DIR | cut -d'_' -f2)
+ echo "Installing $ENDPOINT"
+ for ITEM in $(ls $SAMPLE_PATH/$INSTALL_DIR | grep ".json"); do
+ ITEM_NAME=$(echo "$ITEM" | cut -d'.' -f1)
+ ITEM_IDENTIFIER=${ENDPOINT}_"${ITEM_NAME}"
+
+ ID=$(cat $CACHE_FILE | grep "$ITEM_IDENTIFIER;" | cut -d';' -f2)
+ if [ -z "$ID" ]; then
+ JSON=$(cat $SAMPLE_PATH/$INSTALL_DIR/$ITEM)
+
+ # Replace ID placeholders
+ for CACHE_LINE in $(cat $CACHE_FILE); do
+ TEMPLATE_PLACEHOLDER="{{$(echo $CACHE_LINE | cut -d';' -f1)}}"
+ CACHE_ID=$(echo $CACHE_LINE | cut -d';' -f2)
+ JSON=$(echo $JSON | sed "s/$TEMPLATE_PLACEHOLDER/$CACHE_ID/g")
+ done
+
+ RESULT=$(curl_call $ENDPOINT "$JSON")
+
+ if [ -z "$RESULT" ]; then
+ echo "Error during creation, exiting!"
+ echo $JSON
+ exit 2
+ fi
+ ID=$(echo $RESULT | jq ".id")
+ echo "$ITEM_IDENTIFIER;$ID" >> $CACHE_FILE
+ echo -e "\tInstalled $ITEM_NAME with ID $ID"
+
+ if [ $ENDPOINT = "schemas" ]; then
+ echo $RESULT | jq -r ".definitions[] | \"${ITEM_IDENTIFIER}_definitions_\(.name);\(.id)\"" >> $CACHE_FILE
+ fi
+ else
+ echo -e "\tSkipping $ITEM_NAME, already present with ID $ID"
+ fi
+ done
+ for ITEM in $(ls $SAMPLE_PATH/$INSTALL_DIR | grep ".csv"); do
+ VOCABULARY_NAME=$(echo "$ITEM" | cut -d'.' -f1)
+ VOCABULARY_IDENTIFIER=vocabularies_${VOCABULARY_NAME}
+ VOCABULARY_ID=$(cat $CACHE_FILE | grep $VOCABULARY_IDENTIFIER | cut -d';' -f2)
+
+ if [ ! -z "$VOCABULARY_ID" ]; then
+ curl_file_upload_call "vocabularies/$VOCABULARY_ID/import/csv" "$SAMPLE_PATH/$INSTALL_DIR/$ITEM"
+ echo -e "\tImported \"$VOCABULARY_NAME\" vocabulary records"
+ else
+ echo -e "\tSkipping record imports into \"$VOCABULARY_NAME\" vocabulary, vocabulary not created beforehand!"
+ fi
+ done
+ for ITEM in $(ls $SAMPLE_PATH/$INSTALL_DIR | grep ".xlsx"); do
+ VOCABULARY_NAME=$(echo "$ITEM" | cut -d'.' -f1)
+ VOCABULARY_IDENTIFIER=vocabularies_${VOCABULARY_NAME}
+ VOCABULARY_ID=$(cat $CACHE_FILE | grep $VOCABULARY_IDENTIFIER | cut -d';' -f2)
+
+ if [ ! -z "$VOCABULARY_ID" ]; then
+ curl_file_upload_call "vocabularies/$VOCABULARY_ID/import/excel" "$SAMPLE_PATH/$INSTALL_DIR/$ITEM"
+ echo -e "\tImported \"$VOCABULARY_NAME\" vocabulary records"
+ else
+ echo -e "\tSkipping record imports into \"$VOCABULARY_NAME\" vocabulary, vocabulary not created beforehand!"
+ fi
+ done
+done
diff --git a/install/samples/books/1_languages/Deutsch.json b/install/samples/books/1_languages/Deutsch.json
new file mode 100644
index 0000000..5a2cdbb
--- /dev/null
+++ b/install/samples/books/1_languages/Deutsch.json
@@ -0,0 +1,4 @@
+{
+ "abbreviation": "ger",
+ "name": "Deutsch"
+}
\ No newline at end of file
diff --git a/install/samples/books/1_languages/English.json b/install/samples/books/1_languages/English.json
new file mode 100644
index 0000000..34fc8a6
--- /dev/null
+++ b/install/samples/books/1_languages/English.json
@@ -0,0 +1,4 @@
+{
+ "abbreviation": "eng",
+ "name": "English"
+}
\ No newline at end of file
diff --git "a/install/samples/books/1_languages/Fran\303\247ais.json" "b/install/samples/books/1_languages/Fran\303\247ais.json"
new file mode 100644
index 0000000..e796791
--- /dev/null
+++ "b/install/samples/books/1_languages/Fran\303\247ais.json"
@@ -0,0 +1,4 @@
+{
+ "abbreviation": "fre",
+ "name": "Français"
+}
\ No newline at end of file
diff --git a/install/samples/books/2_types/Anything.json b/install/samples/books/2_types/Anything.json
new file mode 100644
index 0000000..ea7aa0f
--- /dev/null
+++ b/install/samples/books/2_types/Anything.json
@@ -0,0 +1,3 @@
+{
+ "name": "Anything"
+}
\ No newline at end of file
diff --git a/install/samples/books/2_types/Date.json b/install/samples/books/2_types/Date.json
new file mode 100644
index 0000000..1543f26
--- /dev/null
+++ b/install/samples/books/2_types/Date.json
@@ -0,0 +1,4 @@
+{
+ "name": "Datum",
+ "validation": "\\d{2}\\.\\d{2}\\.\\d{4}"
+}
\ No newline at end of file
diff --git a/install/samples/books/2_types/Hex_RGB.json b/install/samples/books/2_types/Hex_RGB.json
new file mode 100644
index 0000000..6fc9e42
--- /dev/null
+++ b/install/samples/books/2_types/Hex_RGB.json
@@ -0,0 +1,4 @@
+{
+ "name": "Hex RGB",
+ "validation": "#[0-9A-Fa-f]{6}"
+}
\ No newline at end of file
diff --git a/install/samples/books/2_types/ISBN13.json b/install/samples/books/2_types/ISBN13.json
new file mode 100644
index 0000000..dee6026
--- /dev/null
+++ b/install/samples/books/2_types/ISBN13.json
@@ -0,0 +1,4 @@
+{
+ "name": "ISBN-13",
+ "validation": "\\d{3}\\-\\d{1}\\-\\d{2}\\-\\d{6}\\-\\d{1}"
+}
\ No newline at end of file
diff --git a/install/samples/books/2_types/Large_Text.json b/install/samples/books/2_types/Large_Text.json
new file mode 100644
index 0000000..9ba35bd
--- /dev/null
+++ b/install/samples/books/2_types/Large_Text.json
@@ -0,0 +1,4 @@
+{
+ "name": "Large Text",
+ "large": true
+}
\ No newline at end of file
diff --git a/install/samples/books/2_types/Number.json b/install/samples/books/2_types/Number.json
new file mode 100644
index 0000000..9390686
--- /dev/null
+++ b/install/samples/books/2_types/Number.json
@@ -0,0 +1,4 @@
+{
+ "name": "Number",
+ "validation": "\\d+"
+}
\ No newline at end of file
diff --git a/install/samples/books/2_types/Yes_No.json b/install/samples/books/2_types/Yes_No.json
new file mode 100644
index 0000000..d051ec3
--- /dev/null
+++ b/install/samples/books/2_types/Yes_No.json
@@ -0,0 +1,6 @@
+{
+ "name": "Ja/Nein",
+ "selectableValues": [
+ "Ja", "Nein"
+ ]
+}
\ No newline at end of file
diff --git a/install/samples/books/3_schemas/Colors_Schema.json b/install/samples/books/3_schemas/Colors_Schema.json
new file mode 100644
index 0000000..1a04b65
--- /dev/null
+++ b/install/samples/books/3_schemas/Colors_Schema.json
@@ -0,0 +1,38 @@
+{
+ "definitions": [
+ {
+ "name": "Name",
+ "typeId": {{types_Anything}},
+ "required": true,
+ "unique": true,
+ "mainEntry": true,
+ "titleField": true,
+ "translationDefinitions": [
+ {
+ "language": "ger",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "eng",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ },
+ {
+ "name": "Farbcode",
+ "typeId": {{types_Hex_RGB}},
+ "required": false,
+ "unique": true,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": false
+ }
+ ]
+}
\ No newline at end of file
diff --git a/install/samples/books/3_schemas/Names.json b/install/samples/books/3_schemas/Names.json
new file mode 100644
index 0000000..0379408
--- /dev/null
+++ b/install/samples/books/3_schemas/Names.json
@@ -0,0 +1,29 @@
+{
+ "definitions": [
+ {
+ "name": "Name",
+ "typeId": {{types_Anything}},
+ "required": true,
+ "unique": true,
+ "mainEntry": true,
+ "titleField": true,
+ "translationDefinitions": [
+ {
+ "language": "ger",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "eng",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/install/samples/books/4_vocabularies/Authors.json b/install/samples/books/4_vocabularies/Authors.json
new file mode 100644
index 0000000..926b63f
--- /dev/null
+++ b/install/samples/books/4_vocabularies/Authors.json
@@ -0,0 +1,5 @@
+{
+ "schemaId": {{schemas_Names}},
+ "name": "Autoren",
+ "description": "Liste aller bekannter Autoren."
+}
\ No newline at end of file
diff --git a/install/samples/books/4_vocabularies/Colors.json b/install/samples/books/4_vocabularies/Colors.json
new file mode 100644
index 0000000..b52b702
--- /dev/null
+++ b/install/samples/books/4_vocabularies/Colors.json
@@ -0,0 +1,4 @@
+{
+ "schemaId": {{schemas_Colors_Schema}},
+ "name": "Farben"
+}
\ No newline at end of file
diff --git a/install/samples/books/4_vocabularies/Locations.json b/install/samples/books/4_vocabularies/Locations.json
new file mode 100644
index 0000000..3e6b1f9
--- /dev/null
+++ b/install/samples/books/4_vocabularies/Locations.json
@@ -0,0 +1,5 @@
+{
+ "schemaId": {{schemas_Names}},
+ "name": "Standorte",
+ "description": "Liste aller Standorte an denen Bücher verwaltet werden."
+}
\ No newline at end of file
diff --git a/install/samples/books/5_schemas/Books_Schema.json b/install/samples/books/5_schemas/Books_Schema.json
new file mode 100644
index 0000000..6401e6c
--- /dev/null
+++ b/install/samples/books/5_schemas/Books_Schema.json
@@ -0,0 +1,98 @@
+{
+ "definitions": [
+ {
+ "name": "Buch-ID",
+ "typeId": {{types_Number}},
+ "required": true,
+ "unique": true,
+ "mainEntry": false,
+ "titleField": false
+ },
+ {
+ "name": "Name",
+ "typeId": {{types_Anything}},
+ "required": true,
+ "unique": true,
+ "mainEntry": true,
+ "titleField": true,
+ "translationDefinitions": [
+ {
+ "language": "ger",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "eng",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ },
+ {
+ "name": "ISBN",
+ "typeId": {{types_ISBN13}},
+ "required": true,
+ "unique": true,
+ "mainEntry": false,
+ "titleField": false
+ },
+ {
+ "name": "Veröffentlichung",
+ "typeId": {{types_Date}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false
+ },
+ {
+ "name": "Autoren",
+ "referenceVocabularyId": {{vocabularies_Authors}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true
+ },
+ {
+ "name": "Buchfarbe",
+ "referenceVocabularyId": {{vocabularies_Colors}},
+ "required": true,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": true,
+ "multiValued": false
+ },
+ {
+ "name": "Standort",
+ "referenceVocabularyId": {{vocabularies_Locations}},
+ "required": true,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": true,
+ "multiValued": false
+ },
+ {
+ "name": "Beschreibung",
+ "typeId": {{types_Large_Text}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": false
+ },
+ {
+ "name": "Ausgeliehen",
+ "typeId": {{types_Yes_No}},
+ "required": true,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": false
+ }
+ ]
+}
\ No newline at end of file
diff --git a/install/samples/books/6_vocabularies/Books.json b/install/samples/books/6_vocabularies/Books.json
new file mode 100644
index 0000000..4bf92f0
--- /dev/null
+++ b/install/samples/books/6_vocabularies/Books.json
@@ -0,0 +1,5 @@
+{
+ "schemaId": {{schemas_Books_Schema}},
+ "name": "Bücher",
+ "description": "Buchdatenbank."
+}
\ No newline at end of file
diff --git a/install/samples/books/7_records/Authors.csv b/install/samples/books/7_records/Authors.csv
new file mode 100644
index 0000000..34ea1f2
--- /dev/null
+++ b/install/samples/books/7_records/Authors.csv
@@ -0,0 +1,12 @@
+ID,Name (ger),Name (eng),Name (fre)
+,Johann Wolfgang von Goethe,Johann Wolfgang von Goethe,Johann Wolfgang von Goethe
+,William Shakespeare,William Shakespeare,William Shakespeare
+,Ernest Hemingway,Ernest Hemingway,Ernest Hemingway
+,Leo Tolstoy,Leo Tolstoy,Leo Tolstoï
+,George Orwell,George Orwell,George Orwell
+,Fyodor Dostoevsky,Fyodor Dostoevsky,Fyodor Dostoïevski
+,Marcel Proust,Marcel Proust,Marcel Proust
+,Franz Kafka,Franz Kafka,Franz Kafka
+,Jane Austen,Jane Austen,Jane Austen
+,Christopher Marlowe,Christopher Marlowe,Christopher Marlowe
+,F. Scott Fitzgerald,Francis Scott Fitzgerald,Francis Scott Fitzgerald
\ No newline at end of file
diff --git a/install/samples/books/7_records/Colors.csv b/install/samples/books/7_records/Colors.csv
new file mode 100644
index 0000000..04fd2b4
--- /dev/null
+++ b/install/samples/books/7_records/Colors.csv
@@ -0,0 +1,16 @@
+ID,Name (ger),Name (eng),Name (fre),Farbcode
+,Schwarz,Black,Noir,#000000
+,Weiß,White,Blanc,#FFFFFF
+,Rot,Red,Rouge,#FF0000
+,Grün,Green,Vert,#00FF00
+,Blau,Blue,Bleu,#0000FF
+,Gelb,Yellow,Jaune,#FFFF00
+,Orange,Orange,Orange,#FFA500
+,Lila,Purple,Violet,#800080
+,Rosa,Pink,Rose,#FFC0CB
+,Grau,Gray,Gris,#808080
+,Cyan,Cyan,Cyan,#00FFFF
+,Magenta,Magenta,Magenta,#FF00FF
+,Braun,Brown,Marron,#A52A2A
+,Beige,Beige,Beige,#F5F5DC
+,Olivgrün,Olive,Olive,#808000
\ No newline at end of file
diff --git a/install/samples/books/7_records/Locations.csv b/install/samples/books/7_records/Locations.csv
new file mode 100644
index 0000000..f741468
--- /dev/null
+++ b/install/samples/books/7_records/Locations.csv
@@ -0,0 +1,4 @@
+ID,Name (ger),Name (eng),Name (fre)
+,Göttingen,Göttingen,Göttingen
+,Hamburg,Hamburg,Hambourg
+,Brüssel,Brussels,Bruxelles
\ No newline at end of file
diff --git a/install/samples/skos/1_languages/Deutsch.json b/install/samples/skos/1_languages/Deutsch.json
new file mode 100644
index 0000000..5a2cdbb
--- /dev/null
+++ b/install/samples/skos/1_languages/Deutsch.json
@@ -0,0 +1,4 @@
+{
+ "abbreviation": "ger",
+ "name": "Deutsch"
+}
\ No newline at end of file
diff --git a/install/samples/skos/1_languages/English.json b/install/samples/skos/1_languages/English.json
new file mode 100644
index 0000000..34fc8a6
--- /dev/null
+++ b/install/samples/skos/1_languages/English.json
@@ -0,0 +1,4 @@
+{
+ "abbreviation": "eng",
+ "name": "English"
+}
\ No newline at end of file
diff --git "a/install/samples/skos/1_languages/Fran\303\247ais.json" "b/install/samples/skos/1_languages/Fran\303\247ais.json"
new file mode 100644
index 0000000..e796791
--- /dev/null
+++ "b/install/samples/skos/1_languages/Fran\303\247ais.json"
@@ -0,0 +1,4 @@
+{
+ "abbreviation": "fre",
+ "name": "Français"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/DCT_created.json b/install/samples/skos/2_types/DCT_created.json
new file mode 100644
index 0000000..0229cdb
--- /dev/null
+++ b/install/samples/skos/2_types/DCT_created.json
@@ -0,0 +1,4 @@
+{
+ "name": "dct:created",
+ "validation": "\\d{4}\\-\\d{2}\\-\\d{2}"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/DCT_creator.json b/install/samples/skos/2_types/DCT_creator.json
new file mode 100644
index 0000000..9d3fad4
--- /dev/null
+++ b/install/samples/skos/2_types/DCT_creator.json
@@ -0,0 +1,3 @@
+{
+ "name": "dct:creator"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/DCT_license.json b/install/samples/skos/2_types/DCT_license.json
new file mode 100644
index 0000000..41f0638
--- /dev/null
+++ b/install/samples/skos/2_types/DCT_license.json
@@ -0,0 +1,4 @@
+{
+ "name": "dct:license",
+ "validation": "https?.*"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/DCT_title.json b/install/samples/skos/2_types/DCT_title.json
new file mode 100644
index 0000000..23ac34a
--- /dev/null
+++ b/install/samples/skos/2_types/DCT_title.json
@@ -0,0 +1,3 @@
+{
+ "name": "dct:title"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/SKOS_altLabel.json b/install/samples/skos/2_types/SKOS_altLabel.json
new file mode 100644
index 0000000..1d7cadc
--- /dev/null
+++ b/install/samples/skos/2_types/SKOS_altLabel.json
@@ -0,0 +1,3 @@
+{
+ "name": "skos:altLabel"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/SKOS_closeMatch.json b/install/samples/skos/2_types/SKOS_closeMatch.json
new file mode 100644
index 0000000..da55e56
--- /dev/null
+++ b/install/samples/skos/2_types/SKOS_closeMatch.json
@@ -0,0 +1,4 @@
+{
+ "name": "skos:closeMatch",
+ "validation": "https?.*"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/SKOS_definition.json b/install/samples/skos/2_types/SKOS_definition.json
new file mode 100644
index 0000000..e48d92e
--- /dev/null
+++ b/install/samples/skos/2_types/SKOS_definition.json
@@ -0,0 +1,3 @@
+{
+ "name": "skos:definition"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/SKOS_editorialNote.json b/install/samples/skos/2_types/SKOS_editorialNote.json
new file mode 100644
index 0000000..600a3b3
--- /dev/null
+++ b/install/samples/skos/2_types/SKOS_editorialNote.json
@@ -0,0 +1,3 @@
+{
+ "name": "skos:editorialNote"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/SKOS_exactMatch.json b/install/samples/skos/2_types/SKOS_exactMatch.json
new file mode 100644
index 0000000..4419c76
--- /dev/null
+++ b/install/samples/skos/2_types/SKOS_exactMatch.json
@@ -0,0 +1,4 @@
+{
+ "name": "skos:exactMatch",
+ "validation": "https?.*"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/SKOS_prefLabel.json b/install/samples/skos/2_types/SKOS_prefLabel.json
new file mode 100644
index 0000000..8b52ed0
--- /dev/null
+++ b/install/samples/skos/2_types/SKOS_prefLabel.json
@@ -0,0 +1,3 @@
+{
+ "name": "skos:prefLabel"
+}
\ No newline at end of file
diff --git a/install/samples/skos/2_types/SKOS_related.json b/install/samples/skos/2_types/SKOS_related.json
new file mode 100644
index 0000000..14c1af3
--- /dev/null
+++ b/install/samples/skos/2_types/SKOS_related.json
@@ -0,0 +1,3 @@
+{
+ "name": "skos:related"
+}
\ No newline at end of file
diff --git a/install/samples/skos/3_schemas/SKOS_Data.json b/install/samples/skos/3_schemas/SKOS_Data.json
new file mode 100644
index 0000000..73af94d
--- /dev/null
+++ b/install/samples/skos/3_schemas/SKOS_Data.json
@@ -0,0 +1,135 @@
+{
+ "definitions": [
+ {
+ "name": "Label",
+ "typeId": {{types_SKOS_prefLabel}},
+ "required": true,
+ "unique": false,
+ "mainEntry": true,
+ "titleField": true,
+ "translationDefinitions": [
+ {
+ "language": "eng",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "ger",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ },
+ {
+ "name": "Alternative Label",
+ "typeId": {{types_SKOS_altLabel}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true,
+ "translationDefinitions": [
+ {
+ "language": "eng",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "ger",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ },
+ {
+ "name": "Definition",
+ "typeId": {{types_SKOS_definition}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true,
+ "translationDefinitions": [
+ {
+ "language": "eng",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "ger",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ },
+ {
+ "name": "Editorial Note",
+ "typeId": {{types_SKOS_editorialNote}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true,
+ "translationDefinitions": [
+ {
+ "language": "eng",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "ger",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ },
+ {
+ "name": "Related",
+ "typeId": {{types_SKOS_related}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true
+ },
+ {
+ "name": "Close Match",
+ "typeId": {{types_SKOS_closeMatch}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true
+ },
+ {
+ "name": "Exact Match",
+ "typeId": {{types_SKOS_exactMatch}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true
+ }
+ ],
+ "hierarchicalRecords": true
+}
\ No newline at end of file
diff --git a/install/samples/skos/3_schemas/SKOS_Metadata.json b/install/samples/skos/3_schemas/SKOS_Metadata.json
new file mode 100644
index 0000000..45d49bd
--- /dev/null
+++ b/install/samples/skos/3_schemas/SKOS_Metadata.json
@@ -0,0 +1,74 @@
+{
+ "definitions": [
+ {
+ "name": "Title",
+ "typeId": {{types_DCT_title}},
+ "required": true,
+ "unique": false,
+ "mainEntry": true,
+ "titleField": true,
+ "translationDefinitions": [
+ {
+ "language": "eng",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "ger",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ },
+ {
+ "name": "Author",
+ "typeId": {{types_DCT_creator}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true,
+ "translationDefinitions": [
+ {
+ "language": "eng",
+ "fallback": true,
+ "required": true
+ },
+ {
+ "language": "ger",
+ "fallback": false,
+ "required": false
+ },
+ {
+ "language": "fre",
+ "fallback": false,
+ "required": false
+ }
+ ]
+ },
+ {
+ "name": "Creation Date",
+ "typeId": {{types_DCT_created}},
+ "required": true,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false
+ },
+ {
+ "name": "License",
+ "typeId": {{types_DCT_license}},
+ "required": false,
+ "unique": false,
+ "mainEntry": false,
+ "titleField": false,
+ "multiValued": true
+ }
+ ],
+ "hierarchicalRecords": false,
+ "singleRootElement": true
+}
\ No newline at end of file
diff --git a/install/samples/skos/4_vocabularies/Role.json b/install/samples/skos/4_vocabularies/Role.json
new file mode 100644
index 0000000..41eb5b8
--- /dev/null
+++ b/install/samples/skos/4_vocabularies/Role.json
@@ -0,0 +1,6 @@
+{
+ "schemaId": {{schemas_SKOS_Data}},
+ "metadataSchemaId": {{schemas_SKOS_Metadata}},
+ "name": "Role",
+ "description": "An example SKOS vocabulary."
+}
\ No newline at end of file
diff --git a/install/samples/skos/5_records/Role.xlsx b/install/samples/skos/5_records/Role.xlsx
new file mode 100644
index 0000000..67a3824
Binary files /dev/null and b/install/samples/skos/5_records/Role.xlsx differ
diff --git a/module-core/pom.xml b/module-core/pom.xml
index 967e569..d5f656f 100644
--- a/module-core/pom.xml
+++ b/module-core/pom.xml
@@ -10,7 +10,7 @@
io.goobi.vocabulary
vocabulary-server-core
- 1.1.3
+ 1.1.4
Vocabulary-Server-Core
Spring Boot based RESTful web service for vocabulary management
jar
@@ -26,7 +26,7 @@
io.goobi.vocabulary
vocabulary-server-exchange
- 1.1.3
+ 1.1.4
compile
diff --git a/module-core/src/main/java/io/goobi/vocabulary/model/jpa/FieldDefinitionEntity.java b/module-core/src/main/java/io/goobi/vocabulary/model/jpa/FieldDefinitionEntity.java
index a1e6c04..1504bdb 100644
--- a/module-core/src/main/java/io/goobi/vocabulary/model/jpa/FieldDefinitionEntity.java
+++ b/module-core/src/main/java/io/goobi/vocabulary/model/jpa/FieldDefinitionEntity.java
@@ -90,7 +90,7 @@ public final boolean equals(Object o) {
return false;
}
FieldDefinitionEntity that = (FieldDefinitionEntity) o;
- return id != that.id;
+ return id == that.id;
}
@Override
diff --git a/module-core/src/main/java/io/goobi/vocabulary/security/SecurityConfiguration.java b/module-core/src/main/java/io/goobi/vocabulary/security/SecurityConfiguration.java
index b1027cc..2ddf272 100644
--- a/module-core/src/main/java/io/goobi/vocabulary/security/SecurityConfiguration.java
+++ b/module-core/src/main/java/io/goobi/vocabulary/security/SecurityConfiguration.java
@@ -23,8 +23,8 @@ public SecurityConfiguration(BearerTokenAuthFilter bearerTokenAuthFilter) {
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
- .dispatcherTypeMatchers(DispatcherType.ASYNC)
- .permitAll()
+ .dispatcherTypeMatchers(DispatcherType.ASYNC).permitAll()
+ .requestMatchers("/docs/**").permitAll()
.anyRequest()
.authenticated()
)
diff --git a/module-core/src/test/java/io/goobi/vocabulary/validation/RecordValidationTests.java b/module-core/src/test/java/io/goobi/vocabulary/validation/RecordValidationTests.java
index 2227d2e..d1cb617 100644
--- a/module-core/src/test/java/io/goobi/vocabulary/validation/RecordValidationTests.java
+++ b/module-core/src/test/java/io/goobi/vocabulary/validation/RecordValidationTests.java
@@ -32,6 +32,7 @@ class RecordValidationTests {
private VocabularyEntity vocabulary;
private FieldTypeEntity ftText;
private FieldDefinitionEntity fdName;
+ private FieldDefinitionEntity fdOther;
@BeforeEach
@@ -47,6 +48,7 @@ public void setUp() {
vocabulary.setName("Test vocabulary");
fdName = new FieldDefinitionEntity();
+ fdName.setId(1L);
fdName.setSchema(schema);
fdName.setName("Name");
fdName.setType(ftText);
@@ -55,17 +57,41 @@ public void setUp() {
fdName.setUnique(true);
fdName.setRequired(true);
- schema.setDefinitions(List.of(fdName));
+ fdOther = new FieldDefinitionEntity();
+ fdOther.setId(2L);
+ fdOther.setSchema(schema);
+ fdOther.setName("Other");
+ fdOther.setType(ftText);
+ fdOther.setMainEntry(false);
+ fdOther.setTitleField(true);
+ fdOther.setUnique(false);
+ fdOther.setRequired(true);
+
+ schema.setDefinitions(List.of(fdName, fdOther));
}
@Test
- void missingRequiredField_fails() {
+ void missingAllRequiredFields_fails() {
VocabularyRecordEntity record = new VocabularyRecordEntity();
record.setVocabulary(vocabulary);
assertThrows(VocabularyException.class, () -> validator.validate(record));
}
+ @Test
+ void missingOneRequiredField_fails() {
+ VocabularyRecordEntity record = new VocabularyRecordEntity();
+ record.setVocabulary(vocabulary);
+
+ FieldInstanceEntity name = new FieldInstanceEntity();
+ name.setVocabularyRecord(record);
+ name.setDefinition(fdName);
+
+ record.setFields(List.of(name));
+
+ assertThrows(VocabularyException.class, () -> validator.validate(record));
+ }
+
@Test
void insertingUnspecifiedField_fails() {
VocabularyRecordEntity record = new VocabularyRecordEntity();
@@ -129,15 +155,23 @@ void hierarchicalRecordsIfEnabled_success() {
parentNameField.setId(1L);
parentNameField.setDefinition(fdName);
parentNameField.setVocabularyRecord(parent);
- parent.setFields(List.of(parentNameField));
+ FieldInstanceEntity parentOtherField = new FieldInstanceEntity();
+ parentOtherField.setId(2L);
+ parentOtherField.setDefinition(fdOther);
+ parentOtherField.setVocabularyRecord(parent);
+ parent.setFields(List.of(parentNameField, parentOtherField));
VocabularyRecordEntity child = new VocabularyRecordEntity();
child.setVocabulary(vocabulary);
FieldInstanceEntity childNameField = new FieldInstanceEntity();
- childNameField.setId(2L);
+ childNameField.setId(3L);
childNameField.setDefinition(fdName);
childNameField.setVocabularyRecord(child);
- child.setFields(List.of(childNameField));
+ FieldInstanceEntity childOtherField = new FieldInstanceEntity();
+ childOtherField.setId(4L);
+ childOtherField.setDefinition(fdOther);
+ childOtherField.setVocabularyRecord(child);
+ child.setFields(List.of(childNameField, childOtherField));
child.setParentRecord(parent);
parent.setChildren(List.of(child));
diff --git a/module-exchange/pom.xml b/module-exchange/pom.xml
index 4b96b43..9bfc74b 100644
--- a/module-exchange/pom.xml
+++ b/module-exchange/pom.xml
@@ -4,7 +4,7 @@
4.0.0
io.goobi.vocabulary
vocabulary-server-exchange
- 1.1.3
+ 1.1.4
Vocabulary Exchange
Vocabulary data exchange classes
jar
diff --git a/pom.xml b/pom.xml
index ac39ccd..869d41e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
io.goobi.vocabulary
vocabulary-server
- 1.1.3
+ 1.1.4
Vocabulary-Server
pom
RESTful webservice for vocabulary management