<%= study_fields.label "Study position" -%>
@@ -33,8 +33,10 @@
<%= render partial: 'custom_metadata/custom_metadata_attribute_input', locals:{f:f,resource:@isa_study.study} %>
+
<%= render partial: 'assets/manage_specific_attributes', locals: { f: study_fields } if show_form_manage_specific_attributes? %>
+
<%= study_fields.fancy_multiselect :publications, { other_projects_checkbox: true, name: "isa_study[study][publication_ids]" } %>
<%= render :partial=> "assets/discussion_links_form", :locals=>{:resource => @isa_study.study} -%>
@@ -42,7 +44,7 @@
<%= render partial: 'projects/implicit_project_selector', locals: { action: action,
select_id: '#study_investigation_id',
parents: Investigation.authorized_for('edit') } %>
-
+
<%= folding_panel("Define #{t(:sample_type)} for Source") do %>
<%= render partial: 'sample_types_form', locals: {f: f, sample_type: @isa_study.source, id_suffix: "_source_sample_type", action: action } if @isa_study.source %>
<% end %>
@@ -58,11 +60,11 @@
<%= render partial: 'sample_types_form', locals: {f: f, sample_type: @isa_study.sample_collection, id_suffix: "_sample_collection_sample_type", action: action } if @isa_study.sample_collection %>
<% end %>
-<% end -%>
+<% end -%>
+
-
<%= form_submit_buttons(@isa_study.study) %>
\ No newline at end of file
+ Templates.init($j('#template-attributes'));
+ });
+
diff --git a/app/views/sample_types/_sample_attribute_form.html.erb b/app/views/sample_types/_sample_attribute_form.html.erb
index 9dbb9b55f0..b2ff05fb62 100644
--- a/app/views/sample_types/_sample_attribute_form.html.erb
+++ b/app/views/sample_types/_sample_attribute_form.html.erb
@@ -52,7 +52,7 @@
<%= select_tag "#{field_name_prefix}[sample_attribute_type_id]",
- options_for_select(SampleAttributeType.all.sort_by(&:title).sort_by { |t| t.default? ? 0 : 1 }.map { |t| [t.title, t.id,{'data-use-cv'=>t.controlled_vocab? || t.seek_cv_list?,'data-is-ontology'=>t.ontology?, 'data-is-seek-sample'=>t.seek_sample? || t.seek_sample_multi? }] }, attribute_type_id),
+ options_for_select(displayed_sample_attribute_types.sort_by(&:title).sort_by { |t| t.default? ? 0 : 1 }.map { |t| [t.title, t.id,{'data-use-cv'=>t.controlled_vocab? || t.seek_cv_list?,'data-is-ontology'=>t.ontology?, 'data-is-seek-sample'=>t.seek_sample? || t.seek_sample_multi? }] }, attribute_type_id),
class: 'form-control sample-type-attribute-type',
disabled: !allow_type_change, data: { attr: "type" } %>
diff --git a/app/views/samples/_attribute_fields.html.erb b/app/views/samples/_attribute_fields.html.erb
index d8915fe791..7d745019ba 100644
--- a/app/views/samples/_attribute_fields.html.erb
+++ b/app/views/samples/_attribute_fields.html.erb
@@ -6,10 +6,4 @@
<% end %>
<%= sample_form_field_for_attribute(attribute, @sample) %>
-
<% end %>
diff --git a/app/views/workflows/_resource_list_item.html.erb b/app/views/workflows/_resource_list_item.html.erb
index 23e5219e28..bc3ef4075a 100644
--- a/app/views/workflows/_resource_list_item.html.erb
+++ b/app/views/workflows/_resource_list_item.html.erb
@@ -13,7 +13,7 @@
<%= list_item_attribute('Type', resource.workflow_class_title) %>
- <%= render partial:"assets/resource_list_item_contributor_and_creators",object:resource %>
+ <%= render partial: 'assets/resource_list_item_contributor_and_creators', object: resource %>
<%= list_item_doi(resource) %>
<% if Seek::Config.isa_enabled %>
diff --git a/config/schedule.rb b/config/schedule.rb
index 545f0bfcf1..db5b73f2ef 100644
--- a/config/schedule.rb
+++ b/config/schedule.rb
@@ -29,17 +29,25 @@
set :output, "#{path}/log/schedule.log"
+MIDNIGHT = Time.now.midnight
+# Apply a static offset, plus an optional configured offset, to run times of periodic jobs.
+# This is to avoid them all occurring at the same time and overloading the server.
+def offset(off_hours)
+ off_minutes = Seek::Config.regular_job_offset || 0
+ (MIDNIGHT + off_hours.hours + off_minutes.minutes).strftime("%-l:%M%P")
+end
+
PeriodicSubscriptionEmailJob::DELAYS.each do |frequency, period|
- every period do
+ every period, at: offset(0) do
runner "PeriodicSubscriptionEmailJob.new('#{frequency}').queue_job"
end
end
-every RegularMaintenanceJob::RUN_PERIOD do
+every RegularMaintenanceJob::RUN_PERIOD, at: offset(1) do
runner "RegularMaintenanceJob.perform_later"
end
-every LifeMonitorStatusJob::PERIOD do
+every LifeMonitorStatusJob::PERIOD, at: offset(2) do
runner "LifeMonitorStatusJob.perform_later"
end
@@ -55,7 +63,7 @@
runner 'ApplicationStatus.instance.refresh'
end
-every 1.day do
+every 1.day, at: offset(3) do
runner 'Galaxy::ToolMap.instance.refresh'
end
diff --git a/config/version.yml b/config/version.yml
index e159f02e42..53646a6c84 100644
--- a/config/version.yml
+++ b/config/version.yml
@@ -9,4 +9,4 @@
major: 1
minor: 13
-patch: 1
+patch: 2
diff --git a/db/migrate/20230125212353_create_custom_metadata_resource_links.rb b/db/migrate/20230125212353_create_custom_metadata_resource_links.rb
new file mode 100644
index 0000000000..1657411f76
--- /dev/null
+++ b/db/migrate/20230125212353_create_custom_metadata_resource_links.rb
@@ -0,0 +1,8 @@
+class CreateCustomMetadataResourceLinks < ActiveRecord::Migration[6.1]
+ def change
+ create_table :custom_metadata_resource_links do |t|
+ t.references :custom_metadata
+ t.references :resource, polymorphic: true
+ end
+ end
+end
diff --git a/db/migrate/20230206214438_add_linked_custom_metadata_type_to_custom_metadata_attribute.rb b/db/migrate/20230206214438_add_linked_custom_metadata_type_to_custom_metadata_attribute.rb
new file mode 100644
index 0000000000..cb0ce8cd00
--- /dev/null
+++ b/db/migrate/20230206214438_add_linked_custom_metadata_type_to_custom_metadata_attribute.rb
@@ -0,0 +1,5 @@
+class AddLinkedCustomMetadataTypeToCustomMetadataAttribute < ActiveRecord::Migration[6.1]
+ def change
+ add_column :custom_metadata_attributes,:linked_custom_metadata_type_id,:integer
+ end
+end
diff --git a/db/migrate/20230330131838_add_custom_metadata_attribute_to_custom_metadata.rb b/db/migrate/20230330131838_add_custom_metadata_attribute_to_custom_metadata.rb
new file mode 100644
index 0000000000..190f8c7657
--- /dev/null
+++ b/db/migrate/20230330131838_add_custom_metadata_attribute_to_custom_metadata.rb
@@ -0,0 +1,5 @@
+class AddCustomMetadataAttributeToCustomMetadata < ActiveRecord::Migration[6.1]
+ def change
+ add_column :custom_metadata, :custom_metadata_attribute_id,:integer
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e7225a5d3f..333b6b6074 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2022_12_12_143407) do
+ActiveRecord::Schema.define(version: 2023_03_30_131838) do
create_table "activity_logs", id: :integer, force: :cascade do |t|
t.string "action"
@@ -369,6 +369,7 @@
t.string "item_type"
t.bigint "item_id"
t.bigint "custom_metadata_type_id"
+ t.integer "custom_metadata_attribute_id"
t.index ["custom_metadata_type_id"], name: "index_custom_metadata_on_custom_metadata_type_id"
t.index ["item_type", "item_id"], name: "index_custom_metadata_on_item_type_and_item_id"
end
@@ -382,11 +383,20 @@
t.bigint "sample_controlled_vocab_id"
t.text "description"
t.string "label"
+ t.integer "linked_custom_metadata_type_id"
t.index ["custom_metadata_type_id"], name: "index_custom_metadata_attributes_on_custom_metadata_type_id"
t.index ["sample_attribute_type_id"], name: "index_custom_metadata_attributes_on_sample_attribute_type_id"
t.index ["sample_controlled_vocab_id"], name: "index_custom_metadata_attributes_on_sample_controlled_vocab_id"
end
+ create_table "custom_metadata_resource_links", force: :cascade do |t|
+ t.bigint "custom_metadata_id"
+ t.string "resource_type"
+ t.bigint "resource_id"
+ t.index ["custom_metadata_id"], name: "index_custom_metadata_resource_links_on_custom_metadata_id"
+ t.index ["resource_type", "resource_id"], name: "index_custom_metadata_resource_links_on_resource"
+ end
+
create_table "custom_metadata_types", force: :cascade do |t|
t.string "title"
t.integer "contributor_id"
diff --git a/db/seeds/007_sample_attribute_types.seeds.rb b/db/seeds/007_sample_attribute_types.seeds.rb
index 4601b7b977..5507134ace 100644
--- a/db/seeds/007_sample_attribute_types.seeds.rb
+++ b/db/seeds/007_sample_attribute_types.seeds.rb
@@ -85,6 +85,9 @@
cv_list_type = SampleAttributeType.find_or_initialize_by(title:'Controlled Vocabulary List')
cv_list_type.update(base_type: Seek::Samples::BaseType::CV_LIST)
+linked_custom_metadata_type = SampleAttributeType.find_or_initialize_by(title:'Linked Custom Metadata')
+linked_custom_metadata_type.update(base_type: Seek::Samples::BaseType::LINKED_CUSTOM_METADATA)
+
puts "Seeded #{SampleAttributeType.count - count} sample attribute types"
# Sample types
diff --git a/docs/AdminGuide/administration.md b/docs/AdminGuide/administration.md
new file mode 100644
index 0000000000..75d902e958
--- /dev/null
+++ b/docs/AdminGuide/administration.md
@@ -0,0 +1,28 @@
+# Verwaltung von SEEK
+
+Hier werden einige grundlegende Administrationsaufgaben beschrieben, die Sie nach der Installation von SEEK durchführen können. Alle Verwaltungsaufgaben finden Sie im Administrationsbereich, indem Sie die Registerkarte Konto und dann die Serververwaltung auswählen. Viele der Einstellungen haben eine Beschreibung ihrer Funktion und werden hier nicht behandelt.
+## Erstellen eines Projekts und einer Einrichtung
+
+Bevor Sie Elemente, wie z. B. Datendateien oder Modelle, zu SEEK hinzufügen können, müssen Sie das erste Projekt und die erste Einrichtung erstellen und sich selbst zu diesen hinzufügen.
+
+Sie können Ihr Projekt und Ihre Einrichtung zunächst über die allgemeinen Aufgaben im Verwaltungsbereich erstellen.
+
+Sobald diese erstellt sind, müssen Sie das Projekt mit der Einrichtung verknüpfen, indem Sie zur Seite Projekt anzeigen navigieren und auf die Schaltfläche Projektverwaltung klicken. Auf dieser Seite können Sie eine oder mehrere Einrichtungen für dieses Projekt auswählen und dann durch Klicken auf die Schaltfläche Aktualisieren am unteren Rand des Formulars speichern.
+
+Sie können sich selbst zu dem von Ihnen erstellten Projekt und der Einrichtung hinzufügen, indem Sie zu Ihrem Profil navigieren, die Personenverwaltung auswählen, dann das Projekt/Einrichtung-Paar aus der Liste auswählen und auf die Schaltfläche Aktualisieren am unteren Ende des Formulars klicken.
+
+Beachten Sie, dass Projekte mit mehreren Institutionen verbunden sein können und Personen zu mehreren Projekt/Institution-Paaren gehören können. Wenn Sie mehrere Elemente aus den Listen auswählen, müssen Sie die STRG-Taste gedrückt halten, während Sie sie auswählen.
+
+## E-Mail konfigurieren
+
+Standardmäßig ist E-Mail deaktiviert, aber wenn Sie die Möglichkeit haben, können Sie es so konfigurieren, dass SEEK E-Mails versendet - z.B. E-Mails über Änderungen in Ihrem Projekt, Benachrichtigungs-E-Mails, Feedback-E-Mails und Benachrichtigungen über Fehler. Sie können E-Mails unter Admin->Konfiguration->Funktionen aktivieren/deaktivieren konfigurieren. Ganz unten auf dieser Seite gibt es ein Kontrollkästchen "E-Mail aktiviert", das Sie aktivieren sollten. Daraufhin werden einige SMTP-Einstellungen angezeigt, die Sie ausfüllen müssen. Alle, die nicht benötigt werden, können leer gelassen werden. Die Bedeutung der Einstellungen sind:
+
+- Adresse - die Adresse (Name oder IP-Adresse) des SMTP-Servers, der für die Zustellung ausgehender E-Mails verwendet wird
+- Port - der Port, über den Ihr Mailserver E-Mails empfängt
+- Domäne - wenn Sie eine HELO-Domäne angeben müssen, können Sie dies hier tun.
+- Authentifizierung - wenn Ihr Mailserver eine Authentifizierung erfordert, müssen Sie hier den Authentifizierungstyp angeben. Dies kann plain (sendet das Passwort im Klartext), login (sendet das Passwort Base64 kodiert) oder in seltenen Fällen cram_md5 sein.
+- Auto STARTTLS enabled - aktivieren Sie dies, wenn Ihr Mailserver Tranport Layer Security erfordert und Sie beim Testen Ihrer Konfiguration STARTTLS-Fehler erhalten
+- Benutzername - wenn Ihr Mailserver eine Authentifizierung erfordert, geben Sie den Benutzernamen in dieser Einstellung an.
+- Passwort - wenn Ihr Mailserver eine Authentifizierung erfordert, geben Sie hier das Passwort ein.
+
+Darunter befindet sich ein Feld, mit dem Sie Ihre Einstellungen testen können. Wenn Sie außerdem E-Mails über aufgetretene Fehler erhalten möchten, können Sie das Kästchen "Ausnahmebenachrichtigung aktiviert" ankreuzen und unten eine Liste von E-Mail-Adressen angeben (durch Komma oder Leerzeichen getrennt).
\ No newline at end of file
diff --git a/docs/AdminGuide/deployment.md b/docs/AdminGuide/deployment.md
new file mode 100644
index 0000000000..5eb510c8b9
--- /dev/null
+++ b/docs/AdminGuide/deployment.md
@@ -0,0 +1,36 @@
+# NFDI4Health LDH Deployment
+Anweisungen und Ressourcen für die Einrichtung eines NFDI4Health Local Data Hup.
+
+## Haftungsausschluss
+Dieses Projekt und seine Komponenten sind Gegenstand intensiver Entwicklung und werden daher als *[Alpha][wiki-alpha]*-Version betrachtet. Verwenden Sie diese Bereitstellungsmethode **noch** nicht für Produktionszwecke, da Sie in Zukunft gezwungen sein könnten, eine Neuinstallation durchzuführen, was zum Verlust der hochgeladenen Daten führen könnte. Wenn Sie jedoch versuchen möchten, an der Entwicklung der Software teilzunehmen, sind Sie hiermit herzlich eingeladen, dies zu tun. Fühlen Sie sich frei, Fehlerberichte und Vorschläge im Issue Tracker zu erstellen.
+
+## Voraussetzungen
+### Docker
+* Docker muss auf dem System installiert sein. Bitte folgen Sie den [offiziellen Installationsanweisungen][docker-install]
+* Denken Sie auch daran, einem Nicht-Root-Linux-Benutzer die Verwendung von Docker zu erlauben, indem Sie ihn zur Docker-Gruppe hinzufügen (siehe [Docker][docker-ugroup]-Dokumentation), da sonst nur ein Root-Benutzer in der Lage ist, Docker auszuführen.
+## Verwendung
+Um einen ersten und einfachen Einblick zu bekommen, wie eine ldh aussehen wird, folgen Sie den folgenden Schritten.
+
+* Klonen Sie dieses Repository
+```bash
+git clone https://github.com/nfdi4health/ldh-deployment.git
+cd ldh-deployment
+```
+* Kopieren Sie docker-compose.env.tpl nach docker-compose.env und ersetzen Sie durch ein Passwort
+```bash
+cat docker-compose.env.tpl \
+ | sed "s||$(openssl rand -base64 21)|" \
+ | sed "s||$(openssl rand -base64 21)|" \
+ > docker-compose.env
+```
+* Verwenden Sie compose zum Starten des LDH
+```
+docker compose up -d
+```
+
+
+
+[wiki-alpha]: https://en.wikipedia.org/wiki/Software_release_life_cycle#Alpha
+[project-issues]: https://github.com/nfdi4health/ldh-deployment/issues
+[docker-install]: https://docs.docker.com/get-docker/
+[docker-ugroup]: https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user
diff --git a/docs/AdminGuide/dockercomp.md b/docs/AdminGuide/dockercomp.md
new file mode 100644
index 0000000000..bdcfedf1bd
--- /dev/null
+++ b/docs/AdminGuide/dockercomp.md
@@ -0,0 +1,144 @@
+# Docker
+## Verwenden von Docker Compose
+
+Mit Docker Compose können Sie SEEK in Docker zusammen mit MySQL und SOLR ausführen, die in eigenen Containern als Mikrodienste ausgeführt werden.
+
+Zunächst muss [Docker installiert](https://docs.docker.com/engine/install/) sein.
+Informationen zur Installation von Docker Compose finden Sie im Docker Compose-Installationshandbuch.
+
+Nach der Installation sind lediglich die Dateien `docker-compose.yml` und `docker/db.env` erforderlich. Sie können sich aber auch einfach die SEEK-Quelle von GitHub ansehen – siehe [LHD installieren](./install_dev.md#ldh-installieren). Wir empfehlen Ihnen, die Passwörter in der Datei `db.env` zu ändern.
+
+Zuerst müssen Sie 4 Volumes erstellen
+```bash
+Docker-Volume erstellen --name=seek-filestore
+Docker-Volume erstellen --name=seek-mysql-db
+Docker-Volume erstellen --name=seek-solr-data
+Docker-Volume erstellen --name=seek-cache
+```
+und dann zum Starten die Datei docker-compose.yml in Ihrem aktuellen Verzeichnis ausführen
+```
+docker-compose up -d
+```
+und gehen Sie zu http://localhost:3000. Es kann zu einer kurzen Verzögerung kommen, bevor Sie eine Verbindung herstellen können, insbesondere wenn dies das erste Mal ist und verschiedene Dinge initialisiert werden.
+
+den Lauf stoppen
+```
+docker-compose down
+```
+Sie ändern den Port und das Bild in der docker-compose.yml durch Bearbeiten
+```bash
+seek:
+ ..
+ ..
+ image: fairdom/seek:1.13
+ ..
+ ..
+ ports:
+ - "3000:3000"
+```
+## Proxy über NGINX oder Apache
+
+Als Alternative zum Ändern des Ports (insbesondere wenn mehrere Instanzen auf demselben Computer ausgeführt werden) können Sie einen Proxy über Apache oder Nginx durchführen. Z.B. Für Nginx würden Sie einen virtuellen Host wie folgt konfigurieren:
+```bash
+server {
+ listen 80;
+ server_name www.my-seek.org;
+ client_max_body_size 2G;
+
+ location / {
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header Host $host:$server_port;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass http://127.0.0.1:3000;
+ }
+}
+```
+Für Apache würde der virtuelle Host Folgendes umfassen:
+```bash
+UseCanonicalName on
+ProxyPreserveHost on
+
+ ProxyPass http://127.0.0.1:3000/ Keepalive=On
+ ProxyPassReverse http://127.0.0.1:3000/
+
+```
+Sie möchten auch HTTPS (Port 443) konfigurieren und empfehlen dringend die Verwendung von Lets Encrypt für kostenlose SSL-Zertifikate.
+## Sichern und Wiederherstellen
+
+Um die MySQL-Datenbank zu sichern und den Dateispeicher zu suchen, müssen Sie die Volumes in einem temporären Container bereitstellen. Versuchen Sie nicht, ein Backup zu erstellen, indem Sie die Volumes direkt vom Hostsystem kopieren. Im Folgenden finden Sie ein Beispiel für ein grundlegendes Verfahren. Wir empfehlen Ihnen jedoch, Datenvolumes sichern, wiederherstellen oder migrieren zu lesen und sich mit der Bedeutung der Schritte vertraut zu machen.
+```bash
+docker-compose stop
+docker run --rm --volumes-from seek -v $(pwd):/backup ubuntu tar cvf /backup/seek-filestore.tar /seek/filestore
+docker run --rm --volumes-from seek-mysql -v $(pwd):/backup ubuntu tar cvf /backup/seek-mysql-db.tar /var/lib/mysql
+docker-compose start
+```
+und zum Wiederherstellen in neue Volumes:
+```bash
+docker-compose down
+docker volume rm seek-filestore
+docker volume rm seek-mysql-db
+docker volume create --name=seek-filestore
+docker volume create --name=seek-mysql-db
+docker-compose up --no-start
+docker run --rm --volumes-from seek -v $(pwd):/backup ubuntu bash -c "tar xfv /backup/seek-filestore.tar"
+docker run --rm --volumes-from seek-mysql -v $(pwd):/backup ubuntu bash -c "tar xfv /backup/seek-mysql-db.tar"
+docker-compose up -d
+```
+**Beachten Sie**, dass es beim Zurücksetzen einer Version, beispielsweise nach einem fehlgeschlagenen Upgrade, besonders wichtig ist, die Volumes „seek-filestore“ und „seek-mysql-db“ zu entfernen und neu zu erstellen – andernfalls könnten zusätzliche Dateien übrig bleiben, wenn das Backup übertrieben wiederhergestellt wird .
+
+Der Cache und der Solr-Index müssen nicht gesichert werden. Sobald der Solr-Index betriebsbereit ist, kann er bei Bedarf neu generiert werden mit:
+```bash
+docker exec seek bundle exec rake seek:reindex_all
+```
+## Upgrade zwischen Versionen
+
+Der Vorgang ist dem Upgrade eines Basiscontainers sehr ähnlich.
+
+Aktualisieren Sie zunächst die `docker-compose.yml` auf die neue Version. Sie können die Version anhand des Image-Tags erkennen – z. B. für 1.13
+```
+image: fairdom/seek:1.13
+```
+
+Führen Sie mit der neuen Datei docker-compose.yml Folgendes aus:
+```
+docker-compose down
+docker-compose pull
+docker-compose up -d seek db solr # avoiding the seek-workers, which will interfere
+docker exec -it seek docker/upgrade.sh
+docker-compose down
+docker-compose up -d
+```
+## Wechsel von einer eigenständigen Installation zu Docker Compose
+
+Wenn Sie eine bestehende SEEK-Installation auf „Bare Metal“ haben und auf die Verwendung von Docker Compose umsteigen möchten, haben wir ein Skript, das Ihnen bei der Migration der Daten helfen kann. Das Skript wurde erstellt, um bei der Umstellung einiger unserer eigenen Dienste zu helfen, wurde darüber hinaus aber nicht umfassend getestet. Bitte verwenden Sie es daher mit Vorsicht.
+
+Zunächst wird ein Dump der MySQL-Datenbank benötigt, der mit `mysqldump` erstellt werden kann
+```
+mysqldump -u -p > seek.sql
+```
+Kopieren Sie sowohl `seek.sql` als auch das Verzeichnis `filestore/` in ein separates Verzeichnis, z. B.:
+```bash
+mkdir /tmp/seek-migration
+cp -rf filestore/ /tmp/seek-migration/
+cp seek.sql /tmp/seek-migration/
+```
+Das zu verwendende Skript finden Sie unter https://github.com/nfdi4health/ldh/blob/main/script/import-docker-data.sh
+
+Beginnen Sie mit einer sauberen Docker Compose-Einrichtung wie oben beschrieben. Wenn Sie das Skript ausführen und den Speicherort des Verzeichnisses angeben, werden alle vorhandenen Volumes gelöscht, neue Volumes erstellt und mit den Sql- und Dateispeicherdaten gefüllt.
+```bash
+wget https://github.com/seek4science/seek/raw/seek-1.13/script/import-docker-data.sh
+sh ./import-docker-data.sh /tmp/seek-migration/
+```
+## Verwendung einer Sub-URI
+
+Wenn Sie SEEK unter einer Sub-URI (z. B. https://yourdomain.com/seek/) ausführen möchten, können Sie die alternative Datei `docker-compose-relative-root.yml` verwenden:
+```bash
+docker-compose -f docker-compose-relative-root.yml up -d
+```
+Um die Sub-URI (standardmäßig `/seek`) anzupassen, ändern Sie die Variable `RAILS_RELATIVE_URL_ROOT` in dieser Datei in den Abschnitten seek und seek_workers.
+
+Bitte beachten Sie, dass Sie beim Hinzufügen/Ändern/Entfernen der `RAILS_RELATIVE_URL_ROOT` in einem bestehenden Container die Assets neu kompilieren und den Cache löschen müssen:
+```bash
+docker exec seek bundle exec rake assets:precompile
+docker exec seek bundle exec rake tmp:clear
+```
diff --git a/docs/AdminGuide/index.md b/docs/AdminGuide/index.md
new file mode 100755
index 0000000000..0d072dcfe5
--- /dev/null
+++ b/docs/AdminGuide/index.md
@@ -0,0 +1,13 @@
+NFDI4Health Local Data Hub
+Admin Guide
+Dieses Handbuch richtet sich an Administratoren, die eine LDH-Instanz warten und betreiben. Alle in diesem Handbuch beschriebenen regelmäßigen Wartungsarbeiten können über die LAP-Webschnittstelle durchgeführt werden.
+
+## Einrichten
+- [LDH Einrichtung mittels Docker Skript](deployment.md)
+- [LDH als Entwicklungssystem](install_dev.md)
+- [LDH in einer Produktivumgebung](install_prod.md)
+- [Verwendung in Docker](dockercomp.md)
+- [Solr einrichten](solr.md)
+
+## Verwalten
+-
\ No newline at end of file
diff --git a/docs/AdminGuide/install_dev.md b/docs/AdminGuide/install_dev.md
new file mode 100644
index 0000000000..fb1f32b9b9
--- /dev/null
+++ b/docs/AdminGuide/install_dev.md
@@ -0,0 +1,183 @@
+# Installation Local Data Hub
+## Einführung
+Diese Schritte beschreiben, wie Sie den LDH direkt auf dem Rechner (Bare-Metal) installieren.
+
+Für die Installation und Ausführung mit Docker, die in vielen Fällen einfacher und schneller ist, lesen Sie bitte die Anleitung zu [Docker Compose](./dockercomp.md).
+
+LDH basiert auf der Ruby on Rails Plattform. Obwohl die Informationen auf dieser Seite Sie mit allem versorgen sollten, was Sie brauchen, um eine Basisinstallation von LDH zum Laufen zu bringen, wäre etwas Hintergrundlektüre zu Ruby on Rails von Vorteil, wenn es für Sie neu ist. Dokumentation und Ressourcen, die Ruby on Rails beschreiben, finden Sie in der [Ruby Dokumentation][ruby-dok].
+
+LDH baut auf Rails auf und benötigt Ruby 2.8.
+
+Wir empfehlen Ihnen, LDH auf einem Linux-System auszuführen. Diese Anleitung basiert auf einem Ubuntu (20.04 LTS) System. Wenn Sie LDH jedoch auf anderen Linux-Distributionen ausführen, besteht der Hauptunterschied in den Namen der erforderlichen Pakete, die für die jeweilige Distribution installiert werden müssen, ansonsten sind die Schritte identisch. Wenn Sie auf einer anderen Distribution oder Version installieren möchten, besuchen Sie bitte die Seite Andere Distributionen und sehen Sie nach, ob sie dort aufgeführt ist.
+
+Sie benötigen sudo-Rechte auf dem Rechner, auf dem Sie LDH installieren, oder Sie müssen sich als root anmelden können. Außerdem benötigen Sie während des gesamten Installationsvorgangs eine aktive Internetverbindung.
+
+Obwohl es möglich ist, ist die Installation und Ausführung von Ruby on Rails auf einem Windows-System mühsam und wird hier nicht behandelt. Um den LDH trotzdem auf einem Windowssystem lauffähig zu bekommen, weisen wir auf die Verwendung von **Windows-Subsystem für Linux** (WSL) hin.
+
+## Installieren von Paketen
+
+Dies sind die Pakete, die benötigt werden, um den LDH mit Ubuntu 20.04 (Desktop oder Server) zu betreiben. Für andere Distributionen oder Versionen besuchen Sie bitte unsere Hinweise zu anderen Distributionen.
+
+Fügen Sie zunächst ein Repository hinzu, das Python-Versionen enthält, die möglicherweise nicht in den Standard-Repositories verfügbar sind
+
+```bash
+sudo apt install software-properties-common
+sudo add-apt-repository ppa:deadsnakes/ppa
+```
+Dann stellen Sie sicher, dass alles auf dem neuesten Stand ist.
+```bash
+sudo apt update
+sudo apt upgrade
+```
+Installieren Sie nun die Pakete:
+```bash
+sudo apt install build-essential cmake git graphviz imagemagick libcurl4-gnutls-dev libgmp-dev \
+ libmagick++-dev libmysqlclient-dev libpq-dev libreadline-dev libreoffice libssl-dev \
+ libxml++2.6-dev libxslt1-dev mysql-server nodejs openjdk-11-jdk openssh-server poppler-utils zip \
+ python3.7-dev python3.7-distutils python3-pip
+```
+Wenn Sie diese Pakete jetzt installieren, wird die Installation von Ruby später einfacher:
+```bash
+sudo apt install autoconf automake bison curl gawk libffi-dev libgdbm-dev \
+ libncurses5-dev libsqlite3-dev libyaml-dev sqlite3
+```
+Die Solr-Implementierung von den LDH erfordert derzeit Java 11, daher müssen Sie möglicherweise die Standard-Java-Laufzeitumgebung des Systems ändern:
+```bash
+sudo update-alternatives --config java
+```
+...und wählen Sie die Version namens `/usr/lib/jvm/java-11-openjdk-amd64/bin/java` oder ähnlich.
+
+## Entwicklung oder Produktion?
+
+Die folgenden Schritte sind sowohl für die Einrichtung von den LDH für die Entwicklung als auch für eine Produktionsumgebung geeignet. Bei der Einrichtung einer Produktionsumgebung gibt es jedoch einige kleine Unterschiede - siehe [Installation von LDH in einer Produktionsumgebung](./install_prod.md)
+## LDH installieren
+
+Jetzt sind Sie bereit für die Installation von den LDH. Sie können entweder direkt von Github installieren oder die Dateien herunterladen. Sie können den LDH auch von Docker aus starten
+### Direkt von Github installieren
+
+Wenn Sie den LDH direkt von GitHub installieren möchten, ist die neueste Version von den LDH als (v1.13.4) gekennzeichnet. Um diese zu holen, führen Sie aus:
+
+```bash
+git clone https://github.com/nfdi4health/ldh.git
+cd ldh/
+```
+
+## Einrichten von Ruby und RubyGems mit RVM
+
+Wir empfehlen Ihnen dringend, RVM für die Verwaltung Ihrer Ruby- und RubyGems-Version zu verwenden. Sie können zwar die Version verwenden, die mit Ihrer Linux-Distribution geliefert wird, aber es ist schwieriger, die verwendete Version zu kontrollieren und auf dem neuesten Stand zu halten.
+
+Um RVM unter Ubuntu zu installieren, gibt es ein Paket, das unter https://github.com/rvm/ubuntu_rvm beschrieben ist.
+```bash
+sudo apt-add-repository -y ppa:rael-gc/rvm
+sudo apt-get update
+sudo apt-get install rvm
+sudo usermod -a -G rvm $USER
+```
+... die Anleitung empfiehlt hier einen Neustart, aber ein erneutes Ein- und Ausloggen funktioniert normalerweise.
+
+Andere Möglichkeiten, RVM zu installieren, finden Sie unter https://rvm.io/rvm/install.
+
+Installieren Sie nun die entsprechende Version von Ruby
+```bash
+rvm install $(cat .ruby-version)
+```
+
+## Installation von Gems
+
+Installieren Sie zunächst Bundler, das zur Verwaltung von Gem-Versionen dient
+```
+gem install bundler
+```
+Als nächstes installieren Sie die Ruby-Gems, die den LDH benötigt (für die Produktion siehe Bundler-Konfiguration)
+```
+bundle installieren
+```
+## Python-Abhängigkeiten installieren
+
+Zuerst muss eine bestimmte Version von setuptools installiert werden, um ein Problem bei der Installation von Abhängigkeiten zu vermeiden
+```
+python3.7 -m pip install setuptools==58
+```
+Dann können die anderen Abhängigkeiten installiert werden
+```
+python3.7 -m pip install -r requirements.txt
+```
+## Einrichten der Datenbank
+
+Zuerst müssen Sie die Datenbankkonfigurationsdatei einrichten. Kopieren Sie eine Standardversion dieser Datei und bearbeiten Sie sie dann:
+```bash
+cp config/database.default.yml config/database.yml
+nano config/database.yml
+```
+WICHTIG: Sie sollten zumindest den Standardbenutzernamen und das Standardpasswort ändern. Ändern Sie dies für jede Umgebung (Entwicklung, Produktion, Test).
+
+Nun müssen Sie die Berechtigungen für den soeben verwendeten Benutzer und das Passwort vergeben (ändern Sie das Beispiel unten entsprechend).
+```bash
+> sudo mysql
+Enter password:
+Welcome to the MySQL monitor. Commands end with ; or \g.
+Your MySQL connection id is 1522
+Server version: 5.5.32-0ubuntu0.12.04.1 (Ubuntu)
+
+Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
+
+mysql> CREATE USER 'mysqluser'@'localhost' IDENTIFIED BY 'mysqlpassword';
+mysql> GRANT ALL PRIVILEGES ON *.* TO 'mysqluser'@'localhost' WITH GRANT OPTION;
+```
+Um nun die Datenbank für den LDH zu erstellen und mit den Standarddaten zu versehen, führen Sie aus:
+```
+bundle exec rake db:setup
+```
+Sie können nun den LDH zum ersten Mal starten, um zu testen, ob alles funktioniert
+```
+bundle exec rails server
+```
+... und besuchen Sie http://localhost:3000 und eine den LDH-Seite sollte geladen werden.
+
+Bevor Sie jedoch fortfahren, beenden Sie den LDH mit STRG+C und starten Sie einige Dienste.
+
+## Starten der den LDH-Dienste
+
+Hier wird beschrieben, wie Sie die Dienste, die den LDH benötigt, schnell in Betrieb nehmen können. Wenn Sie einen Produktionsserver einrichten, können Sie mit diesen Schritten überprüfen, ob die Dinge funktionieren. Sie sollten jedoch auch die Anleitung Installation für die Produktion lesen, um diese Dienste zu automatisieren.
+### Einrichten und Starten des Suchdienstes
+
+Der LDH verwendet die Apache Solr Suchmaschine, die seit der LDH v1.12 separat eingerichtet werden muss. Dies ist relativ einfach und es gibt eine Anleitung dazu in Solr einrichten.
+### Starten und Stoppen des Hintergrunddienstes
+
+den LDH verwendet Delayed Job, um verschiedene asynchrone Aufträge zu verarbeiten. Es ist wichtig, dass dieser Dienst läuft.
+
+Um Delayed Job zu starten, führen Sie aus:
+```
+bundle exec rake den LDH:workers:start
+```
+und zum Beenden führen Sie aus:
+```
+bundle exec rake den LDH:workers:stop
+```
+Sie können auch neu starten mit
+```
+bundle exec rake den LDH:workers:restart
+```
+
+## den LDH starten
+Sie können nun den LDH erneut starten:
+```
+bundle exec rails server
+```
+
+### Einen Administrator anlegen
+
+Wenn Sie den LDH zum ersten Mal unter http://localhost:3000 besuchen und keine Benutzer vorhanden sind, werden Sie aufgefordert, einen neuen Benutzer anzulegen. Dieser Benutzer wird der Administrator von den LDH sein (Sie können in Zukunft andere Benutzer anlegen oder hinzufügen). Legen Sie einen Benutzernamen und ein Passwort an, füllen Sie Ihr Profil aus und schon können Sie den LDH nutzen.
+
+Sie werden aufgefordert, unser sehr kurzes Registrierungsformular auszufüllen. **Bitte tun Sie dies, falls Sie es noch nicht getan haben**, da dies für die zukünftige Unterstützung und Finanzierung von den LDH sehr hilfreich ist.
+
+### Letzte Schritte
+
+Wenn Sie den LDH für den produktiven Einsatz einrichten, gehen Sie bitte zurück zu unserem Leitfaden den LDH für die Produktion installieren.
+
+Sie sollten jetzt auch unseren Administrationsleitfaden lesen, in dem einige grundlegende Aufgaben und Einstellungen beschrieben sind.
+
+
+
+[ruby-dok]:[https://guides.rubyonrails.org/]
+[dockercomp]:[dockercomp.md]
diff --git a/docs/AdminGuide/install_prod.md b/docs/AdminGuide/install_prod.md
new file mode 100644
index 0000000000..1f3691154a
--- /dev/null
+++ b/docs/AdminGuide/install_prod.md
@@ -0,0 +1,155 @@
+# Installation von LDH in einer Produktionsumgebung
+
+Diese Seite enthält einige zusätzliche Hinweise zur Einrichtung von SEEK für die Produktion (d.h. für den realen Einsatz und nicht für die Entwicklung).
+
+Wenn Sie diese zusätzlichen Hinweise lesen und befolgen, werden Sie mehr Leistung aus SEEK herausholen und die laufende Wartung reduzieren.
+
+Wenn Sie SEEK unter einer Sub-URI laufen lassen wollen, z.B. example.com/seek, dann lesen und befolgen Sie bitte Installieren unter einer Sub-URI am Ende der Installation.
+## Bevor Sie SEEK installieren
+
+Dadurch wird sichergestellt, dass einige der Rake-Aufgaben die entsprechende Datenbank betreffen.
+
+Um später Zeit zu sparen, sind auch einige zusätzliche Pakete zu installieren:
+```bash
+sudo apt-get install libapr1-dev libaprutil1-dev
+```
+Legen Sie zunächst einen Benutzer an, dem die SEEK-Anwendung gehört:
+```bash
+sudo useradd -m seek
+```
+Wir empfehlen, SEEK in /srv/rails/seek zu installieren - zuerst müssen Sie dieses Verzeichnis erstellen und seek die entsprechenden Rechte erteilen
+```bash
+sudo mkdir -p /srv/rails
+sudo chown seek:seek /srv/rails
+```
+Wechseln Sie nun zum Benutzer seek
+```bash
+sudo su - seek
+cd /srv/rails
+```
+Bevor Sie der Standardinstallations-Anleitung folgen, müssen Sie eine Umgebungsvariable setzen, die anzeigt, dass Sie SEEK als Produktionssystem einrichten und ausführen wollen.
+```bash
+export RAILS_ENV=production
+```
+Sie müssen diese Variable zurücksetzen, wenn Sie Ihre Shell schließen und eine neue Sitzung starten.
+
+Sie können nun der allgemeinen Installationsanleitung folgen und dann zu dieser Seite zurückkehren, um einige zusätzliche Schritte auszuführen, damit SEEK zusammen mit Apache läuft und auch die erforderlichen Dienste automatisiert werden.
+
+Wenn Sie Probleme mit der Anforderung eines sudo-Passworts während der RVM-Schritte haben - richten Sie RVM und ruby-1.9.3 zunächst als Benutzer mit sudo-Zugang ein und wiederholen Sie die Schritte als seek-Benutzer. Das bedeutet, dass die benötigten Pakete dann installiert sein sollten. Zum Zeitpunkt der Erstellung dieser Anleitung sollte dies nicht notwendig sein.
+
+## Bundler-Konfiguration
+
+Wenn Sie Gems mit Bundler installieren, konfigurieren Sie zunächst mit
+```bash
+bundle config set deployment 'true'
+bundle config set ohne 'development test'
+```
+Dies verhindert, dass Edelsteine versehentlich geändert werden und vermeidet auch, dass unnötige Edelsteine installiert werden.
+
+# Nachdem Sie SEEK installiert haben
+## Kompilieren von Assets
+
+Assets - wie Bilder, Javascript und Stylesheets - müssen vorkompiliert werden, d. h. sie werden verkleinert, in einer einzigen Datei zusammengefasst und komprimiert. Diese werden dann in public/assets abgelegt. Um sie zu kompilieren, führen Sie den folgenden Befehl aus. Dies kann einige Zeit in Anspruch nehmen, haben Sie also Geduld
+```bash
+bundle exec rake assets:precompile
+```
+## Bedienung von SEEK durch Apache
+
+Zuerst müssen Sie [Passenger Phusion](https://www.phusionpassenger.com/library/install/apache/install/oss/bionic/) einrichten.
+### Passenger installieren
+
+Die folgenden Schritte sind der obigen Anleitung entnommen:
+
+Installieren Sie den PGP-Schlüssel:
+```bash
+sudo apt-get install -y dirmngr gnupg
+sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 561F9B9CAC40B2F7
+sudo apt-get install -y apt-transport-https ca-certificates
+```
+apt-Repository hinzufügen:
+```bash
+sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger bionic main > /etc/apt/sources.list.d/passenger.list'
+sudo apt-get update
+```
+Installieren Sie das Apache-Modul:
+```bash
+sudo apt-get install -y libapache2-mod-passenger
+```
+Aktivieren Sie das Modul:
+```bash
+sudo a2enmod passenger
+sudo apache2ctl restart
+```
+Überprüfen Sie, ob alles funktioniert:
+```bash
+sudo /usr/bin/passenger-config validate-install
+```
+## Apache-Konfiguration
+
+Erstellen Sie nun eine Definition des virtuellen Hosts für SEEK:
+```bash
+sudo nano /etc/apache2/sites-available/seek.conf
+```
+die wie folgt aussieht (wenn Sie einen DNS für Ihre Site registriert haben, setzen Sie ServerName entsprechend):
+```bash
+
+ ServerName www.yourhost.com
+
+ PassengerRuby /usr/local/rvm/rubies/seek/bin/ruby
+
+ DocumentRoot /srv/rails/seek/public
+
+ # This relaxes Apache security settings.
+ Allow from all
+ # MultiViews must be turned off.
+ Options -MultiViews
+ Require all granted
+
+
+ Header unset ETag
+ FileETag None
+ # RFC says only cache for 1 year
+ ExpiresActive On
+ ExpiresDefault "access plus 1 year"
+
+
+```
+(Beachten Sie, dass wir in der PassengerRuby-Direktive auf unseren Alias "seek" verweisen).
+
+Der LocationMatch-Block weist den Apache an, die Assets (Bilder, CSS, Javascript) mit einer langen Verfallszeit auszuliefern, was zu einer besseren Leistung führt, da diese Elemente im Cache gespeichert werden. Möglicherweise müssen Sie die Module headers und expires für Apache aktivieren:
+```bash
+sudo a2enmod headers
+sudo a2enmod expires
+```
+Aktivieren Sie nun die SEEK-Site und deaktivieren Sie den Standard, der mit Apache installiert ist, und starten Sie neu:
+```bash
+sudo a2ensite seek
+sudo a2dissite 000-default
+sudo service apache2 restart
+```
+Wenn Sie nun http://localhost besuchen (beachten Sie, dass es keinen 3000er Port gibt), sollten Sie SEEK sehen.
+
+Wenn Sie SEEK neu starten wollen, vielleicht nach einem Upgrade, ohne Apache neu zu starten, können Sie dies tun, indem Sie (als Benutzer seek)
+```bash
+touch /srv/rails/seek/tmp/restart.txt
+```
+
+## Konfigurieren für HTTPS
+
+Wir empfehlen dringend die Verwendung von [Lets Encrypt](https://letsencrypt.org/) für kostenlose SSL-Zertifikate.
+## Einrichten der Dienste
+
+Die folgenden Schritte zeigen, wie Sie delayed_job und soffice so einrichten, dass sie als Dienst laufen und automatisch gestartet und heruntergefahren werden, wenn Sie den Server neu starten. Apache Solr sollte bereits eingerichtet sein, wenn Sie den Anweisungen zur [Einrichtung von Solr](./solr.md) folgen.
+### Delayed Job Hintergrunddienst
+
+Erstellen Sie die Datei /etc/init.d/delayed_job-seek und kopieren Sie den Inhalt von `scripts/delayed_job-seek` in diese Datei.
+
+Ausführen:
+```bash
+sudo chmod +x /etc/init.d/delayed_job-seek
+sudo update-rc.d delayed_job-seek Voreinstellungen
+```
+Starten Sie es mit:
+```bash
+sudo /etc/init.d/delayed_job-seek start
+```
\ No newline at end of file
diff --git a/docs/AdminGuide/otherdistro.md b/docs/AdminGuide/otherdistro.md
new file mode 100644
index 0000000000..996efc5307
--- /dev/null
+++ b/docs/AdminGuide/otherdistro.md
@@ -0,0 +1,317 @@
+# Anleitung für andere Distributionen
+- [Linux](#installation-von-seek-für-andere-linux-distributionen)
+ - [Linux Mint 18](#linux-mint-18)
+ - [Fedora 20 / RHEL / CentOS](#fedora-20--rhel--centos)
+ - [Pakete](#pakete)
+ - [Installieren von RVM](#installieren-von-rvm)
+ - [Einrichten der Datenbank](#einrichten-der-datenbank)
+ - [Einrichten für die Produktion mit Passenger Phusion](#einrichten-für-die-produktion-mit-passenger-phusion)
+ -
+ - [Ubuntu 20.04 (LTS)](#ubuntu-2004-lts)
+ - [Debian](#debian)
+- [Mac OS](#installation-von-seek-für-mac-os-x)
+ - [Catalina](#catalina)
+ - [Installieren der Pakete](#installieren-der-pakete)
+ - [Einrichten von MySQL](#einrichten-von-mysql)
+ - [PostGres Gem installieren](#postgres-gem-installieren)
+ - [Puma Gem installieren](#puma-gem-installieren)
+ - [Andere Hinweise](#andere-hinweise)
+ - [Verbindung zu MySQL von einem Client aus](#verbindung-zu-mysql-von-einem-client-aus)
+
+
+
+
+# Installation von SEEK für andere Linux-Distributionen
+
+Unsere [Installationsanleitung](./install_dev.md) basiert auf der Ubuntu 20.04 (LTS) Distribution und Version. Abgesehen von den Distributionspaketen sollte der Installationsprozess für andere Distributionen jedoch sehr ähnlich sein.
+
+Für einige andere gängige Distributionen beschreiben wir hier die erforderlichen Distributionspakete und alle anderen Unterschiede zu unserer allgemeinen Installationsanleitung, die uns bekannt sind.
+## Linux Mint 18
+---
+Sobald SEEK installiert ist und läuft, sollte es keine Probleme mehr geben. Der einzige Unterschied, den wir festgestellt haben, ist, dass MySql bei der Installation der Pakete nicht nach einem Root-Passwort fragt. Um sich zunächst mit mysql zu verbinden, um die Berechtigungen einzurichten, müssen Sie möglicherweise Folgendes tun:
+```bash
+sudo mysql -u root
+```
+## Fedora 20 / RHEL / CentOS
+---
+Diese Installation wurde mit Fedora 20 durchgeführt, gilt aber höchstwahrscheinlich auch für Red Hat Enterprise Linux, CentOS und andere Red Hat-basierte Linux-Distributionen oder ist ein guter Ausgangspunkt dafür.
+
+Vielen Dank an Jay Moore für sein Feedback zu seinen eigenen Erfahrungen bei der Installation von SEEK unter RHEL.
+### Pakete
+
+Die Paketnamen sind für Red Hat recht unterschiedlich und werden mit Yum installiert. Die Pakete, die Sie installieren müssen, sind
+```bash
+sudo yum install mysql-server
+```
+Damit wird zwar MariaDB installiert, aber das ist kompatibel und kein Problem. Der Rest der Pakete (einschließlich der Pakete für die Ausführung von SEEK mit Apache) wird wie folgt installiert
+```bash
+sudo yum groupinstall "Development Tools" "Development Libraries"
+sudo yum install wget curl mercurial ruby openssl-devel openssh-server git readline-devel
+sudo yum install libxml2-devel libxml++-devel java-1.7.0-openjdk-devel sqlite-devel
+sudo yum install poppler-utils libreoffice mysql-devel mysql-libs ImageMagick-c++-devel libxslt-devel
+sudo yum install libtool gawk libyaml-devel autoconf gdbm-devel ncurses-devel automake bison libffi-devel
+sudo yum install httpd-itk httpd-devel
+```
+### Installieren von RVM
+
+Installieren Sie wie gewohnt nach der [Installationsanleitung](./install_dev.md), aber achten Sie besonders auf Meldungen über die Aktualisierung Ihres `.profile?` oder `.bash_profile`.
+### Installation von Gems
+
+Wie bei Linux Mint und Ubuntu 14.04 sollten Sie den folgenden Befehl ausführen, bevor Sie bundle install starten, um sicherzustellen, dass `Nokogiri` mit der installierten Version von `LibXML` kompiliert wird.
+```bash
+bundle config build.nokogiri --use-system-libraries
+```
+### Einrichten der Datenbank
+
+Fedora installiert `MariaDB` anstelle von Mysql. Möglicherweise müssen Sie die Datenbank mit starten:
+```bash
+sudo service mariadb start
+```
+Um sie beim Booten zu starten (bei mir war dies nicht standardmäßig aktiviert), sollten Sie Folgendes ausführen:
+```bash
+sudo chkconfig mariadb on
+```
+Um sich mit der Datenbank zu verbinden und den Benutzer für SEEK einzurichten, führen Sie aus:
+```bash
+sudo mariadb
+```
+Ansonsten bleibt alles beim Alten.
+### Einrichten für die Produktion mit Passenger Phusion
+
+Um `Apache` zu starten und zu stoppen, müssen Sie
+```bash
+sudo apachectl start
+sudo apachectl stop
+```
+Wie auch bei MariaDB ist es nicht so konfiguriert, dass es beim Booten startet, um dies zu beheben, führen Sie folgende Kommandos aus:
+```bash
+sudo apachectl stop
+sudo usermod -d /home/apache apache
+sudo usermod -s /bin/bash apache
+sudo mkdir /home/apache
+sudo chown apache /home/apache
+sudo apachectl start
+```
+und verwenden Sie statt www-data den folgenden Befehl, um zu diesem Benutzer zu wechseln:
+```bash
+sudo su - apache
+```
+und fahren Sie dann mit der normalen Installation fort, zusammen mit den oben beschriebenen Unterschieden bei der Installation der Edelsteine und der Einrichtung der Datenbank, bis Sie zur Installation und Einrichtung von Passenger Phusion kommen.
+
+Bevor ich das Passenger-Modul erstelle, muss ich zunächst die folgende Variable setzen, um sicherzustellen, dass es mit einer 64bit-Architektur erstellt wurde
+```bash
+export ARCHFLAGS="-arch x86_64"
+```
+und führen Sie dann Folgendes aus
+```bash
+bundle exec passenger-install-apache2-module
+```
+Ich erhielt einige Warnungen, dass FORTIFY_SOURCE eine Kompilierung mit Optimierung erfordert, die ich ignorierte und die keine Probleme zu verursachen schienen.
+
+Am Ende des Kompilierens und Einrichtens von Passenger Phusion werden einige Details über die Konfiguration angezeigt, die auf Apache angewendet werden soll. Diese sollte auf eine Konfigurationsdatei in `/etc/httpd/conf.d/` angewendet werden. Ich habe z.B. eine Datei /etc/httpd/conf.d/seek.conf verwendet. Sie sollten auch die anderen conf-Dateien entfernen, die dort standardmäßig abgelegt sind. Der Inhalt dieser Datei sah am Ende wie folgt aus, wobei sich Ihre Version leicht unterscheiden kann.
+```bash
+LoadModule passenger_module "/home/apache/.rvm/gems/ruby-2.1.2@seek/gems/passenger-4.0.45/buildout/apache2/mod_passenger.so"
+
+ PassengerRoot /home/apache/.rvm/gems/ruby-2.1.2@seek/gems/passenger-4.0.45
+ PassengerDefaultRuby /home/apache/.rvm/gems/ruby-2.1.2@seek/wrappers/ruby
+
+
+
+ # !!! Be sure to point DocumentRoot to 'public'!
+ DocumentRoot /srv/rails/seek/public
+
+ # This relaxes Apache security settings.
+ AllowOverride all
+ # MultiViews must be turned off.
+ Options -MultiViews
+ # Uncomment this if you're on Apache >= 2.4:
+ Require all granted
+
+
+```
+Danach sollte der Apache neu gestartet werden mit
+```bash
+sudo apachectl restart
+```
+Nun stieß ich beim Laden des Moduls auf einen Berechtigungsfehler, der mit SELinux zusammenhing. Um dies zu umgehen, deaktivierte ich SELinux mit
+```bash
+sudo setenforce 0
+```
+Unter http://sergiy.kyrylkov.name/2012/02/26/phusion-passenger-with-apache-on-rhel-6-centos-6-sl-6-with-selinux wird beschrieben, wie man SELinux wieder aktivieren kann, aber wir haben es nicht geschafft, dies zu erreichen.
+
+Wenn Sie eine Lösung haben, wie Sie SELinux wieder aktivieren können, kontaktieren Sie uns bitte. Einzelheiten zur Kontaktaufnahme mit uns finden Sie unter http://seek4science.org/contact.
+
+## Ubuntu 20.04 (LTS)
+---
+Die allgemeinen Pakete:
+```bash
+sudo apt-get install wget curl mercurial ruby rdoc ri libopenssl-ruby ruby-dev mysql-server libssl-dev build-essential openssh-server git-core
+sudo apt-get install libmysqlclient16-dev libmagick++-dev libxslt-dev libxml++2.6-dev openjdk-6-jdk libsqlite3-dev sqlite3
+sudo apt-get install poppler-utils openoffice.org openoffice.org-java-common
+```
+Um zu vermeiden, dass Sie während der Installation von Ruby 1.9.3 mit RVM dazu aufgefordert werden:
+```bash
+sudo apt-get install libreadline6-dev libyaml-dev autoconf libgdbm-dev libncurses5-dev automake bison libffi-dev
+```
+So installieren Sie das Passenger Phusion-Modul, um SEEK mit Apache auszuführen:
+```bash
+sudo apt-get install apache2-mpm-prefork apache2-prefork-dev libapr1-dev libaprutil1-dev libcurl4-openssl-dev
+```
+Der Befehl zum Starten von soffice ist ebenfalls etwas anders, da er nur einfache statt doppelte Bindestriche für die Argumente verwendet:
+```bash
+soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard > /dev/null 2>&1 &
+```
+Wenn Sie feststellen, dass die Konvertierung von Dokumenten in das PDF-Format (für die Anzeige von Inhalten im Browser) langsam ist, können Sie ein aktuelleres LibreOffice 3.5 aus einem separaten Repository installieren - dies kann jedoch zukünftige Betriebssystem-Upgrades beeinträchtigen:
+```bash
+sudo apt-get purge openoffice* libreoffice*
+sudo apt-get install python-software-properties
+sudo add-apt-repository ppa:libreoffice/libreoffice-3-5
+sudo apt-get update
+sudo apt-get install libreoffice
+```
+## Debian
+---
+Standardmäßig wird der Benutzer, den Sie während der Installation für Debian anlegen, nicht zur Liste der sudoers hinzugefügt. Sie können Ihren Benutzer zur sudo-Gruppe hinzufügen, z.B.
+```bash
+adduser sudo
+```
+Weitere Details finden Sie unter https://wiki.debian.org/sudo.
+
+Alternativ können Sie bei der Installation Befehle, die mit sudo beginnen, als root-Benutzer ausführen.
+
+Die erforderlichen Paketnamen sind die gleichen wie bei Ubuntu 12.04 - folgen Sie also einfach der Installationsanleitung.
+
+Wenn Sie Probleme mit der Verwendung von rvm haben, müssen Sie Ihr Terminal möglicherweise so konfigurieren, dass Befehle als Login-Shell ausgeführt werden. Es gibt ein Kontrollkästchen, das Sie unter dem Menü Bearbeiten, Profileinstellungen und dann unter der Registerkarte Titel und Befehl finden können.
+
+# Installation von SEEK für Mac OS X
+
+Obwohl Sie Seek unter Mac OS ausführen können, könnten Sie auf zufällige Probleme stoßen und müssen verschiedene Anpassungen vornehmen, von denen einige unten aufgeführt sind. Einige Versionen verschiedener Ruby Gems sind nicht voll funktionsfähig oder können unter Mac OS nicht installiert werden. Es wird daher dringend empfohlen, Seek in einer virtuellen Maschine zu installieren, vorzugsweise unter Ubuntu.
+## Catalina
+---
+Dieser Abschnitt führt Sie durch die Installation der vorausgesetzten Pakete, für weitere Schritte lesen Sie bitte die Hauptinstallationsanleitung
+
+Zunächst müssen Sie Fink und MacPorts installieren, zwei Paketverwaltungsprogramme für Mac OS X. Die meisten Pakete werden von Fink installiert, während einige von MacPorts installiert werden. Folgen Sie diesem Link, um Fink zu installieren: http://www.finkproject.org/download/index.php?phpLang=en und für MacPorts: https://www.macports.org/install.php
+### Installieren der Pakete
+```bash
+sudo fink install wget curl openssl100-dev git readline6
+sudo fink install libxml++2 sqlite3-dev sqlite3
+sudo fink install poppler-bin mysql-unified-dev
+
+sudo port install mysql8-server
+sudo port install openssh ImageMagick libxslt
+```
+Für die folgenden Pakete müssen Sie das dmg-Image herunterladen und manuell installieren:
+```bash
+Libreoffice (alternatives Open Office): http://www.libreoffice.org/download
+Java JDK: http://www.oracle.com/technetwork/java/javase/downloads/index.html oder https://jdk.java.net/ (openjdk)
+PostGres: https://www.postgresql.org/download/macosx/
+Node.js: https://nodejs.org/en/download/
+```
+### Einrichten von MySQL
+---
+https://trac.macports.org/wiki/howto/MySQL
+
+Wichtige Schritte nach der Installation:
+
+Wählen Sie mysql8 beim Standard-Mysql aus:
+```bash
+sudo port select mysql mysql8
+```
+Starten Sie den Server:
+```bash
+sudo port load mysql8-server
+```
+Initialisieren Sie die Datenbank.
+
+Dabei erhalten Sie ein temporäres Root-Passwort. Sie müssen es aufschreiben, da es später (sehr) schwierig sein wird, es zurückzusetzen. Bei der ersten tatsächlichen Verwendung von mysql (mit dem Befehl mysql) müssen Sie das Root-Passwort ändern (siehe unten).
+```bash
+sudo /opt/local/lib/mysql8/bin/mysqld --initialize --user=_mysql
+```
+Erster Start von mysql:
+```bash
+mysql -uroot -p # angegebenes Passwort verwenden
+```
+Sie können nichts tun, bevor Sie ein neues Passwort für root eingerichtet haben:
+```bash
+ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpassword';
+```
+MySql hat standardmäßig eine neue Authentifizierungsmethode. Um sicherzustellen, dass Seek sich damit verbinden kann, müssen Sie angeben, dass der Seek-DB-Benutzer (festgelegt in Database.yml) die alte "native password"-Methode verwenden kann:
+```bash
+ALTER USER 'ldhmainuser'@'localhost' IDENTIFIED WITH mysql_native_password
+```
+Dann aktivieren Sie die neuen Privilegien:
+```bash
+flush privileges;
+```
+### PostGres Gem installieren
+---
+Um die PostGres-Unterstützung mit Gem zu installieren, wird der Pfad zu den Binärdateien benötigt:
+```bash
+sudo PATH=$PATH:/Library/PostgreSQL/x.y/bin gem install pg
+```
+für PostGres 10 wäre es zum Beispiel:
+```bash
+sudo PATH=$PATH:/Library/PostgreSQL/10/bin gem install pg
+```
+### Puma Gem installieren
+---
+Puma braucht eine Option, um mit dem neuen Xcode zu kompilieren:
+```bash
+gem install puma:4.3.5 -- --with-cflags="-Wno-error=implicit-function-declaration"
+```
+### Andere Hinweise
+---
+Standardmäßig verbindet sich der mysql-Client mit dem mysql-Server über einen Socket unter `/tmp/mysql.sock`. Möglicherweise installieren Sie jedoch standardmäßig die .sock-Datei unter `/opt/local/var/run/mysql8/mysqld.sock`. Daher muss die .sock-Datei in database.yml neu konfiguriert werden
+```bash
+socket: /opt/local/var/run/mysql8/mysqld.sock
+```
+Und auch wenn Sie den mysql-Client ausführen wollen, müssen Sie den Pfad der .sock-Datei unter der Option -S
+
+Möglicherweise müssen Sie den Installationsort von Libreoffice angeben, bevor Sie den Befehl soffice ausführen. Sie können z.B. folgende Zeile in `~/.bashrc` einfügen
+```bash
+export PATH="$PATH:/Programme/LibreOffice.app/Inhalte/MacOS/"
+```
+### Verbindung zu MySQL von einem Client aus
+---
+MacPorts deaktiviert standardmäßig vollständig entfernte Verbindungen, die für die meisten SQL-Clients erforderlich sind. Um sie zu aktivieren, können Sie die my.cnf bearbeiten:
+```bash
+sudo vim /opt/local/etc/mysql8/my.cnf
+```
+```bash
+# MacPorts-Standardeinstellungen verwenden
+# !include /opt/local/etc/mysql8/macports-default.cnf
+
+[client]
+port = 3306
+socket = /opt/local/var/run/mysql8/mysqld.sock
+default-character-set = utf8
+
+[mysqld_safe]
+socket = /opt/local/var/run/mysql8/mysqld.sock
+nice = 0
+default-character-set = utf8
+
+[mysqld]
+basedir="/opt/local"
+socket = /opt/local/var/run/mysql8/mysqld.sock
+port = 3306
+bind-address = 127.0.0.1
+skip-external-locking
+#skip-networking
+character-set-server = utf8
+
+[mysqldump]
+default-character-set = utf8
+```
+Starten Sie dann MySQL neu (möglicherweise müssen Sie den Prozess beenden):
+```bash
+sudo port unload mysql8-server
+
+ps -ax | grep mysql -> wenn mysqld noch da ist, verwenden Sie die aufgelistete PID:
+
+sudo kill PID
+```
+dann
+```bash
+sudo port load mysql8-server
+```
\ No newline at end of file
diff --git a/docs/AdminGuide/solr.md b/docs/AdminGuide/solr.md
new file mode 100644
index 0000000000..a572e1ebac
--- /dev/null
+++ b/docs/AdminGuide/solr.md
@@ -0,0 +1,75 @@
+# Einrichten der Apache Solr Suchmaschine
+
+Seit Version 1.12 von FAIRDOM-SEEK muss [Apache Solr](https://solr.apache.org/) nun separat eingerichtet werden, anstatt die integrierte `Sunspot Solr` zu verwenden.
+
+Diese Anleitung bezieht sich nur auf Bare-Metal-Installationen von FAIRDOM-SEEK. Er betrifft nicht die Verwendung einer [Docker](dockercomp.md)-basierten Installation, bei der die Änderungen bereits für Sie erledigt sind.
+
+Es gibt zwei Alternativen zur Installation und Ausführung von Apache Solr. Wenn möglich, ist es am einfachsten, unser Docker-Image zu verwenden. Falls dies nicht möglich ist, finden Sie weiter unten auch einige Anweisungen zur direkten Installation von Apache Solr.
+
+## Verwendung des Docker-Images
+
+Die Verwendung von Docker ist die einfachste Lösung, um Solr, vorkonfiguriert für SEEK, mit demselben fairdom/seek-solr:8.11-Image auszuführen, das wir mit Docker compose verwenden.
+
+Sie müssen zunächst [Docker installieren](https://docs.docker.com/engine/install/). Wir stellen Beispielskripte zum Einrichten und Starten sowie zum Beenden des Solr-Dienstes zur Verfügung:
+
+- `script/start-docker-solr.sh`
+ - Bei der ersten Ausführung wird das Image geholt, ein Volume erstellt, um die indizierten Daten zu speichern, und der Dienst gestartet. Er ist so eingestellt, dass er automatisch neu startet, wenn er nicht explizit gestoppt wird. Bei weiteren Ausführen wird der Dienst neu gestartet.
+- `skript/stop-docker-solr.sh`
+ - Wie bereits angedeutet, wird der Dienst damit gestoppt. Der Container und das Volume bleiben erhalten und können neu gestartet werden.
+
+Diese Skripte sollten aus dem Stammverzeichnis Ihrer SEEK-Installation ausgeführt werden, z. B:
+```bash
+sh ./script/start-docker-solr.sh
+```
+Der Docker-Container erhält den Namen seek-solr und das Volume den Namen seek-solr-data-volume .
+
+Sobald er läuft und die Suche aktiviert ist, können Sie Jobs auslösen, um alle durchsuchbaren Inhalte neu zu indizieren mit
+```bash
+bundle exec rake seek:reindex_all
+```
+Es gibt ein zusätzliches Skript, script/delete-docker-solr.sh, das verwendet werden kann, um sowohl den Container als auch das Volume zu löschen.
+
+## Installation von Apache Solr
+
+Im Folgenden werden die Schritte zur Installation und Einrichtung von Solr unter Ubuntu 20.04 beschrieben, aber der Prozess sollte für alle Debian-basierten Distributionen gleich und für andere sehr ähnlich sein. Er basiert auf der Anleitung auf https://tecadmin.net/install-apache-solr-on-ubuntu-20-04/, aber die folgenden Schritte wurden für Solr 8.11.1 aktualisiert.
+
+Zuerst sollten Sie sicherstellen, dass Java 11 installiert ist. OpenJDK ist in Ordnung
+```bash
+sudo apt update
+sudo apt install openjdk-11-jdk
+```
+Überprüfen Sie dies mit
+```bash
+java -version
+```
+Wenn eine andere Version angezeigt wird, verwenden Sie den folgenden Befehl und wählen Sie die Nummer für die richtige Version
+```bash
+sudo update-alternatives --config java
+```
+Der nächste Schritt ist das Herunterladen und Installieren von Solr in /opt/ und das Einrichten als Dienst
+```bash
+cd /opt
+sudo wget https://downloads.apache.org/lucene/solr/8.11.1/solr-8.11.1.tgz
+sudo tar xzf solr-8.11.1.tgz solr-8.11.1/bin/install_solr_service.sh --strip-components=2
+sudo bash ./install_solr_service.sh solr-8.11.1.tgz
+```
+Die Dienste können auf die übliche Weise gestoppt und gestartet werden mit
+```bash
+sudo dienst solr stop
+sudo dienst solr start
+```
+Nun müssen Sie den für SEEK konfigurierten Kern einrichten. Wechseln Sie in das Stammverzeichnis der SEEK-Installation (in diesem Beispiel /srv/rails/seek)
+```bash
+cd /srv/rails/seek
+sudo su - solr -c "/opt/solr/bin/solr create -c seek -d $(pwd)/solr/seek/conf"
+```
+
+Die Konfiguration und die Daten für den SEEK-Kern befinden sich in `/var/solr/data/seek`.
+
+Sie sollten in der Lage sein, zu bestätigen, dass der Dienst läuft und der Kern eingerichtet ist, indem Sie http://localhost:8983/solr besuchen.
+
+Solr ist nun eingerichtet, und Sie können Aufträge zur Neuindizierung des Inhalts mit
+```bash
+bundle exec rake seek:reindex_all
+```
+
diff --git a/docs/ISA_bestpractices.md b/docs/ISA_bestpractices.md
new file mode 100755
index 0000000000..9318206ed3
--- /dev/null
+++ b/docs/ISA_bestpractices.md
@@ -0,0 +1,111 @@
+# Kurzanleitung Eingabe SEEK
+## Allgemeine Strukturierung in SEEK
+### Übersicht der Ressourcen
+![ISA Seek Struktur](./images/BestPractice/seekStruct.png)
+### Mögliche Vernetzungen
+[//]:
+
+||Programme|Project|Investigation|Study|Assay|Publication|Data|Document|
+|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
+|**Programme**|-|n (ed)|||||||
+|**Project**|1 (mg)|-|||||||
+|**Investigation**||n (mg)|-|||n (ed)|||
+|**Study**|||1 (ed)|-||n (ed)|||
+|**Assay**||||1 (ed)|-|1 (ed)|1 (ed)|1 (ed)|
+|**Publication**||1 (ed)|1 (ed)|1 (ed)|1 (ed)|-|1 (ed)||
+|**Data**|||||||-||
+|**Document**||n (mg)|||n (ed)|||-|
+
+*Beispiel: Eine Investigation kann n (also vielen) Projekte zugewiesen werden. Immer über „Edit“ (=ed), "Manage" (=mg)*
+## Beispiel: Eingabe der Studie ABC
+
+Idee: Sponsor./Programme ist UL. Die Projektebene bündelt alle Personen des Forschungsvorhaben (PI und alle die auch Zugriff bekommen sollen). U.U. gilt diese für mehrere Vorhaben.
+
+### Ziel
+
+- Programm: University Leipzig (Sponsor)
+ - Project ABC-PI
+ - Investigation ABC
+ - Study ABC-Pilot
+ - Study ABC
+ - Assay: Studienunterlagen
+ - Document: Studienprotokoll
+ - Document: Einwilligung
+ - Assay: Daten (Beschreibung)
+ - Datafile Endpunkte 1
+ - Datafile Tabelle 2
+ - Study ABC-Follow Up
+ - Publikation “Discontinuation…”
+
+In SEEK soll sich für die Investigation folgendes Bild ergeben:
+
+![Seek Tree](./images/BestPractice/studytree.png)
+*Study Tree*
+
+## Klickanleitung
+
+Es gibt viele Wege zum Ziel. Ressourcen können aus anderen Ressourcen heraus oder eben direkt von der Startseite aus angelegt werden.
+
+- Einloggen / Startseite
+- Programm anlegen:
+ - _Create Programm_
+ - Title z.B. „University Leipzig (Sponsor)
+ - Muss, je nach SEEK Konfiguration, genehmigt werden
+- Projekt anlegen:
+ - In der Programm-Ansicht _„Actions/Create Project“_
+ - Muss, je nach SEEK Konfiguration, genehmigt werden“
+ - Hier sollte man dann als „Project administrators“ sichtbar sein
+- Investigation anlegen:
+ - In der Projektansicht “Add new/Add new Investigation”
+ - Bei „Projects“ sollte „ABC-PI“ gewählt sein
+ - Hinweis, wenn die Investigation unsichtbar ist.
+- Study anlegen:
+ - In der Investigationsansicht _„Add new/Add new Study“_
+
+- Assay anlegen:
+ - In der Studyansicht „A Modellling analysis“ (oder oder An Experimental assay“)
+
+- Document anlegen:
+ - In der Assay Ansicht „Add new/Add new Document”
+ - Hier nochmal kontrollieren: Projects “ABC-PI“ auswählen
+ - Z.B. lokale PDF „Datei auswählen“
+
+- DataFile anlgen:
+ - Typisch Local File (Excel) hochladen; alle Angaben füllen, insbesondere Projektassoziation
+- Publication anlegen:
+ - Z.b. von Titelseite „Create Publication”
+ - 3 Möglichkeiten: (von Pubmed, Manuelle Eingabe, aus Literatureintrag)
+ - Best Practice: Eingabe über pubmed-id, z.B. 34540953
+ - Zugehöriges Projekt assoziieren, z.B. „ABC-PI“
+ - „Fetch“ und „Register“
+ - Evtl. Autoren mit SEEK Nutzer assoziieren oder auch, zusätzlich zum Projekt, mit beliebig anderen Ressourcetypen verbinden, z.B. der Investigation „ABC“
+ - Nun erst „Save“
+## Mögliche Ansicht des Ergebnis
+
+- Projektansicht „ABC-PI“
+ - Hier Related Items oder „Single Page”
+- Aus Investigationansicht
+ - Entweder Related Items oder kleine Grafik
+
+ - ![View Investigation](./images/BestPractice/investigation.png)
+
+## Feintuning
+
+- Titel ist Pflicht – aber bitte auch immer Description befüllen!
+- Festlegen der Rechte
+- Best-Practice: Nur Assays evtl. nicht sichtbar; alles andere Public View
+
+## Rechte
+
+- Programme, Projekte und Publikationen sind immer öffentlich sichtbar
+- Test z.B. über Ansicht ohne Anmeldung
+- Investigation, Studies, Assays, Data files, Documents nach Wahl über “Manage <'resource>'” , z.B. ist auch sowas
+
+![hidden tree](./images/BestPractice/studytree_hiddenview.png)
+![rights](./images/BestPractice/view_options.png)
+
+Für nicht autoriserte User sieht dann die Investigation/Related Item so aus:
+
+ ![related Items](./images/BestPractice/RelatedItems.png)
+
+Die “+” steht für “Hidden Items” – man sieht also, dass man nicht alles sieht.
\ No newline at end of file
diff --git a/docs/UserGuide/citationable.md b/docs/UserGuide/citationable.md
new file mode 100644
index 0000000000..f307111189
--- /dev/null
+++ b/docs/UserGuide/citationable.md
@@ -0,0 +1,55 @@
+# Investigation, Studie oder Assay zitierfähig machen
+
+Mit SEEK können Sie Untersuchungen, Studien und Assays veröffentlichen, und zwar vollständig mit der Struktur und den Assets, aus denen sie bestehen. Sie können der Untersuchung dann einem DOI zuweisen, der eine dauerhafte Verknüpfung bietet, mit der Sie und andere sie zitieren können.
+
+Im Folgenden werden die Schritte zur Veröffentlichung einer Untersuchung beschrieben, sie gelten aber auch für Studien und Assays.
+
+- Öffentlich machen
+- Snapshotting
+- Erstellen eines Forschungsobjekts
+- Zuweisen eines DOI
+
+## Öffentlich machen
+
+Um eine Untersuchung zitierfähig zu machen, muss sie zunächst veröffentlicht werden. Um Ihre Untersuchung zu veröffentlichen, navigieren Sie zu Ihrer Untersuchung und klicken Sie auf die Schaltfläche Verwaltung in der oberen rechten Ecke von SEEK. Wählen Sie die Schaltfläche Vollständige Untersuchung veröffentlichen.
+
+Untersuchung 1 veröffentlichen
+
+Die Untersuchung kann einige Studien, Proben und andere Asset-Dateien enthalten, die noch nicht veröffentlicht sind. Sie können die Elemente, die derzeit noch nicht veröffentlicht sind, überprüfen, indem Sie unten links in SEEK auf OK klicken. Sie können diesen Schritt auch überspringen, wenn Sie keine weiteren Elemente veröffentlichen möchten.
+
+Untersuchung veröffentlichen 2
+
+Sie können alle derzeit unveröffentlichten Assets überprüfen und haben die Möglichkeit, sie alle oder einige wenige davon zu veröffentlichen.
+
+Untersuchung 3 veröffentlichen
+
+Sie werden darüber informiert, welche Assets Sie veröffentlichen möchten. Um sie zu veröffentlichen, bestätigen Sie die Änderungen in der unteren linken Ecke von SEEK.
+## Snapshotting
+
+Sobald die Untersuchung (zumindest) öffentlich ist, kann ein Schnappschuss der Untersuchung erstellt werden. Ermittlungen entwickeln sich weiter und verändern ihre Strukturen in SEEK. Ein Schnappschuss ist eine Möglichkeit, eine Version der Untersuchung in ihrem aktuellen Zustand einzufrieren, so dass selbst dann, wenn sich Aspekte der Untersuchung im Laufe der Zeit ändern, auf die eingefrorene Version zugegriffen werden kann.
+
+Um einen Schnappschuss zu erstellen, müssen Sie den Schnappschuss über die Verwaltungsschaltfläche in der oberen rechten Ecke des Untersuchungsbildschirms in SEEK auswählen.
+
+Schnappschuss erstellen 1
+
+Sie erhalten eine Auflistung der Elemente, die in den Schnappschuss aufgenommen und ausgeschlossen werden sollen. Alle nicht-öffentlichen Elemente sind ausgeschlossen. Sie müssen sie öffentlich machen, wenn sie in den Schnappschuss aufgenommen werden sollen. Wenn Sie mit dem Inhalt des Schnappschusses zufrieden sind, können Sie fortfahren, indem Sie unten rechts auf Schnappschuss erstellen klicken.
+
+Schnappschuss erstellen 2
+## Ein Forschungsobjekt erstellen
+
+Nachdem der Schnappschuss erstellt wurde, können Sie den Schnappschuss als Forschungsobjekt herunterladen, indem Sie auf die Schaltfläche "Herunterladen" in der oberen rechten Ecke von SEEK klicken.
+
+Schnappschuss erstellen 1
+## Zuweisung eines DOI
+Nachdem der Schnappschuss erstellt wurde, können Sie dem Schnappschuss einen DOI, einen dauerhaften Bezeichner, zuweisen. Damit können Sie dauerhaft auf den Inhalt des Schnappschusses verweisen, unabhängig davon, ob er an einen anderen Ort verschoben wird. Auf diese Weise kann der Schnappschuss in Veröffentlichungen verwendet werden, um herkömmliches Zusatzmaterial zu ergänzen oder zu ersetzen. Außerdem können Ihre Daten so von anderen Forschern zitiert werden. Sie können einen DOI zuweisen, indem Sie auf die Schaltfläche DOI in der oberen rechten Ecke klicken.
+
+Snapshotting 1
+
+Sobald Sie einen DOI generiert haben, wird der Schnappschuss mit einem DOI-Logo versehen, so dass Sie wissen, um welchen Schnappschuss es sich handelt.
+
+DOI 1
+
+Sie können den DOI-Link auch in den Attributen des Schnappschusses finden
+
+DOI 1
+
diff --git a/docs/UserGuide/contribute_publication.md b/docs/UserGuide/contribute_publication.md
new file mode 100755
index 0000000000..db9325cca1
--- /dev/null
+++ b/docs/UserGuide/contribute_publication.md
@@ -0,0 +1,67 @@
+# Publikation hinzufügen
+
+Um eine Veröffentlichung im LDH zu registrieren, müssen Sie sich bei Ihrem LDH-Konto anmelden. Die Schaltfläche ***"Create+"*** sollte in der Navigationsleiste sichtbar sein. Gehen Sie zu ***" Create+ > Publication"***. Sie gelangen zu einem Bildschirm, auf dem Sie zwischen der Registrierung mit PubMed-ID (PMID), der manuellen Eingabe oder dem Datei-Import wählen können.
+
+## Registrierung mit PubMed-ID
+
+Dies ist die Standardmethode. Sie müssen Folgendes angeben:
+
+- Publikationstyp
+- PubMed-ID
+- Zugehöriges Projekt
+
+Nachdem Sie auf die Schaltfläche ***"Fetch"*** geklickt haben, ruft der LDH die Informationen von PubMed ab. Klicken Sie nun auf die Schaltfläche ***"Register"*** und Ihre Publikation wird registriert. Der nächste Bildschirm führt Sie zur Bearbeitung der Abhängigkeiten der Publikationen. (lesen Sie [hier](#bearbeiten-von-publikationen) mehr)
+
+## Manuelle Registrierung einer Publikation
+
+Die zweite Möglichkeit, eine Publikation zu registrieren, ist die manuelle Registrierung.
+Sie müssen Folgendes angeben:
+
+- ein Projekt
+- Titel
+- Liste der Autoren
+- eine Zusammenfassung
+- eventuelles Journal oder andere Publikationsplattform
+- eventuelle Zitat
+- Veröffentlichungsdatum
+
+Wenn Sie eine DOI-Nummer eingeben, können Sie die entsprechenden Daten abrufen, indem Sie auf die Schaltfläche ***"Crossref"*** klicken. Die abgerufenen Daten werden automatisch ausgefüllt.
+
+Autoren werden durch Eintragen des ersten Buchstabens des Nachnamens des Autors hinzugefügt.
+In der erscheinenden Liste können Sie einen bereits bekannten Autor oder eine registrierte Person auswählen.
+Ein bekannter Autor ist ein Autor, der bereits mit anderen Publikationen in Verbindung gebracht wird, aber nicht als Person im LDH registriert ist.
+
+Wenn der Autor nicht in der Liste enthalten ist, geben Sie den Namen im Publikationsstil ein und klicken Sie auf den Namen unter Neuer Autor.
+Registrierte Autoren werden mit ihren Autorenprofilen verknüpft.
+Nachdem Sie alle relevanten Informationen eingegeben haben, klicken Sie auf die Schaltfläche Erstellen.
+Der nächste Bildschirm führt Sie zur Bearbeitung der Abhängigkeiten der Publikationen. (lesen Sie [hier](#bearbeiten-von-publikationen) mehr)
+
+## Importieren per Datei
+
+Die dritte und letzte Möglichkeit, eine Publikation zu registrieren, besteht darin, eine Bibtex-Datei zu importieren.
+Die Bibtex-Datei sollte einen oder mehrere Einträge von Publikationen enthalten, die zu einem Projekt gehören. Es ist also notwendig, dass Sie für jedes Projekt, das Ihre Publikationen enthält, eine bibtex-Datei bereitstellen.
+
+Nachdem Sie auf die Schaltfläche ***"Import"*** geklickt haben, wird der erste Eintrag importiert, und der Bearbeitungsbildschirm wird angezeigt. (lesen Sie [hier](#bearbeiten-von-publikationen) mehr)
+
+Wenn Sie auf die Schaltfläche Alle importieren klicken, werden alle Einträge importiert und es wird kein Bearbeitungsbildschirm angezeigt.
+Wenn Sie die Publikationen bearbeiten möchten, gehen Sie in Ihrem Konto in der rechten Ecke des Bildschirms auf Meine Artikel.
+
+Dort können Sie den Eintrag, den Sie bearbeiten möchten, aus der Liste auswählen.
+
+Um in den Bearbeitungsmodus zu gelangen, wählen Sie die Schaltfläche ***"Manage Publication"*** unter dem Dropdown-Menü ***"Actions"***.
+
+Der nächste Bildschirm führt Sie zur Bearbeitung der Abhängigkeiten der Publikationen. (lesen Sie [hier](#bearbeiten-von-publikationen) mehr)
+
+## Bearbeiten von Publikationen
+
+Wenn Sie den Bearbeitungsmodus einer bestimmten Veröffentlichung aufrufen (wie in den vorherigen Abschnitten beschrieben), können Sie die Metadaten der Veröffentlichung verwalten.
+
+- Unter ***Project*** können Sie weitere Projekte hinzufügen oder bestehende Beziehungen entfernen.
+- ***Associate authors*** ist eine Liste aller Autoren, die mit der Veröffentlichung in Verbindung stehen. Das Portal schlägt den Autor auf der Grundlage der in der Datenbank registrierten Autoren vor. Wenn es einen falschen oder fehlenden Vorschlag gibt, wählen Sie den richtigen aus, indem Sie die ersten Buchstaben des Nachnamens aus der Liste eingeben.
+- Unter ***Abstract*** können Sie eine kurze Zusammenfassung der wichtigsten Fakten dieser Veröffentlichung schreiben.
+- ***Related links*** gibt einen HTML-Link an, wenn es keinen DOI- oder PubMed-Eintrag gibt.
+
+
+Ereignisse, Investigationen, Studien, Assays, Data-Files, Modelle, Präsentationen und Dokumente können ebenfalls mit den Veröffentlichungen verknüpft werden. Diese Entitäten müssen erstellt werden, bevor auf sie verwiesen werden kann.
+
+
diff --git a/docs/UserGuide/createProject.md b/docs/UserGuide/createProject.md
new file mode 100755
index 0000000000..dd0b7b7c10
--- /dev/null
+++ b/docs/UserGuide/createProject.md
@@ -0,0 +1,53 @@
+# Was ist ein Project
+
+Ein Projekt stellt eine Gruppe von einer oder mehreren Personen dar, die gemeinsam an einer bestimmten Aktivität arbeiten. Das Projekt bietet die Möglichkeit, die Aktivität zu beschreiben und zu fördern und dem Team Anerkennung zukommen zu lassen. Das Projekt hat einen Titel, optional eine Beschreibung, eine öffentliche Website und eine Avatar-Grafik. Die Benutzer müssen Mitglied eines Projekts sein, bevor sie Artikel registrieren können, die dann mit diesem Projekt in Verbindung stehen, und ein Benutzer kann unbegrenzt an vielen Projekten teilnehmen.
+
+Ein Projekt bietet nicht nur Anerkennung, sondern auch nützliche Funktionen wie Standardfreigabeberechtigungen und -lizenzen sowie die Möglichkeit, die Freigabeberechtigungen für alle Mitglieder des Projekts einfach festzulegen. Einige Mitglieder des Projekts können spezielle Gatekeeper- und Housekeeper-Rollen innerhalb des Projekts haben - weitere Informationen finden Sie unter [Spezielle Benutzerrollen](roles.md).
+
+Das Projekt hat einen eigenen [Projektadministrator](roles.md#projektadministrator) - normalerweise der Benutzer, der das Projekt ursprünglich beantragt hat. Dieser Benutzer kann nicht nur die Projektdetails bearbeiten, sondern auch Mitglieder hinzufügen und entfernen, ihre Rollen festlegen und zusätzliche Administratoren definieren. Er kann auch neue Institutionen, Profile (zur Beschreibung von Mitgliedern, die sich noch nicht registriert haben) und Organismen definieren.
+
+Ein Mitglied des Projekts ist auch mit einer Institution für den Kontext dieses Projekts verbunden (einige Benutzer können mit verschiedenen Institutionen für verschiedene Projekte verbunden sein).
+
+# Was ist ein Programm?
+
+Wenn es so konfiguriert ist, dass es aktiviert ist, kann LDH auch Programme haben. Programme sind ein Dach, das ein oder mehrere Projekte enthält. Sie sind ein selbstverwalteter Bereich, der eine breit angelegte Aktivität beschreibt (in der Regel im Zusammenhang mit einem finanzierten Zuschuss), z. B. ein Konsortium oder eine lang laufende Aktivität, für die weitere Projekte benötigt werden.
+
+Nach der Genehmigung erhält das Programm einen [Programmadministrator](roles.md#programmadministrator), dem es freisteht, sofort weitere Projekte anzulegen, ohne dass eine weitere Genehmigung erforderlich ist.
+
+Das Programm muss einen Titel haben und kann optional auch eine Beschreibung, Finanzierungsdetails, eine Website und eine Avatar-Grafik haben.
+
+Für Benutzer, die nur ein einzelnes Projekt und kein Programm benötigen, kann ein standortverwaltetes Programm definiert werden (empfohlen), mit dem ihr Projekt verknüpft wird. Sie verwalten dann nur ihr Projekt, ohne sich um Programme kümmern zu müssen. Das Projekt kann später in ein eigenes Programm verschoben werden, falls erforderlich.
+
+# Ein Projekt erstellen
+
+Nach der Registrierung eines neuen LDH-Kontos werden Sie zunächst aufgefordert, ein Projekt zu erstellen (oder einem [Projekt beizutreten](joinProject.md)). Wenn Sie bereits Mitglied sind und weitere Projekte hinzufügen möchten, können Sie über das Menü "Erstellen" in der oberen Leiste ein Projekt erstellen.
+
+## Ein Programm auswählen
+
+Falls aktiviert, muss zuerst ein Programm ausgewählt oder erstellt werden. Falls konfiguriert, haben Sie auch die Möglichkeit, ein standortverwaltetes Programm auszuwählen. Standardmäßig ist das vom Standort verwaltete Programm ausgewählt, aber wenn es nicht markiert ist, gibt es die Möglichkeit, den Titel eines neuen Programms anzugeben. In diesem Stadium ist nur der Titel erforderlich, aber weitere Details können später nach der Erstellung angegeben werden.
+
+![Programm auswählen](../images/UserGuide/)
+
+Wenn Sie bereits bestehende Programme verwalten, wird stattdessen ein Dropdown-Feld angezeigt, aus dem Sie eines Ihrer bestehenden Programme auswählen können. Sie haben auch die Möglichkeit, ein neues Programm zu erstellen.
+
+## Definieren des Projekts
+
+Als nächstes müssen Sie das Projekt definieren. Sie müssen mindestens einen Titel angeben, können aber auch eine Beschreibung und eine Webseite erstellen. Sobald es erstellt ist, können Sie es bearbeiten und zusätzliche Details und Mitglieder hinzufügen.
+
+![Projekt definieren](../images/UserGuide/)
+
+## Definieren Sie Ihre Institution
+
+Wenn das Projekt erstellt wird, werden Sie automatisch zusammen mit dem Administrator Mitglied. Um Mitglied zu werden, müssen Sie auch die Institution (oder Zugehörigkeit) angeben, mit der Sie im Zusammenhang mit diesem Projekt verbunden sind. Es muss nicht dieselbe Institution sein wie bei anderen Projekten, und es ist nicht ungewöhnlich, dass sie unterschiedlich ist.
+
+Beginnen Sie mit der Eingabe des Namens Ihrer Einrichtung, und es werden die vorhandenen Optionen angezeigt, die den von Ihnen eingegebenen Text enthalten (oder mit der Einrichtung in Verbindung stehen, wie z. B. die Stadt). Hoffentlich wird Ihre Einrichtung gefunden und Sie können sie einfach auswählen. Wenn nicht, können Sie die oberste Option wählen, um eine neue Einrichtung zu definieren.
+
+Bei der Beschreibung einer neuen Einrichtung ist nur der Titel erforderlich, aber Sie können auch Angaben zu ihrer Website, ihrer Stadt und ihrem Land machen. Sie können die Angaben auch nachträglich bearbeiten und zusätzliche Informationen hinzufügen.
+
+![Institution definieren](../images/UserGuide/)
+
+## Schritt zur Genehmigung
+
+Wenn Sie ein Projekt innerhalb eines von Ihnen verwalteten Programms erstellen, gibt es keinen Genehmigungsschritt. Es wird eine Seite angezeigt, auf der Sie die Details überprüfen und das Projekt dann sofort erstellen können.
+
+Andernfalls wird ein zuständiger Administrator per E-Mail über Ihren Antrag benachrichtigt. Sie werden auch direkt benachrichtigt, wenn Sie LDH verwenden. Dem Administrator wird eine Seite angezeigt, auf der er die Details schnell überprüfen und die Anfrage entweder annehmen oder ablehnen kann.
\ No newline at end of file
diff --git a/docs/UserGuide/editingProfile.md b/docs/UserGuide/editingProfile.md
new file mode 100755
index 0000000000..d9830f4183
--- /dev/null
+++ b/docs/UserGuide/editingProfile.md
@@ -0,0 +1,37 @@
+# Profil bearbeiten
+
+Um Ihr Profil zu bearbeiten, müssen Sie eingeloggt sein. Wenn Sie eingeloggt sind, können Sie auf Ihren Namen in der oberen rechten Ecke von LDH klicken.
+
+![Profil bearbeiten 1](../images/UserGuide/)
+
+Wählen Sie ***My profile*** aus dem Dropdown-Menü, um in die Profilansicht zu wechseln oder wählen Sie ***Edit profile*** um gleich in den Bearbeitungsmodus zu wechseln.
+
+![Profil bearbeiten 2](../images/UserGuide/)
+
+Haben Sie ***My profile*** gewählt, navigieren Sie folgend zum Button ***Actions*** in der oberen rechten Ecke und wählen dort ***Edit profile*** aus dem Dropdown-Menü
+
+![Profil bearbeiten 3](../images/UserGuide/)
+
+Die Felder, die Sie bearbeiten können, sind überschaubar und umfassen:
+
+- Vorname
+- Nachname
+- ORCID-Kennung
+- Beschreibung
+- Angaben zum Kontakt
+- Wissen und Erfahrung
+- Positionen im Projekt
+- E-Mail-Ankündigungen
+- Abonnements
+
+# Passwort ändern
+Um Ihr Passwort zu ändern, müssen Sie eingeloggt sein. Wenn Sie eingeloggt sind, können Sie auf Ihren Namen in der oberen rechten Ecke von LDH klicken.
+
+![Passwortändern 1](../images/UserGuide/)
+
+Wählen Sie ***My profile*** aus dem Dropdown-Menü, um in die Profilansicht zu wechseln oder wählen Sie ***Change Password*** um gleich in den Bearbeitungsmodus zu wechseln.
+
+Haben Sie ***My profile*** gewählt, navigieren Sie folgend zum Button ***Actions*** in der oberen rechten Ecke und wählen dort ***Manage Account*** aus dem Dropdown-Menü.
+
+In der folgenden Ansicht können Sie Ihre Anmeldedaten bearbeiten.
+
diff --git a/docs/UserGuide/generic_linking_var.md b/docs/UserGuide/generic_linking_var.md
new file mode 100755
index 0000000000..87967114b5
--- /dev/null
+++ b/docs/UserGuide/generic_linking_var.md
@@ -0,0 +1,123 @@
+# Allgemeine Verknüpfungsvariablen in LDH
+
+## Titel
+
+Sie sollten die Titel so beschreibend wie möglich gestalten.
+
+## Beschreibung
+
+Die Beschreibung ermöglicht es Ihnen, wichtige Details weiter auszuführen. Beschreibungen können mit [Markdown](https://www.markdownguide.org/basic-syntax/) formatiert werden, entweder über Markup oder über die verschiedenen Optionen oberhalb der Texteingabe (z.B. fett, kursiv, Hyperlinks...). Markdown-Farbband UI
+
+## Projekte
+
+Assets können über das Dropdown-Menü den Projekten zugewiesen werden, in denen sie erstellt wurden. Projekt hinzufügen 1
+
+Mit der Schaltfläche Entfernen können Sie alle ausgewählten Projekte entfernen. Projekt 2 hinzufügen
+
+## Extended Metadata
+
+
+
+## Details zur Investigation
+
+### Studie
+
+[Assay-spezifisch] Sie können einen Assay mit einer bestimmten Studie innerhalb Ihrer Projekte verknüpfen, indem Sie das Dropdown-Menü verwenden.
+
+### Angesprochenes biologisches Problem
+
+[Assay-spezifisch - Modellierungsanalyse] Sie können über das Dropdown-Menü auswählen, welches biologische Problem mit der Modellierungsanalyse behandelt wird. Sie können auch Ihre eigene Modellierungsanalyse hinzufügen, indem Sie die Schaltfläche "Neuer Modellierungsanalysetyp" verwenden.
+
+Angesprochenes biologisches Problem 1
+### Assay-Typ
+
+[Assay-spezifisch - Experimentalassay] Sie können einen Assay-Typ aus dem Dropdown-Menü auswählen oder ggf. einen neuen Assay-Typ über die Schaltfläche "Neuer Assay-Typ" erstellen.
+
+Assay-Typ 1
+
+### Technologie-Typ
+
+[Assay-spezifisch - Experimentalassay] Sie können einen Technologietyp aus dem Dropdown-Menü auswählen oder ggf. einen neuen Technologietyp über die Schaltfläche "Neuer Technologietyp" erstellen.
+
+Technologietyp 1
+
+### Organismen
+
+[Assay-spezifisch] Sie können einen Organismus aus dem Dropdown-Menü auswählen.
+
+Organismus 1
+
+##
+
+### Freigabe
+
+LDH verfügt über fein abgestufte Freigabeberechtigungen. Sie können wählen, ob Sie ein Asset in LDH nur für sich selbst, für ausgewählte Personen innerhalb und außerhalb von LDH, für Ihr gesamtes Projekt oder für die Öffentlichkeit freigeben möchten.
+
+
+
+### Schlagwörter
+
+Schlagwörter (Tags) sind Schlüsselwörter, die in irgendeiner Weise für das Asset und seine Eigenschaften relevant sind. Sie werden verwendet, damit relevante Assets von anderen Nutzern bei der Suche nach Schlüsselwörtern leichter gefunden werden können. Um ein Schlagwort hinzuzufügen, geben Sie es einfach in das Feld ein. Während der Eingabe werden Vorschläge für Tags in einem Dropdown-Menü angezeigt. Sie können jeden freien Text für Tags verwenden.
+
+Tags hinzufügen 1
+
+### Zuschreibungen
+
+Eine Zuordnung in LDH ermöglicht es Ihnen, gegebenenfalls das Asset auszuwählen, von dem Ihr Asset abgeleitet wurde (in LDH gespeichert). Während Sie die Zuordnung eingeben, werden die zugehörigen Assets in einem Dropdown-Menü angezeigt.
+
+Tags hinzufügen 1
+
+### Creator
+
+Creator sind andere Personen, die an der Erstellung des Assets beteiligt waren, z. B. durch Planung, Experimente oder Analysen. Dabei muss es sich nicht unbedingt um dieselbe Person handeln, die das Element registriert hat - den Mitwirkenden.
+
+Sie können mehrere Creator hinzufügen, entweder einen nach dem anderen. Beginnen Sie mit der Eingabe des Namens und die passenden Einträge werden angezeigt. Drücken Sie ENTER, Komma oder klicken Sie, um die Person hinzuzufügen.
+
+
+
+Im Feld ***"Additional credit"*** können weitere Mitwirkende angegeben werden, welche nicht unter Creators geführt werden sollen. Handelt es sich dabei um mehrere verschiedene Personen, können diese hintereinander, getrennt durch Komma im Freitextfeld aufgelistet werden.
+
+Sie können auch über den Button ***"Add new creator"*** Nicht-LDH-User hinzufügen. Nach klicken erscheint ein kleineres Eingabefenster in dem Vorname und Nachname eingegeben werden müsse. Fakultativ können noch Zugehörigkeit und OrcID angegeben werden.
+
+
+
+## SOPs
+
+[Assay-spezifisch] SOPs sind Standardarbeitsanweisungen, die das für die Durchführung des Assays erforderliche Protokoll beschreiben. Sie können in jedem beliebigen Format vorliegen (Word-Dateien, E-Lab-Notebooks, Code, kommentierte Tabellenkalkulationen usw.). Relevante SOPs können über das Dropdown-Menü direkt mit dem Assay verknüpft werden.
+
+## Data-Files
+
+[Assay-spezifisch] Datendateien können alle Dateien sErstellerLDHein, die für den Assay relevante Daten enthalten (Rohdaten, verarbeitete Daten, Kalibrierungsinformationen usw.). Sie können ein beliebiges Format haben (Word-Dateien, E-Lab-Notebooks, Code, kommentierte Tabellen usw.). Relevante Datendateien können über das Dropdown-Menü direkt mit dem Assay verknüpft werden.
+
+## Platzhalter
+
+[Assay-spezifisch] Ein Platzhalter kennzeichnet Daten, die bei der Durchführung eines Projekts verbraucht, verwendet oder erzeugt werden. Platzhalter werden verwendet, wenn die Struktur eines Projekts definiert ist, die Daten jedoch noch nicht bekannt sind, weil das Projekt noch nicht vollständig abgeschlossen ist. Wenn die Daten bekannt sind, kann die Datendatei mit dem Platzhalter verknüpft werden, den sie erfüllt. Platzhalter können überall verwendet werden, wo eine Datendatei sein kann.
+
+## Dateivorlagen
+
+Eine Dateivorlage beschreibt konforme Datendateien. Sie kann mit Informationen über das Format und den Typ der Daten in den Datendateien versehen werden. Die Anmerkungen beziehen sich nicht auf die Dateivorlage selbst. Zum Beispiel kann eine Dateivorlage, die ein Word-Dokument ist, konforme PNG-Bilder beschreiben.
+
+## Publikationen
+
+Wenn Ihr Asset in direktem Zusammenhang mit einer Publikation steht, können Sie die beiden in LDH miteinander verknüpfen. Sie können Publikationen innerhalb Ihres Projekts aus dem Dropdown-Menü auswählen. Wenn sich die Publikation in einem anderen Projekt befindet, müssen Sie das Kontrollkästchen Publikationen aus anderen Projekten verknüpfen aktivieren.
+
+
+
+Wenn eine Publikation hinzugefügt wird, erscheint in der rechten unteren Ecke von LDH eine Vorschau. Sie kann bei Bedarf einfach wieder durch klicken entfernt werden.
+
+
+## Experimentelle Untersuchungen und Modellierungsanalysen
+
+Es ist am besten, wenn Assets mit Hilfe des ISA-Diagramms kontextualisiert werden. Das bedeutet, dass Assets nach Möglichkeit mit einem Assay oder einer experimentellen Analyse verknüpft werden sollten. Dies kann durch Auswahl eines geeigneten Assays oder einer experimentellen Analyse aus dem Dropdown-Menü erfolgen.
+Nach der Auswahl erscheint auf der rechten Seite von LDH eine Assay-Vorschau. Die Verknüpfung kann leicht vom Asset entfernt werden.
+
+
+## Ereignisse
+
+Wenn das Asset als Teil eines in LDH registrierten Ereignisses erstellt wurde, können Sie das Asset über das Dropdown-Menü mit dem Ereignis verknüpfen.
+
+Ereignis hinzufügen 1
+
+Eine Vorschau des Ereignisses wird auf der rechten Seite von LDH angezeigt, sobald es ausgewählt wurde. Die Verknüpfung kann leicht vom Asset entfernt werden.
+
+Ereignis 2 hinzufügen
diff --git a/docs/UserGuide/index.md b/docs/UserGuide/index.md
new file mode 100755
index 0000000000..7eaf161c3c
--- /dev/null
+++ b/docs/UserGuide/index.md
@@ -0,0 +1,24 @@
+NFDI4Health Local Data Hub
+User Guide
+
+## Inhalt
+### User
+- [Registrierung in SEEK](registry.md)
+- [Profil bearbeiten](editingProfile.md)
+### LDH
+- [Projekt beitreten](joinProject.md)
+- [Projekt erstellen](createProject.md)
+- [ISA Struktur erstellen](isa_struct.md)
+ - [Investigation erstellen](isa_struct.md#erstellen-einer-investigation)
+ - [Studie erstellen](isa_struct.md#eine-studie-erstellen)
+ - [Erstellen eines Assays](isa_struct.md#erstellen-eines-assays)
+ - [Erstellen einer Modellierungsanalyse](isa_struct.md#erstellen-einer-modellierungsanalyse)
+- [ISA Übersicht](isa_overview.md)
+- [Publikation hinzufügen](contribute_publication.md)
+- [Investigation, Studie oder assay zitierfähig machen](citationable.md)
+- [Spezielle Benutzerrollen](roles.md)
+- [Projekt Dashboard](project_dashboard.md)
+
+
+### ISA Nutzung für NFDI4Health
+- [ISA Best Practice](../ISA_bestpractices.md)
diff --git a/docs/UserGuide/isa_overview.md b/docs/UserGuide/isa_overview.md
new file mode 100755
index 0000000000..4e1788ca2c
--- /dev/null
+++ b/docs/UserGuide/isa_overview.md
@@ -0,0 +1,72 @@
+# ISA-Übersicht
+
+## Zusammenfassung
+
+Die ISA-Übersicht ist eine grafische Darstellung des aktuellen Elements in Beziehung zu anderen Elementen innerhalb seiner ISA-Struktur (Untersuchung, Studie, Prüfung).
+
+Sie dient dazu, einen einfachen visuellen Überblick zu geben, und kann auch dazu verwendet werden, zwischen den Elementen in der Ansicht zu navigieren. Durch Doppelklicken auf einen Knoten können Sie direkt zu diesem Element navigieren. Der Titel und die Beschreibung des ausgewählten Elements werden oben angezeigt; langer Text kann vollständig angezeigt werden, wenn Sie mit der Maus über den Text fahren.
+
+Die Übersicht bietet auch die Möglichkeit, das Layout zu ändern und ein Bild für Präsentationen und Berichte zu exportieren.
+
+## Legende der Icons
+
+Um die Identifizierung der ISA-Elemente zu erleichtern, finden Sie im Folgenden eine Zusammenfassung der verwendeten Symbole.
+
+|Icon|Bezeichnung|
+|:---:|:---:|
+|![](../../app/assets/images/avatars/avatar-programme.png)|Programm|
+|![](../../app/assets/images/avatars/avatar-project.png)| Projekt|
+|![](../../app/assets/images/avatars/avatar-institution.png)| Institution|
+|![](../../app/assets/images/avatars/avatar-investigation.png)|Investigation|
+|![](../../app/assets/images/avatars/avatar-study.png)| Studie|
+|![](../../app/assets/images/avatars/avatar-assay.png)|Assay|
+|![](../../app/assets/images/avatars/avatar-model-analysis.png)|Modellanalyse|
+|![](../../app/assets/images/avatars/avatar-model.png)| Model|
+|![](../../app/assets/images/avatars/avatar-publication.png)|Publikation|
+|![](../../app/assets/images/avatars/avatar-event.png)|Ereignis/Veranstaltung|
+
+
+SOPs, Data-Filesn, Dokumente und Präsentationen haben Symbole, die ihrem Dateityp entsprechen.
+
+## Baum-Ansicht (Tree)
+
+
+
+Die Baumansicht ist die Standardansicht und zeigt die ISA-Struktur in Form von Ordnern an, ähnlich wie ein Dateibrowser. Zu Beginn werden das aktuelle Element und alle darunter liegenden Elemente aufgeklappt dargestellt, während andere Elemente eingeklappt sind. Die eingeklappten Elemente können durch Anklicken aufgeklappt werden. Die Elemente, die unter dem aktuell angezeigten Element liegen, werden ebenfalls mit einem schwachen blauen Hintergrund hervorgehoben.
+
+Wenn Sie z. B. eine Studie anzeigen, wird diese Studie erweitert angezeigt, während die Geschwisterstudien eingeklappt dargestellt werden.
+
+
+
+
+Wenn Elemente mehr als ein übergeordnetes Element haben, z. B. eine Datendatei, die mit mehr als einem Assay verbunden ist, wird sie unter jedem dieser Elemente angezeigt.
+
+Sie können zu einem Element in der Strukturansicht springen, indem Sie darauf doppelklicken.
+
+Eine Vollbildansicht der Struktur kann durch Umschalten auf die Schaltfläche ***"Fullscreen"*** (Vollbild) angezeigt werden und kann durch erneutes Klicken oder Drücken der ESC-Taste wiederhergestellt werden.
+
+## Grafische Ansicht (Graph)
+
+Die grafische Ansicht kann durch Klicken auf die Schaltfläche ***"Graph"*** oben rechts angezeigt werden. Dies zeigt eine grafische Ansicht, in der das Element innerhalb des Netzwerks hervorgehoben wird. Standardmäßig werden nur die unmittelbaren Nachbarn vollständig angezeigt, während andere Knoten kleiner sind. Unmittelbare Verbindungen werden ebenfalls hervorgehoben. Dies trägt dazu bei, die Übersichtlichkeit komplexer Diagramme zu verringern und eine unmittelbare visuelle Vorstellung von der Position des aktuellen Elements im Netzwerk zu erhalten.
+
+
+
+Sie können mit dem Diagramm interagieren, indem Sie auf einzelne Knoten klicken, die sich dann zusammen mit ihren nächsten Nachbarn vergrößern. Der Titel und die Beschreibung des ausgewählten Elements werden ebenfalls am oberen Rand aktualisiert.
+
+Wenn Sie möchten, dass alle Knoten vollständig angezeigt werden, können Sie dies über die Schaltfläche ***"All nodes"*** umschalten.
+
+
+
+
+
+Sie können das Diagramm mit der Maus verschieben und mit den Bedienelementen oben links vergrößern und verkleinern. Einzelne Knoten können auch gezogen und neu positioniert werden.
+
+Wie bei der Strukturansicht können Sie auch hier den Vollbildmodus einschalten. Im Vollbildmodus können Sie mit dem Mausrad hinein- und herauszoomen.
+
+Um das Diagramm als PNG-Bild zu exportieren, klicken Sie auf die Schaltfläche mit dem Bildsymbol oben rechts. Daraufhin wird ein Bild des aktuellen Stands des Diagramms angezeigt, das heruntergeladen werden kann. Das Bild hat eine höhere Auflösung, vor allem, wenn es im Vollbildmodus exportiert wird.
+
+## Geteilte Ansicht (Split)
+
+
+
+Die geteilte Ansicht ist eine Kombination aus Baum- und Diagrammansicht, wobei der Baum auf der rechten Seite angezeigt wird. Wenn Sie also auf einen Baumknoten klicken, wird dieser auch im Diagramm hervorgehoben, und wenn Sie auf das Diagramm klicken, wird der Baumknoten ausgewählt und bei Bedarf erweitert. Die geteilte Ansicht funktioniert am besten, wenn sie als Vollbild angezeigt wird.
\ No newline at end of file
diff --git a/docs/UserGuide/isa_struct.md b/docs/UserGuide/isa_struct.md
new file mode 100755
index 0000000000..89d1e03e26
--- /dev/null
+++ b/docs/UserGuide/isa_struct.md
@@ -0,0 +1,62 @@
+# Generierung der ISA-Struktur
+
+Die ISA-Struktur (Investigation, Study, Assay) ist ein allgemeiner Rahmen, um zu beschreiben, wie Experimente miteinander in Beziehung stehen.
+
+## Erstellen einer Investigation
+
+Die Investigation ist ein übergeordnetes Konzept, das verwandte Studien miteinander verbindet. Um eine Investigation zu erstellen, wählen Sie Investigation aus dem Erstellungsmenü am oberen Rand des LAP.
+Eine Investigation wird mit Hilfe der folgenden Felder beschrieben und verknüpft:
+
+- [Titel](generic_linking_var.md#titel)
+- [Beschreibung](generic_linking_var.md#beschreibung)
+- [Creator ](generic_linking_var.md#creator)
+- [Freigabe ](generic_linking_var.md#freigabe)
+- [Publikationen](generic_linking_var.md#publikationen)
+
+## Eine Studie erstellen
+
+Eine Studie ist eine bestimmte biologische Hypothese oder Analyse. Mehrere Studien können mit einer Investigation verbunden werden. Um eine Studie zu erstellen, wählen Sie Studie aus dem Erstellungsmenü oben in der LDH.
+Eine Studie wird mit Hilfe der folgenden Felder beschrieben und verknüpft:
+- [Titel](generic_linking_var.md#titel)
+- [Beschreibung](generic_linking_var.md#beschreibung)
+- [Creator ](generic_linking_var.md#creator)
+- [Investigationsdetails](generic_linking_var.md#details-zur-investigation)
+- [Gemeinsame Nutzung](generic_linking_var.md#freigabe)
+- [Creator ](generic_linking_var.md#creator)
+- [Publikationen](generic_linking_var.md#publikationen)
+
+## Erstellen eines Assays
+
+Ein Assay ist im Allgemeinen ein Experiment, das entweder ein Material oder eine Datenprobe über ein Protokoll in ein neues Material oder eine neue Datenprobe umwandelt. Mehrere Versuche können mit einer Studie verbunden werden.
+
+Versuchsversuche beziehen sich speziell auf Laborversuche. Sie können eine experimentelle Prüfung erstellen, indem Sie im Menü "Erstellen" oben in der LAP die Option "Prüfung" auswählen. Sie können dann einen Assay-Typ auswählen. Wählen Sie Experimenteller Assay.
+Ein experimenteller Assay wird mit den folgenden Feldern beschrieben und verknüpft:
+- [Titel](generic_linking_var.md#titel)
+- [Beschreibung](generic_linking_var.md#beschreibung)
+- [Studie](generic_linking_var.md#studie)
+- [Assay-Typ](generic_linking_var.md#assay-typ)
+- [Technologie-Typ](generic_linking_var.md#technologie-typ)
+- [Creator ](generic_linking_var.md#creator)
+- [Gemeinsame Nutzung](generic_linking_var.md#freigabe)
+- [Schlagwörter](generic_linking_var.md#schlagwörter)
+- [SOPs](generic_linking_var.md#sops)
+- [Data File](generic_linking_var.md#data-files)
+- [Publikationen](generic_linking_var.md#publikationen)
+
+### Erstellen einer Modellierungsanalyse
+
+Ein Assay ist im Allgemeinen ein Experiment, das entweder ein Material oder eine Datenprobe über ein Protokoll in ein neues Material oder eine neue Datenprobe umwandelt. Mehrere Assays können mit einer Studie verbunden werden.
+
+Modellierungsanalysen beziehen sich speziell auf Simulationen (In-Silico-Experimente) von Modellen. Sie können eine Modellierungsanalyse durchführen, indem Sie im Menü "Erstellen" oben in der LAP die Option "Assay" auswählen. Sie können dann einen Assay-Typ auswählen. Wählen Sie Modellierungsanalyse.
+
+Ein Modellierungsversuch wird durch die folgenden Felder beschrieben und verknüpft:
+- [Titel](generic_linking_var.md#titel)
+- [Beschreibung](generic_linking_var.md#beschreibung)
+- [Studie](generic_linking_var.md#studie)
+- [Angesprochenes biologisches Problem](generic_linking_var.md#angesprochenes-biologisches-problem)
+- [Creator ](generic_linking_var.md#creator)
+- [Gemeinsame Nutzung](generic_linking_var.md#freigabe)
+- [Schlagwörter](generic_linking_var.md#schlagwörter)
+- [SOPs](generic_linking_var.md#sops)
+- [Data File](generic_linking_var.md#data-files)
+- [Publikationen](generic_linking_var.md#publikationen)
\ No newline at end of file
diff --git a/docs/UserGuide/joinProject.md b/docs/UserGuide/joinProject.md
new file mode 100755
index 0000000000..d31ceae5d1
--- /dev/null
+++ b/docs/UserGuide/joinProject.md
@@ -0,0 +1,34 @@
+# Projekt beitreten
+
+Sie werden aufgefordert, einem Projekt beizutreten, wenn Sie sich zum ersten Mal registrieren und noch nicht Mitglied eines Projekts sind.
+
+Sie können den Beitritt zu einem Projekt auch auf der Projektseite selbst beantragen. Navigieren Sie dazu zunächst zu der Projektseite. Solange das Projekt einen Administrator hat und Sie noch kein Mitglied sind, sollte eine Schaltfläche "Mitgliedschaft beantragen" verfügbar sein:
+
+
+
+Es ist nur möglich, alle 12 Stunden eine Anfrage an dasselbe Projekt zu stellen.
+
+## Projekt auswählen
+Wenn Sie diese Seite aufrufen, nachdem Sie auf der Projektseite einen Antrag auf Beitritt gestellt haben, ist das Projekt bereits ausgewählt:
+
+![Request Project2](../images/UserGuide/)
+
+Wenn Sie die Seite direkt aufgerufen haben, z. B. nach der Registrierung, müssen Sie das Projekt auswählen, dem Sie beitreten möchten.
+
+Dazu geben Sie den Namen des Projekts in das Feld ein, woraufhin Vorschläge angezeigt werden. Die Vorschläge ergeben sich aus der Übereinstimmung des eingegebenen Namens mit dem Projekttitel oder einem Teil der Beschreibung. Sie können bis zu 3 auf einmal auswählen. Wenn Sie das gewünschte Projekt nicht finden können, können Sie die gesamte Liste durchsuchen und filtern und dann wie oben beschrieben auf der Seite Projekte einen Antrag auf Beitritt stellen.
+
+## Definieren Sie Ihre Institution
+
+Wenn Sie dem Projekt beitreten, werden Sie mit einer Institution (oder einem Verband) verbunden. Diese müssen Sie bei der Antragstellung angeben. Es steht Ihnen frei, sich für verschiedene Projekte einer anderen Einrichtung zuzuordnen, falls erforderlich.
+
+Beginnen Sie mit der Eingabe des Namens Ihrer Einrichtung, und es werden die vorhandenen Optionen angezeigt, die den von Ihnen eingegebenen Text enthalten (oder mit der Einrichtung in Verbindung stehen, wie z. B. die Stadt). Hoffentlich wird Ihre Einrichtung gefunden und Sie können sie einfach auswählen. Falls nicht, können Sie die oberste Option wählen, um eine neue Institution zu definieren.
+
+Bei der Beschreibung einer neuen Einrichtung ist nur der Titel erforderlich, aber Sie können auch Angaben zu ihrer Website, ihrer Stadt und ihrem Land machen. Sie können die Angaben auch nachträglich bearbeiten und zusätzliche Informationen hinzufügen.
+
+Institution definieren
+## Einen Kommentar abgeben
+
+Sie haben auch die Möglichkeit, einen Kommentar abzugeben, um zu beschreiben, warum Sie dem Projekt beitreten möchten. Dies ist besonders wichtig, wenn Sie dem Projektadministrator noch nicht bekannt sind.
+## Schritt zur Genehmigung
+
+Ihr Antrag wird an die Projektadministratoren geschickt, entweder per E-Mail oder durch eine Benachrichtigung in FAIRDOM-SEEK. Sie werden dann entweder genehmigt und dem Projekt hinzugefügt oder Ihr Antrag wird abgelehnt. In jedem Fall werden Sie per E-Mail über das Ergebnis informiert.
\ No newline at end of file
diff --git a/docs/UserGuide/project_dashboard.md b/docs/UserGuide/project_dashboard.md
new file mode 100644
index 0000000000..1845d383aa
--- /dev/null
+++ b/docs/UserGuide/project_dashboard.md
@@ -0,0 +1,32 @@
+# Projekt-Dashboard
+
+Die Seite "Projekt-Dashboard" enthält verschiedene Diagramme, die Metriken zu den Aktivitäten innerhalb des Projekts über einen bestimmten Zeitraum darstellen.
+
+Dashboard-Schaltfläche
+## Zugriff auf das Dashboard
+
+Das Dashboard ist für alle Projektmitglieder über eine Schaltfläche auf der Seite des Projekts zugänglich.
+
+Dashboard-Schaltfläche
+## Einreichungen
+
+Das Diagramm der Einreichungen zeigt alle Projektelemente an, die in einem bestimmten Zeitraum erstellt wurden. Das Intervall kann geändert werden, um die Ergebnisse nach Tag, Monat oder Jahr zu gruppieren. Asset-Typen können aus dem Diagramm ausgeschlossen werden, indem Sie auf ihren Eintrag in der Legende auf der rechten Seite klicken. Ein Doppelklick auf einen Anlagentyp blendet alle Anlagentypen außer diesem aus.
+
+Beiträge zum Dashboard
+## Asset-Zugänglichkeit
+
+Das Kuchendiagramm zur Asset-Zugänglichkeit zeigt die Zugänglichkeit von Assets an, die im betreffenden Zeitraum erstellt wurden. Über die Dropdown-Liste "Typ" können Sie optional nach einem bestimmten Asset-Typ filtern.
+
+Die drei Ebenen der Zugänglichkeit sind:
+
+- Veröffentlicht - Assets, auf die jeder, der SEEK besucht, zugreifen (und gegebenenfalls herunterladen) kann.
+- Projekt zugänglich - Assets, auf die Mitglieder dieses Projekts zugreifen (und ggf. herunterladen) können.
+- Andere - Assets, die privat sind oder auf die nur begrenzt zugegriffen werden kann.
+
+Dashboard Zugänglichkeit
+## Meist angesehene und heruntergeladene Assets
+
+Die Panels für die am häufigsten angesehenen/heruntergeladenen Assets zeigen einfache "Top 10"-Listen von Assets nach der Anzahl der Aufrufe/Downloads in einem bestimmten Zeitraum. Sie können auch nach Typ gefiltert werden.
+## Aktivste Einreicher
+
+Der Bereich "Aktivste Einreicher" zeigt die 10 Personen mit der höchsten Anzahl von Einreichungen im Projekt während des Zeitraums. Das Erstellen eines SEEK-Assets zählt als eine Einreichung.
\ No newline at end of file
diff --git a/docs/UserGuide/registry.md b/docs/UserGuide/registry.md
new file mode 100755
index 0000000000..d21561a4b0
--- /dev/null
+++ b/docs/UserGuide/registry.md
@@ -0,0 +1,32 @@
+# Registrierung in SEEK
+
+Um sich im NFDI4Health Local Data Hub (LDH) zu registrieren, müssen Sie auf die Schaltfläche **"Registrer"** in der oberen rechten Ecke klicken.
+
+![Register 1](../images/UserGuide/)
+*Registrierung 1*
+
+Sie werden zu einem Bildschirm weitergeleitet, auf dem Sie Folgendes angeben müssen
+
+- Einen Login-Namen (kann Ihr richtiger Name oder ein anderer geeigneter Name sein)
+- Eine E-Mail Adresse
+- Ein Passwort für Ihr Konto.
+
+Wenn Sie fertig sind, klicken Sie auf die Schaltfläche Registrieren in der linken unteren Ecke.
+
+![Register 2](../images/UserGuide/)
+*Registrierung 2*
+
+Sie werden dann zu einem Bildschirm weitergeleitet, auf dem Sie weitere Informationen eingeben müssen. Wir benötigen die folgenden Informationen:
+- Vorname
+- Nachname
+- Ihre E-Mail-Adresse, die automatisch aus dem vorherigen Bildschirm übernommen werden sollte.
+- ORCID ID - wenn Sie noch keine ORCID haben, müssen Sie sich unter [OrcID.org](http://orcid.org/) registrieren lassen.
+
+Obligatorische Angaben sind mit einem roten Sternchen gekennzeichnet. Nachdem Sie den Rest Ihrer Daten eingegeben haben, müssen Sie bei den meisten Installationen von LDH Ihr Konto aktivieren. Sie erhalten dann eine E-Mail an das von Ihnen angegebene E-Mail-Konto.
+
+Anmeldung 4
+
+Nachdem Sie Ihr Konto aktiviert und sich eingeloggt haben, müssen Sie entweder ein Projekt erstellen oder einem Projekt beitreten, bevor Sie Inhalte registrieren können. Weitere Informationen finden Sie unter:
+
+- [Einem bestehenden Projekt beitreten](joinProject.md)
+- [Erstellen Sie ein neues Projekt](createProject.md)
\ No newline at end of file
diff --git a/docs/UserGuide/roles.md b/docs/UserGuide/roles.md
new file mode 100755
index 0000000000..219d4910af
--- /dev/null
+++ b/docs/UserGuide/roles.md
@@ -0,0 +1,66 @@
+# Spezielle Benutzerrollen
+
+LDH verfügt über eine Reihe von speziellen Rollen, die den Benutzern zugewiesen werden können
+
+Programmspezifische Rollen:
+
+- [Programmadministratoren](#programmadministrator)
+
+Projektspezifische Rollen:
+
+- [Asset housekeeper](#asset-housekeeper)
+- [Asset gatekeeper](#asset-gatekeeper)
+- [Projektadministrator](#programmadministrator)
+
+Im Folgenden finden Sie eine Zusammenfassung der Fähigkeiten der einzelnen Rollen.
+|| **Project admin**| **Asset Housekeeper** | **Asset Gatekeeper** | **Normal User** |
+|---|:---:|:---:|:---:|:---:|
+| **Notified of new project member**|X||||
+| **manage project meta data details (that they are a member of)**|X|X|X|X|
+| **Authenticate, authorise, assign, remove and mark as left users to projects** |X|||||
+| **Authorise request to make project specific asset(s) public access**|||X|
+| **Manage project specific assets of users thatr have left the project**||X|||
+| **Create new assets**|X|X|X|X|
+| **Create new profiles**|X||||
+| **Create and edit new institutions**|X||||
+| **Create new organisms**|X||||
+| **Edit profiles**|X||||
+| **Change login details**||||X|
+
+## Programmadministrator
+
+Ein Programmadministrator ist für ein ganzes Programm zuständig. Er hat die Möglichkeit, seinem Programm andere Programmadministrator zuzuweisen, kann sich aber nicht selbst entfernen. Um sich selbst zu entfernen, muss er zunächst einen anderen Verwalter zuweisen und diesen bitten, dies für ihn zu tun, um zu verhindern, dass ein Programm versehentlich ohne einen Verwalter ist. Jeder andere LDH-Benutzer kann zum Programmadministrator ernannt werden.
+
+Ein Programmadministrator hat auch die Möglichkeit, Projekte zu erstellen, die dann automatisch seinem Programm zugewiesen werden. Sie werden zwar nicht automatisch zum [Projektadministrator](#programmadministrator) oder Mitglied dieses Projekts, aber es besteht die Möglichkeit, dies zu tun, indem Sie die Institution auswählen.
+
+Um ein Projekt zu erstellen, wählen Sie das Menü Erstellen oben auf der Seite. Ihr Programm muss zuvor angenommen und aktiviert worden sein. Wenn Sie ein Projekt erstellt haben, können Sie auch ein Logo oder ein Bild einfügen, indem Sie auf Bild ändern unter dem Bild auf der rechten Seite der Projektseite klicken. Ein Programmadministrator verfügt auch über einige der Fähigkeiten eines [Projektadministrators](#programmadministrator):
+
+- Hinzufügen und Entfernen von Personen aus einem Projekt
+- Profile erstellen
+- Institutionen erstellen
+
+## Asset-Housekeeper
+
+Der Asset Housekeeper hat die besondere Fähigkeit, Assets zu verwalten, die anderen Personen im Projekt gehören - aber nur Personen, die als im Projekt inaktiv gekennzeichnet wurden. Dies ist nützlich, um zu verhindern, dass Objekte "gestrandet" werden, wenn jemand ein Projekt verlässt, ohne jedoch seine Assets aus dem Projekt zu übergeben, damit sie von anderen Benutzern verwaltet werden können.
+
+Um ein Asset-Housekeeper zu werden, muss der Benutzer auch Mitglied dieses Projekts sein.
+
+## Asset-Gatekeeper
+
+Hierbei handelt es sich um eine optionale Rolle, die es einem oder mehreren bestimmten Benutzern ermöglicht, die Kontrolle darüber zu haben, ob Assets innerhalb des Projekts veröffentlicht werden. Wenn ein Projektelement veröffentlicht wird, ist es erst dann verfügbar, wenn der Asset Gatekeeper es genehmigt hat. Der Asset Gatekeeper wird benachrichtigt, wenn ein Asset zur Veröffentlichung ansteht. Er verhindert, dass bereits veröffentlichte Elemente zu schnell öffentlich zugänglich werden.
+
+Um ein Asset-Gatekeeper zu werden, muss der Benutzer auch Mitglied dieses Projekts sein.
+
+## Projektadministrator
+
+Der Projektadministrator wird benachrichtigt, wenn sich eine neue Person in LDH für das Projekt anmeldet. Er hat auch die Möglichkeit,:
+
+- Hinzufügen und Entfernen von Personen aus einem Projekt
+- Profile erstellen
+- Institutionen erstellen
+- Personen zu Projektrollen zuzuweisen
+- Markieren, wenn eine Person in einem Projekt inaktiv wird
+
+Sie können auch die Projektdetails und die mit dem Projekt verbundenen Institutionen bearbeiten.
+
+Um ein Projektadministrator zu werden, muss der Benutzer auch Mitglied des Projekts sein.
\ No newline at end of file
diff --git a/docs/images/BestPractice/RelatedItems.png b/docs/images/BestPractice/RelatedItems.png
new file mode 100755
index 0000000000..7e431dfe98
Binary files /dev/null and b/docs/images/BestPractice/RelatedItems.png differ
diff --git a/docs/images/BestPractice/investigation.png b/docs/images/BestPractice/investigation.png
new file mode 100755
index 0000000000..a9214af0d7
Binary files /dev/null and b/docs/images/BestPractice/investigation.png differ
diff --git a/docs/images/BestPractice/network.png b/docs/images/BestPractice/network.png
new file mode 100755
index 0000000000..204ce22f5b
Binary files /dev/null and b/docs/images/BestPractice/network.png differ
diff --git a/docs/images/BestPractice/seekStruct.png b/docs/images/BestPractice/seekStruct.png
new file mode 100755
index 0000000000..d3ec811881
Binary files /dev/null and b/docs/images/BestPractice/seekStruct.png differ
diff --git a/docs/images/BestPractice/studytree.png b/docs/images/BestPractice/studytree.png
new file mode 100755
index 0000000000..93d562d716
Binary files /dev/null and b/docs/images/BestPractice/studytree.png differ
diff --git a/docs/images/BestPractice/studytree_hiddenview.png b/docs/images/BestPractice/studytree_hiddenview.png
new file mode 100755
index 0000000000..e460a25537
Binary files /dev/null and b/docs/images/BestPractice/studytree_hiddenview.png differ
diff --git a/docs/images/BestPractice/view_options.png b/docs/images/BestPractice/view_options.png
new file mode 100755
index 0000000000..e2f534d502
Binary files /dev/null and b/docs/images/BestPractice/view_options.png differ
diff --git a/docs/images/UserGuide/creators.PNG b/docs/images/UserGuide/creators.PNG
new file mode 100755
index 0000000000..e6663809c6
Binary files /dev/null and b/docs/images/UserGuide/creators.PNG differ
diff --git a/docs/images/UserGuide/graph_nav.png b/docs/images/UserGuide/graph_nav.png
new file mode 100755
index 0000000000..2f017ef9be
Binary files /dev/null and b/docs/images/UserGuide/graph_nav.png differ
diff --git a/docs/images/UserGuide/graph_view.png b/docs/images/UserGuide/graph_view.png
new file mode 100755
index 0000000000..c4659bce95
Binary files /dev/null and b/docs/images/UserGuide/graph_view.png differ
diff --git a/docs/images/UserGuide/graph_view_all_nodes.png b/docs/images/UserGuide/graph_view_all_nodes.png
new file mode 100755
index 0000000000..8100ef1832
Binary files /dev/null and b/docs/images/UserGuide/graph_view_all_nodes.png differ
diff --git a/docs/images/UserGuide/manage_account_2.png b/docs/images/UserGuide/manage_account_2.png
new file mode 100755
index 0000000000..fc0a48436e
Binary files /dev/null and b/docs/images/UserGuide/manage_account_2.png differ
diff --git a/docs/images/UserGuide/newCreator.png b/docs/images/UserGuide/newCreator.png
new file mode 100755
index 0000000000..5770f9ae1b
Binary files /dev/null and b/docs/images/UserGuide/newCreator.png differ
diff --git a/docs/images/UserGuide/publications.png b/docs/images/UserGuide/publications.png
new file mode 100755
index 0000000000..d82650ad71
Binary files /dev/null and b/docs/images/UserGuide/publications.png differ
diff --git a/docs/images/UserGuide/request-membership-button.png b/docs/images/UserGuide/request-membership-button.png
new file mode 100755
index 0000000000..6e518c86bb
Binary files /dev/null and b/docs/images/UserGuide/request-membership-button.png differ
diff --git a/docs/images/UserGuide/sharing.png b/docs/images/UserGuide/sharing.png
new file mode 100755
index 0000000000..3e1a9355d6
Binary files /dev/null and b/docs/images/UserGuide/sharing.png differ
diff --git a/docs/images/UserGuide/splitt_view.png b/docs/images/UserGuide/splitt_view.png
new file mode 100755
index 0000000000..372bbb6d5a
Binary files /dev/null and b/docs/images/UserGuide/splitt_view.png differ
diff --git a/docs/images/UserGuide/tree_struct.png b/docs/images/UserGuide/tree_struct.png
new file mode 100755
index 0000000000..f5eb7425fb
Binary files /dev/null and b/docs/images/UserGuide/tree_struct.png differ
diff --git a/docs/images/UserGuide/tree_struct_folded.png b/docs/images/UserGuide/tree_struct_folded.png
new file mode 100755
index 0000000000..a49e6edf25
Binary files /dev/null and b/docs/images/UserGuide/tree_struct_folded.png differ
diff --git a/docs/index.md b/docs/index.md
new file mode 100755
index 0000000000..bc51179340
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,45 @@
+[![Build Status](https://github.com/nfdi4health/ldh/actions/workflows/tests.yml/badge.svg)](https://github.com/nfdi4health/ldh/actions/workflows/tests.yml)
+# Local Data Hub
+
+## Über den Local Data Hub
+---
+Die Nfdi4Health Local Data Hub (LDH) Plattform ist eine webbasierte Ressource für den Austausch von heterogenen wissenschaftlichen Forschungsdaten, Modellen oder Simulationen, Prozessen und Forschungsergebnissen. Sie bewahrt Assoziationen zwischen ihnen sowie Informationen über die beteiligten Personen und Organisationen. Der LDH basiert dabei auf dem [SEEK4Science][seek] Framework. Grundlage von SEEK ist die ISA-Infrastruktur, ein Standardformat zur Beschreibung, wie einzelne Experimente zu umfassenderen Studien und Untersuchungen zusammengeführt werden. Innerhalb von SEEK wurde ISA erweitert und ist konfigurierbar, so dass die Struktur auch außerhalb der Biologie verwendet werden kann.
+
+LDH enthält eine semantische Technologie, die anspruchsvolle Abfragen der Daten ermöglicht, ohne die Benutzer zu behindern.
+
+Für ein Beispiel von LDH besuchen Sie bitte unsere [Demoinstanz][demo].
+
+Um zu sehen, wie der LDH als Teil von Nfdi4health für echte Wissenschaft genutzt wird, besuchen Sie bitte den [Leipzig Health Atlas][LHA]
+
+## NFDI4Health
+---
+Der LDH wird im Rahmen der NFDI4Health-Initiative entwickelt und finanziert. Die Nationale Forschungsdateninfrastruktur für personenbezogene Gesundheitsdaten – fokussiert sich auf Daten, die in klinischen, epidemiologischen und Public Health-Studien generiert werden. Die Erhebung und Analyse dieser Daten zu Gesundheits- sowie Krankheitsstatus und wichtiger Einflussfaktoren darauf sind eine wesentliche Komponente zur Entwicklung neuer Therapien, übergreifender Versorgungsansätze und präventiver Maßnahmen eines modernen Gesundheitswesens.
+
+Obwohl diese Daten bereits hohen inhaltlichen Qualitätsstandards genügen, erfüllen sie häufig nicht die Anforderungen der FAIR-Prinzipien:
+
+- Die Auffindbarkeit der Daten ist aufgrund fehlender internationaler Standards für Registrierung und Publikation häufig eingeschränkt.
+- Möglichkeiten der Datennutzung durch Dritte sind in der Regel unklar.
+- Weiterhin schränken Datenschutzbestimmungen und Einwilligungserklärungen der Studienteilnehmenden die Wiederverwendbarkeit der Daten ein.
+- Datenbanken sind oft nicht interoperabel, z. B. aufgrund der großen methodischen Heterogenität bei der Erfassung von Expositionen und gesundheitlichen Endpunkten.
+
+## Installation
+---
+
+Wir empfehlen die Installation vom LDH auf Debian oder Ubuntu.
+
+Um die neueste Version zu installieren, besuchen Sie bitte: [LDH Installationsanleitung](./AdminGuide/index.md)
+
+Für Details über andere Distributionen und die Installation unter Mac OS X besuchen Sie bitte: [Anleitung für andere Distributionen](./AdminGuide/otherdistro.md#)
+
+Die Dokumentation ist auf dem ghpages-Zweig verfügbar.
+
+## Documentation
+---
+
+
+- [User Guide](./UserGuide/index.md)
+- [Admin Guide](./AdminGuide/index.md)
+
+[seek]:[https://seek4science.org/]
+[demo]:[https://lap.test.nfdi4health.de/]
+[LHA]:[https://www.health-atlas.de/]
diff --git a/lib/seek/assets_standard_controller_actions.rb b/lib/seek/assets_standard_controller_actions.rb
index 238bf43df1..30846847c8 100644
--- a/lib/seek/assets_standard_controller_actions.rb
+++ b/lib/seek/assets_standard_controller_actions.rb
@@ -124,6 +124,17 @@ def update_sharing_policies(item, parameters = params)
item.policy.set_attributes_with_sharing(policy_params(parameters)) if policy_params(parameters).present?
end
+ def update_linked_custom_metadatas(item, parameters = params)
+
+ root_key = controller_name.singularize.to_sym
+
+ # return no custom metdata is selected
+ return unless params[root_key][:custom_metadata_attributes].present?
+ return unless params[root_key][:custom_metadata_attributes][:custom_metadata_type_id].present?
+ item.custom_metadata.update_linked_custom_metadata(parameters[root_key][:custom_metadata_attributes])
+
+ end
+
def initialize_asset
item = class_for_controller_name.new(asset_params)
set_shared_item_variable(item)
diff --git a/lib/seek/config.rb b/lib/seek/config.rb
index 00110ab98d..b216834f0b 100644
--- a/lib/seek/config.rb
+++ b/lib/seek/config.rb
@@ -38,6 +38,8 @@ def smtp_propagate
password = smtp_settings 'password'
smtp_hash['password'] = password
+ smtp_hash['enable_starttls_auto'] = false if smtp_hash['enable_starttls_auto'].nil?
+
new_hash = {}
smtp_hash.keys.each do |key|
new_hash[key.to_sym] = smtp_hash[key]
diff --git a/lib/seek/config_setting_attributes.yml b/lib/seek/config_setting_attributes.yml
index 9fdd58c58d..000357c341 100644
--- a/lib/seek/config_setting_attributes.yml
+++ b/lib/seek/config_setting_attributes.yml
@@ -254,3 +254,5 @@ fair_signposting_enabled:
bio_tools_enabled:
require_cookie_consent:
galaxy_tool_sources:
+regular_job_offset:
+ convert: :to_i
diff --git a/lib/seek/content_blob_common.rb b/lib/seek/content_blob_common.rb
index 6f14cdfe6b..2ec85f98ec 100644
--- a/lib/seek/content_blob_common.rb
+++ b/lib/seek/content_blob_common.rb
@@ -122,24 +122,22 @@ def redirect_on_error(asset, msg = nil)
end
def handle_download(disposition = 'attachment', image_size = nil)
- if @content_blob.url.blank?
- if @content_blob.file_exists?
- if image_size && @content_blob.is_image_convertable?
- @content_blob.resize_image(image_size)
- filepath = @content_blob.full_cache_path(image_size)
- headers['Content-Length'] = File.size(filepath).to_s
- else
- filepath = @content_blob.filepath
- # added for the benefit of the tests after rails3 upgrade - but doubt it is required
- headers['Content-Length'] = @content_blob.file_size.to_s
- end
- send_file filepath, filename: @content_blob.original_filename, type: @content_blob.content_type || 'application/octet-stream', disposition: disposition
+ jerm_generated = @asset_version && @asset_version.contributor.nil?
+ if @content_blob.file_exists? && !jerm_generated # JERM will try to download first
+ if image_size && @content_blob.is_image_convertable?
+ @content_blob.resize_image(image_size)
+ filepath = @content_blob.full_cache_path(image_size)
+ headers['Content-Length'] = File.size(filepath).to_s
else
- redirect_on_error @asset_version, "Unable to find a copy of the file for download, or an alternative location. Please contact an administrator of #{Seek::Config.instance_name}."
+ filepath = @content_blob.filepath
+ # added for the benefit of the tests after rails3 upgrade - but doubt it is required
+ headers['Content-Length'] = @content_blob.file_size.to_s
+ headers['Content-MD5'] = @content_blob.md5sum if @content_blob.md5sum
end
- else
+ send_file filepath, filename: @content_blob.original_filename, type: @content_blob.content_type || 'application/octet-stream', disposition: disposition
+ elsif @content_blob.url.present?
begin
- if @asset_version.contributor.nil? # A jerm generated resource
+ if jerm_generated
download_jerm_asset
else
case URI(@content_blob.url).scheme
@@ -148,14 +146,14 @@ def handle_download(disposition = 'attachment', image_size = nil)
else
stream_from_http_url
end
-
end
rescue Seek::DownloadException => de
redirect_on_error @asset_version, 'There was an error accessing the remote resource, and a local copy was not available. Please try again later when the remote resource may be available again.'
rescue Jerm::JermException => de
redirect_on_error @asset_version, de.message
end
-
+ else
+ redirect_on_error @asset_version, "Unable to find a copy of the file for download, or an alternative location. Please contact an administrator of #{Seek::Config.instance_name}."
end
end
@@ -186,7 +184,7 @@ def stream_from_http_url
info = Seek::DownloadHandling::HTTPHandler.new(@content_blob.url).info
case info[:code]
when 200
- stream_with(Seek::DownloadHandling::HTTPStreamer.new(@content_blob.url))
+ stream_with(Seek::DownloadHandling::HTTPStreamer.new(@content_blob.url), info)
when 401, 403
# Try redirecting the user to the URL if SEEK cannot access it
redirect_to @content_blob.url
@@ -205,8 +203,9 @@ def stream_from_ftp_url
stream_with(Seek::DownloadHandling::FTPStreamer.new(@content_blob.url))
end
- def stream_with(streamer)
+ def stream_with(streamer, info={})
response.headers['Content-Type'] = @content_blob.content_type
+ response.headers['Content-Length'] = info[:file_size].to_s if info[:file_size]
response.headers['Content-Disposition'] = "attachment; filename=#{@content_blob.original_filename}"
response.headers['Last-Modified'] = Time.now.ctime.to_s
diff --git a/lib/seek/json_metadata/attribute.rb b/lib/seek/json_metadata/attribute.rb
index 09505c029d..d6b4453a78 100644
--- a/lib/seek/json_metadata/attribute.rb
+++ b/lib/seek/json_metadata/attribute.rb
@@ -16,7 +16,7 @@ module Attribute
# validates that the attribute type is SeekSample if linked_sample_type is set, and vice-versa
validate :linked_sample_type_and_attribute_type_consistency
- delegate :controlled_vocab?, :seek_cv_list?, :seek_sample?, :seek_sample_multi?, :seek_strain?, :seek_resource?, to: :sample_attribute_type, allow_nil: true
+ delegate :controlled_vocab?, :seek_cv_list?, :seek_sample?, :seek_sample_multi?, :seek_strain?, :seek_resource?, :linked_custom_metadata?, to: :sample_attribute_type, allow_nil: true
end
# checks whether the value is blank against the attribute type and base type
diff --git a/lib/seek/json_metadata/serialization.rb b/lib/seek/json_metadata/serialization.rb
index 81332be220..1ed4f4ca03 100644
--- a/lib/seek/json_metadata/serialization.rb
+++ b/lib/seek/json_metadata/serialization.rb
@@ -18,9 +18,13 @@ def data
end
def get_attribute_value(attr)
- attr = attr.accessor_name if attr.is_a?(attribute_class)
-
- data[attr.to_s]
+ if attr.try(:sample_attribute_type).try(:linked_custom_metadata?)
+ value = self.linked_custom_metadatas.select{|cm| cm.custom_metadata_type_id == attr.linked_custom_metadata_type_id}.select{|cm|cm.custom_metadata_attribute == attr}.first
+ else
+ attr = attr.accessor_name if attr.is_a?(attribute_class)
+ value = data[attr.to_s]
+ end
+ value
end
def set_attribute_value(attr, value)
diff --git a/lib/seek/list_sorter.rb b/lib/seek/list_sorter.rb
index c72854c002..e6b1b74a47 100644
--- a/lib/seek/list_sorter.rb
+++ b/lib/seek/list_sorter.rb
@@ -45,7 +45,7 @@ class ListSorter
# This section **modifies** "items" relation so that it includes a new column "downloads"
alog=ActivityLog.all.where(action: 'download',activity_loggable_type: items.first.class.name)
downloads=alog.select("activity_loggable_id AS #{items.table.name}_id, COUNT(activity_loggable_id) AS downloads").group(:activity_loggable_id)
- items._select!('*', 'd.downloads').joins!("LEFT OUTER JOIN (#{downloads.to_sql}) d ON #{items.table.name}.id = d.#{items.table.name}_id")
+ items._select!("#{items.table.name}.*", 'd.downloads').joins!("LEFT OUTER JOIN (#{downloads.to_sql}) d ON #{items.table.name}.id = d.#{items.table.name}_id")
#### Using Arel
# This section builds the equivalent arel_table to provide the corresponding arel_field
@@ -83,7 +83,7 @@ class ListSorter
# This section **modifies** "items" relation so that it includes a new column "views"
alog=ActivityLog.all.where(action: 'show',activity_loggable_type: items.first.class.name)
views=alog.select("activity_loggable_id AS #{items.table.name}_id, COUNT(activity_loggable_id) AS views").group(:activity_loggable_id)
- items._select!('*', 'v.views').joins!("LEFT OUTER JOIN (#{views.to_sql}) v ON #{items.table.name}.id = v.#{items.table.name}_id")
+ items._select!("#{items.table.name}.*", 'v.views').joins!("LEFT OUTER JOIN (#{views.to_sql}) v ON #{items.table.name}.id = v.#{items.table.name}_id")
#### Using Arel
# This section builds the equivalent arel_table to provide the corresponding arel_field
@@ -165,16 +165,20 @@ def self.sort_by_order(items, order = nil)
if items.is_a?(ActiveRecord::Relation)
orderings = strategy_for_relation(order, items)
# Postgres requires any columns being ORDERed to be explicitly SELECTed (only when using DISTINCT?).
- columns = [items.arel.as(items.table.name)[Arel.star]]
- orderings.each do |ordering|
- if ordering.is_a?(Arel::Nodes::Ordering)
- expr = ordering.expr
- # Don't need to SELECT columns that are already covered by "*" and MySQL will error if you try!
- unless expr.respond_to?(:relation) && expr.relation == items.arel_table
- columns << expr
+ if ["--views_desc","--downloads_desc"].include? order
+ columns = []
+ else
+ columns = [items.arel.as(items.table.name)[Arel.star]]
+ orderings.each do |ordering|
+ if ordering.is_a?(Arel::Nodes::Ordering)
+ expr = ordering.expr
+ # Don't need to SELECT columns that are already covered by "*" and MySQL will error if you try!
+ unless expr.respond_to?(:relation) && expr.relation == items.arel_table
+ columns << expr
+ end
+ else
+ columns << ordering
end
- else
- columns << ordering
end
end
items.select(columns).order(orderings)
diff --git a/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb
new file mode 100644
index 0000000000..d3da68d69e
--- /dev/null
+++ b/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb
@@ -0,0 +1,12 @@
+module Seek
+ module Samples
+ module AttributeTypeHandlers
+ class LinkedCustomMetadataAttributeTypeHandler < BaseAttributeHandler
+
+ def test_value(value)
+ fail 'Not a custom metadata' unless value.is_a?(CustomMetadata)
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/seek/samples/base_type.rb b/lib/seek/samples/base_type.rb
index 60e3f39e4a..1091eafdc5 100644
--- a/lib/seek/samples/base_type.rb
+++ b/lib/seek/samples/base_type.rb
@@ -3,7 +3,7 @@ module Samples
# Defines the base type used for sample attributes, and makes them available as constants
# for example Seek::Samples::BaseType.DATE_TIME = 'DateTime'
module BaseType
- ALL_TYPES = %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList)
+ ALL_TYPES = %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList LinkedCustomMetadata)
ALL_TYPES.each do |type|
BaseType.const_set(type.underscore.upcase, type)
diff --git a/lib/seek/sharing/sharing_common.rb b/lib/seek/sharing/sharing_common.rb
index be67d7035a..a45cec2f6f 100644
--- a/lib/seek/sharing/sharing_common.rb
+++ b/lib/seek/sharing/sharing_common.rb
@@ -73,26 +73,16 @@ def batch_sharing_permission_changed
# returns an enumeration of assets for bulk sharing change based upon the parameters passed
def resolve_sharing_params(params)
- param_not_isa = params[:share_not_isa]
- param_isa = params[:share_isa]
+ param_not_isa = params[:share_not_isa] || {}
+ param_isa = params[:share_isa] || {}
if param_not_isa.blank? && param_isa.blank?
[@asset].compact
else
assets = []
- unless param_not_isa.blank?
- param_not_isa.keys.each do |asset_class|
- param_not_isa[asset_class].keys.each do |id|
- assets << eval("#{asset_class}.find_by_id(#{id})")
- end
- end
- end
- unless param_isa.blank?
- param_isa.keys.each do |asset_class|
- param_isa[asset_class].keys.each do |id|
- assets << eval("#{asset_class}.find_by_id(#{id})")
- end
- end
+ Seek::Util.authorized_types.each do |klass|
+ ids = (param_not_isa[klass.name]&.keys || []) | (param_isa[klass.name]&.keys || [])
+ assets += klass.where(id: ids).to_a if ids.any?
end
assets.compact.uniq
end
diff --git a/public/api/definitions/_schemas.yml b/public/api/definitions/_schemas.yml
index 63cf6b7019..cfc28c5ed3 100644
--- a/public/api/definitions/_schemas.yml
+++ b/public/api/definitions/_schemas.yml
@@ -2287,6 +2287,8 @@ programmePatch:
properties:
administrators:
$ref: "#/components/schemas/multipleReferences"
+ people:
+ $ref: "#/components/schemas/multipleReferences"
projects:
$ref: "#/components/schemas/multipleReferences"
additionalProperties: false
@@ -4916,4 +4918,4 @@ workflowResponse:
required:
- data
- jsonapi
- additionalProperties: false
\ No newline at end of file
+ additionalProperties: false
diff --git a/public/api/examples/programmePatch.json b/public/api/examples/programmePatch.json
index 314ce7748f..07b41fd5c0 100644
--- a/public/api/examples/programmePatch.json
+++ b/public/api/examples/programmePatch.json
@@ -1,6 +1,6 @@
{
"data": {
- "id": "12",
+ "id": "1296",
"type": "programmes",
"attributes": {
"title": "Changed title",
@@ -15,7 +15,7 @@
"projects": {
"data": [
{
- "id": "433",
+ "id": "7653",
"type": "projects"
}
]
@@ -23,7 +23,15 @@
"administrators": {
"data": [
{
- "id": "404",
+ "id": "5588",
+ "type": "people"
+ }
+ ]
+ },
+ "people": {
+ "data": [
+ {
+ "id": "5588",
"type": "people"
}
]
diff --git a/public/api/examples/programmePatchResponse.json b/public/api/examples/programmePatchResponse.json
index d06628c7cf..5e6383467e 100644
--- a/public/api/examples/programmePatchResponse.json
+++ b/public/api/examples/programmePatchResponse.json
@@ -1,6 +1,6 @@
{
"data": {
- "id": "227",
+ "id": "1296",
"type": "programmes",
"attributes": {
"discussion_links": [
@@ -19,20 +19,23 @@
"administrators": {
"data": [
{
- "id": "1039995956",
+ "id": "5588",
"type": "people"
}
]
},
"people": {
"data": [
-
+ {
+ "id": "5588",
+ "type": "people"
+ }
]
},
"projects": {
"data": [
{
- "id": "1022260828",
+ "id": "7653",
"type": "projects"
}
]
@@ -104,14 +107,14 @@
}
},
"links": {
- "self": "/programmes/227"
+ "self": "/programmes/1296"
},
"meta": {
- "created": "2022-10-26T11:51:45.000Z",
- "modified": "2022-10-26T11:51:45.000Z",
+ "created": "2023-03-28T14:57:01.000Z",
+ "modified": "2023-03-28T14:57:01.000Z",
"api_version": "0.3",
"base_url": "http://localhost:3000",
- "uuid": "7d2b06a0-3752-013b-356e-000c29a94011"
+ "uuid": "b8016460-afa6-013b-c76a-2c91a17e7bb9"
}
},
"jsonapi": {
diff --git a/public/api/examples/programmePost.json b/public/api/examples/programmePost.json
index b706bef83f..a16f03954c 100644
--- a/public/api/examples/programmePost.json
+++ b/public/api/examples/programmePost.json
@@ -15,7 +15,7 @@
"projects": {
"data": [
{
- "id": "352",
+ "id": "7564",
"type": "projects"
}
]
@@ -23,11 +23,11 @@
"administrators": {
"data": [
{
- "id": "334",
+ "id": "5510",
"type": "people"
},
{
- "id": "335",
+ "id": "5511",
"type": "people"
}
]
diff --git a/public/api/examples/programmePostResponse.json b/public/api/examples/programmePostResponse.json
index a55042e96f..e413d7b659 100644
--- a/public/api/examples/programmePostResponse.json
+++ b/public/api/examples/programmePostResponse.json
@@ -1,6 +1,6 @@
{
"data": {
- "id": "219",
+ "id": "1288",
"type": "programmes",
"attributes": {
"discussion_links": [
@@ -20,24 +20,31 @@
"administrators": {
"data": [
{
- "id": "1039995878",
+ "id": "5510",
"type": "people"
},
{
- "id": "1039995879",
+ "id": "5511",
"type": "people"
}
]
},
"people": {
"data": [
-
+ {
+ "id": "5510",
+ "type": "people"
+ },
+ {
+ "id": "5511",
+ "type": "people"
+ }
]
},
"projects": {
"data": [
{
- "id": "1022260739",
+ "id": "7564",
"type": "projects"
}
]
@@ -109,14 +116,14 @@
}
},
"links": {
- "self": "/programmes/219"
+ "self": "/programmes/1288"
},
"meta": {
- "created": "2022-10-26T11:51:36.000Z",
- "modified": "2022-10-26T11:51:36.000Z",
+ "created": "2023-03-28T14:56:53.000Z",
+ "modified": "2023-03-28T14:56:53.000Z",
"api_version": "0.3",
"base_url": "http://localhost:3000",
- "uuid": "77e168e0-3752-013b-356e-000c29a94011"
+ "uuid": "b37f0780-afa6-013b-c76a-2c91a17e7bb9"
}
},
"jsonapi": {
diff --git a/public/api/examples/programmeResponse.json b/public/api/examples/programmeResponse.json
index 9f10d1e1a0..4410e43f65 100644
--- a/public/api/examples/programmeResponse.json
+++ b/public/api/examples/programmeResponse.json
@@ -1,11 +1,11 @@
{
"data": {
- "id": "226",
+ "id": "1295",
"type": "programmes",
"attributes": {
"discussion_links": [
{
- "id": "296",
+ "id": "410",
"label": "Slack",
"url": "http://www.slack.com/"
}
@@ -23,7 +23,7 @@
"administrators": {
"data": [
{
- "id": "1039995953",
+ "id": "5585",
"type": "people"
}
]
@@ -31,7 +31,11 @@
"people": {
"data": [
{
- "id": "1039995952",
+ "id": "5584",
+ "type": "people"
+ },
+ {
+ "id": "5585",
"type": "people"
}
]
@@ -39,7 +43,7 @@
"projects": {
"data": [
{
- "id": "1022260823",
+ "id": "7648",
"type": "projects"
}
]
@@ -47,7 +51,7 @@
"institutions": {
"data": [
{
- "id": "980200600",
+ "id": "5584",
"type": "institutions"
}
]
@@ -55,7 +59,7 @@
"investigations": {
"data": [
{
- "id": "973656185",
+ "id": "656",
"type": "investigations"
}
]
@@ -63,7 +67,7 @@
"studies": {
"data": [
{
- "id": "1060386098",
+ "id": "574",
"type": "studies"
}
]
@@ -71,7 +75,7 @@
"assays": {
"data": [
{
- "id": "1035387711",
+ "id": "492",
"type": "assays"
}
]
@@ -79,7 +83,7 @@
"data_files": {
"data": [
{
- "id": "883654903",
+ "id": "164",
"type": "data_files"
}
]
@@ -87,7 +91,7 @@
"models": {
"data": [
{
- "id": "1004286178",
+ "id": "656",
"type": "models"
}
]
@@ -95,7 +99,7 @@
"sops": {
"data": [
{
- "id": "1055250943",
+ "id": "164",
"type": "sops"
}
]
@@ -103,7 +107,7 @@
"publications": {
"data": [
{
- "id": "498",
+ "id": "164",
"type": "publications"
}
]
@@ -111,7 +115,7 @@
"presentations": {
"data": [
{
- "id": "210",
+ "id": "82",
"type": "presentations"
}
]
@@ -119,7 +123,7 @@
"events": {
"data": [
{
- "id": "1025618899",
+ "id": "82",
"type": "events"
}
]
@@ -127,7 +131,7 @@
"documents": {
"data": [
{
- "id": "452",
+ "id": "164",
"type": "documents"
}
]
@@ -135,7 +139,7 @@
"workflows": {
"data": [
{
- "id": "386",
+ "id": "82",
"type": "workflows"
}
]
@@ -147,14 +151,14 @@
}
},
"links": {
- "self": "/programmes/226"
+ "self": "/programmes/1295"
},
"meta": {
- "created": "2022-10-26T11:51:44.000Z",
- "modified": "2022-10-26T11:51:44.000Z",
+ "created": "2023-03-28T14:57:00.000Z",
+ "modified": "2023-03-28T14:57:00.000Z",
"api_version": "0.3",
"base_url": "http://localhost:3000",
- "uuid": "7d002660-3752-013b-356e-000c29a94011"
+ "uuid": "b7d5d740-afa6-013b-c76a-2c91a17e7bb9"
}
},
"jsonapi": {
diff --git a/public/api/examples/programmesResponse.json b/public/api/examples/programmesResponse.json
index 6669a896da..b6e1fe975a 100644
--- a/public/api/examples/programmesResponse.json
+++ b/public/api/examples/programmesResponse.json
@@ -1,33 +1,33 @@
{
"data": [
{
- "id": "8",
+ "id": "1292",
"type": "programmes",
"attributes": {
"title": "A Maximal Programme"
},
"links": {
- "self": "/programmes/8"
+ "self": "/programmes/1292"
}
},
{
- "id": "6",
+ "id": "1291",
"type": "programmes",
"attributes": {
- "title": "A Minimal Programme"
+ "title": "A Programme: 28"
},
"links": {
- "self": "/programmes/6"
+ "self": "/programmes/1291"
}
},
{
- "id": "7",
+ "id": "1290",
"type": "programmes",
"attributes": {
- "title": "A Programme: 5"
+ "title": "A Minimal Programme"
},
"links": {
- "self": "/programmes/7"
+ "self": "/programmes/1290"
}
}
],
diff --git a/test/factories/custom_metadata_types.rb b/test/factories/custom_metadata_types.rb
index f2c3026f51..dd4ccf23d0 100644
--- a/test/factories/custom_metadata_types.rb
+++ b/test/factories/custom_metadata_types.rb
@@ -71,10 +71,10 @@
f.after_build do |a|
a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'apple name')
cv_list_attribute = CustomMetadataAttribute.new(title: 'apple list', sample_attribute_type: Factory(:cv_list_attribute_type),
- sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), description: "apple samples list", label: "apple samples list")
+ sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), description: "apple samples list", label: "apple samples list")
a.custom_metadata_attributes << cv_list_attribute
cv_attribute = CustomMetadataAttribute.new(title: 'apple controlled vocab', sample_attribute_type: Factory(:controlled_vocab_attribute_type),
- sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), description: "apple samples controlled vocab", label: "apple samples controlled vocab")
+ sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), description: "apple samples controlled vocab", label: "apple samples controlled vocab")
a.custom_metadata_attributes << cv_attribute
end
end
@@ -121,4 +121,115 @@
a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'type_of_growth_facility')
a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'cultural_practices')
end
+end
+
+# for testing linked custom metadata
+Factory.define(:first_name_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'first_name'
+ f.association :sample_attribute_type, factory: :string_sample_attribute_type
+end
+
+Factory.define(:last_name_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'last_name'
+ f.association :sample_attribute_type, factory: :string_sample_attribute_type
+end
+
+Factory.define(:street_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'street'
+ f.association :sample_attribute_type, factory: :string_sample_attribute_type
+end
+
+Factory.define(:city_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'city'
+ f.association :sample_attribute_type, factory: :string_sample_attribute_type
+end
+
+Factory.define(:role_email_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'role_email'
+ f.association :sample_attribute_type, factory: :string_sample_attribute_type
+end
+
+Factory.define(:role_phone_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'role_phone'
+ f.association :sample_attribute_type, factory: :string_sample_attribute_type
+end
+
+
+Factory.define(:role_name_custom_metadata_type,class:CustomMetadataType) do |f|
+ f.title 'role_name'
+ f.supported_type 'Study'
+ f.after_build do |a|
+ a.custom_metadata_attributes << Factory(:first_name_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << Factory(:last_name_custom_metadata_attribute, required: true)
+ end
+end
+
+Factory.define(:role_address_custom_metadata_type,class:CustomMetadataType) do |f|
+ f.title 'role_address'
+ f.supported_type 'Study'
+ f.after_build do |a|
+ a.custom_metadata_attributes << Factory(:street_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << Factory(:city_custom_metadata_attribute, required: true)
+ end
+end
+
+Factory.define(:role_name_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'role_name'
+ f.association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type
+ f.association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type
+end
+
+Factory.define(:role_address_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'role_address'
+ f.association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type
+ f.association :linked_custom_metadata_type, factory: :role_address_custom_metadata_type
+end
+
+Factory.define(:role_custom_metadata_type,class:CustomMetadataType) do |f|
+ f.title 'role'
+ f.supported_type 'Study'
+ f.after_build do |a|
+ a.custom_metadata_attributes << Factory(:role_email_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << Factory(:role_phone_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << Factory(:role_name_linked_custom_metadata_attribute)
+ end
+end
+
+Factory.define(:role_multiple_custom_metadata_type,class:CustomMetadataType) do |f|
+ f.title 'role'
+ f.supported_type 'Study'
+ f.after_build do |a|
+ a.custom_metadata_attributes << Factory(:role_email_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << Factory(:role_phone_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << Factory(:role_name_linked_custom_metadata_attribute)
+ a.custom_metadata_attributes << Factory(:role_address_linked_custom_metadata_attribute)
+ end
+end
+
+Factory.define(:dad_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'dad'
+ f.association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type
+ f.association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type
+end
+
+Factory.define(:mom_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'mom'
+ f.association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type
+ f.association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type
+end
+
+Factory.define(:child_name_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do |f|
+ f.title 'child'
+ f.association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type
+ f.association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type
+end
+
+Factory.define(:family_custom_metadata_type,class:CustomMetadataType) do |f|
+ f.title 'family'
+ f.supported_type 'Study'
+ f.after_build do |a|
+ a.custom_metadata_attributes << Factory(:dad_linked_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << Factory(:mom_linked_custom_metadata_attribute,required: true)
+ a.custom_metadata_attributes << Factory(:child_name_linked_custom_metadata_attribute)
+ end
end
\ No newline at end of file
diff --git a/test/factories/sample_attribute_types.rb b/test/factories/sample_attribute_types.rb
index b0b723a90d..51419a2018 100644
--- a/test/factories/sample_attribute_types.rb
+++ b/test/factories/sample_attribute_types.rb
@@ -48,6 +48,11 @@
f.base_type Seek::Samples::BaseType::SEEK_SAMPLE_MULTI
end
+Factory.define(:custom_metadata_sample_attribute_type, class: SampleAttributeType) do |f|
+ f.sequence(:title) { |n| "Linked Custom Metadata attribute type #{n}" }
+ f.base_type Seek::Samples::BaseType::LINKED_CUSTOM_METADATA
+end
+
Factory.define(:data_file_sample_attribute_type, class: SampleAttributeType) do |f|
f.sequence(:title) { |n| "Data file attribute type #{n}" }
f.base_type Seek::Samples::BaseType::SEEK_DATA_FILE
diff --git a/test/fixtures/json/requests/patch_max_programme.json.erb b/test/fixtures/json/requests/patch_max_programme.json.erb
index 02b680fc6d..08278a16aa 100644
--- a/test/fixtures/json/requests/patch_max_programme.json.erb
+++ b/test/fixtures/json/requests/patch_max_programme.json.erb
@@ -27,6 +27,14 @@
"type": "people"
}
]
+ },
+ "people": {
+ "data": [
+ {
+ "id": "<%= @programme_administrator.id %>",
+ "type": "people"
+ }
+ ]
}
}
}
diff --git a/test/fixtures/json/responses/get_max_programme.json.erb b/test/fixtures/json/responses/get_max_programme.json.erb
index e419dd0d06..fe76013233 100644
--- a/test/fixtures/json/responses/get_max_programme.json.erb
+++ b/test/fixtures/json/responses/get_max_programme.json.erb
@@ -31,7 +31,8 @@
},
"people": {
"data":
- <%= res.people.map { |p| { id: p.id.to_s, type: 'people' } }.to_json %>
+ <% people = res.people.map { |p| { id: p.id.to_s, type: 'people' } } %>
+ <%= people.append({ id: res.programme_administrator_ids.first.to_s, type: 'people' }).to_json %>
},
"projects": {
"data": [
diff --git a/test/functional/content_blobs_controller_test.rb b/test/functional/content_blobs_controller_test.rb
index b12d09980a..ff4bcd7ac4 100644
--- a/test/functional/content_blobs_controller_test.rb
+++ b/test/functional/content_blobs_controller_test.rb
@@ -368,6 +368,8 @@ def setup
assert File.exist?(doc_sop.content_blob.filepath('pdf')), 'the generated PDF file should remain'
end
+
+
test 'should gracefully handle view_pdf for non existing asset' do
stub_request(:head, 'http://somewhere.com/piccy.doc').to_return(status: 404)
sop = Factory(:sop,
@@ -566,8 +568,39 @@ def setup
assert_equal "attachment; filename=\"small-test-spreadsheet.xls\"; filename*=UTF-8''small-test-spreadsheet.xls", @response.header['Content-Disposition']
assert_equal 'application/vnd.ms-excel', @response.header['Content-Type']
assert_equal '7168', @response.header['Content-Length']
+ assert_equal '86f7a87eb0b1c30b172037d69628f279', @response.header['Content-MD5']
+ end
+
+ test 'download should provide the content length if file exists but has a url' do
+ df = Factory :small_test_spreadsheet_datafile, policy: Factory(:public_policy), contributor: User.current_user.person
+ blob = df.content_blob
+ blob.update_column(:url, 'http://website.com/somefile.txt')
+ get :download, params: { data_file_id: df, id: df.content_blob }
+ assert_response :success
+ assert_equal "attachment; filename=\"small-test-spreadsheet.xls\"; filename*=UTF-8''small-test-spreadsheet.xls", @response.header['Content-Disposition']
+ assert_equal 'application/vnd.ms-excel', @response.header['Content-Type']
+ assert_equal '7168', @response.header['Content-Length']
+ assert_equal '86f7a87eb0b1c30b172037d69628f279', @response.header['Content-MD5']
+ end
+
+ test 'download via streaming should provide the content length' do
+ mock_remote_file "#{Rails.root}/test/fixtures/files/ms_word_test.doc",
+ 'http://somewhere.com/piccy.doc',
+ 'Content-Length':'500'
+ doc_sop = Factory(:sop,
+ policy: Factory(:public_policy),
+ contributor: User.current_user.person,
+ content_blob: Factory(:doc_content_blob,
+ data: nil,
+ url: 'http://somewhere.com/piccy.doc',
+ uuid: UUID.generate))
+ get :download, params: { sop_id: doc_sop, id: doc_sop.content_blob }
+ assert_response :success
+
+ assert_equal '500', @response.header['Content-Length']
end
+
test 'should not log download for inline view intent' do
df = Factory :small_test_spreadsheet_datafile, policy: Factory(:public_policy), contributor: User.current_user.person
assert_no_difference('ActivityLog.count') do
diff --git a/test/functional/documents_controller_test.rb b/test/functional/documents_controller_test.rb
index 8e54eae323..887dff2b82 100644
--- a/test/functional/documents_controller_test.rb
+++ b/test/functional/documents_controller_test.rb
@@ -993,7 +993,17 @@ class DocumentsControllerTest < ActionController::TestCase
Factory(:activity_log, action: 'download', activity_loggable: d6, created_at: 4.minutes.ago, culprit: person.user)
Factory(:activity_log, action: 'download', activity_loggable: d5, created_at: 3.minutes.ago, culprit: person.user)
+ d3.annotate_with('tag1', 'tag', d3.contributor)
+ d4.annotate_with('tag1', 'tag', d4.contributor)
+ d5.annotate_with('tag1', 'tag', d5.contributor)
+ disable_authorization_checks do
+ d3.save!
+ d4.save!
+ d5.save!
+ end
+
downloads_ordered = [d2, d3, d6, d5, d1, d4]
+ downloads_ordered_tag1 = [d3, d5, d4]
get :index
assert_select '#index_sort_order' do
@@ -1003,6 +1013,10 @@ class DocumentsControllerTest < ActionController::TestCase
get :index, params: { order: 'downloads_desc' }
assert_response :success
assert_equal downloads_ordered, assigns(:documents).to_a
+
+ get :index, params: { filter: { tag: 'tag1' }, order: 'downloads_desc' }
+ assert_response :success
+ assert_equal downloads_ordered_tag1, assigns(:documents).to_a
end
test 'sort by views' do
@@ -1021,7 +1035,17 @@ class DocumentsControllerTest < ActionController::TestCase
Factory(:activity_log, action: 'show', activity_loggable: d6, created_at: 4.minutes.ago)
Factory(:activity_log, action: 'show', activity_loggable: d5, created_at: 3.minutes.ago)
+ d1.annotate_with('tag1', 'tag', d1.contributor)
+ d3.annotate_with('tag1', 'tag', d3.contributor)
+ d6.annotate_with('tag1', 'tag', d6.contributor)
+ disable_authorization_checks do
+ d1.save!
+ d3.save!
+ d6.save!
+ end
+
views_ordered = [d4, d3, d6, d5, d1, d2]
+ views_ordered_tag1 = [d3, d6, d1]
get :index
assert_select '#index_sort_order' do
@@ -1031,6 +1055,10 @@ class DocumentsControllerTest < ActionController::TestCase
get :index, params: { order: 'views_desc' }
assert_response :success
assert_equal views_ordered, assigns(:documents).to_a
+
+ get :index, params: { filter: { tag: 'tag1' }, order: 'views_desc' }
+ assert_response :success
+ assert_equal views_ordered_tag1, assigns(:documents).to_a
end
test 'filtering a scoped collection' do
diff --git a/test/functional/isa_assays_controller_test.rb b/test/functional/isa_assays_controller_test.rb
index 722b50b465..a8d3d52e41 100644
--- a/test/functional/isa_assays_controller_test.rb
+++ b/test/functional/isa_assays_controller_test.rb
@@ -25,6 +25,8 @@ def setup
projects = User.current_user.person.projects
inv = Factory(:investigation, projects: projects, contributor: User.current_user.person)
study = Factory(:study, investigation_id: inv.id, contributor: User.current_user.person)
+ other_creator = Factory(:person)
+ this_person = User.current_user.person
source_sample_type = Factory(:simple_sample_type, title: 'source sample_type')
@@ -41,6 +43,8 @@ def setup
assert_difference('SampleType.count', 1) do
post :create, params: { isa_assay: { assay: { title: 'test', study_id: study.id,
sop_ids: [Factory(:sop, policy: Factory(:public_policy)).id],
+ creator_ids: [this_person.id, other_creator.id],
+ other_creators: 'other collaborators',
position: 0, assay_class_id: 1, policy_attributes: policy_attributes },
input_sample_type_id: sample_collection_sample_type.id,
sample_type: { title: 'assay sample_type', project_ids: [projects.first.id], template_id: 1,
@@ -61,8 +65,8 @@ def setup
} } } }
end
end
- i = assigns(:isa_assay)
- assert_redirected_to controller: 'single_pages', action: 'show', id: i.assay.projects.first.id,
+ isa_assay = assigns(:isa_assay)
+ assert_redirected_to controller: 'single_pages', action: 'show', id: isa_assay.assay.projects.first.id,
params: { notice: 'The ISA assay was created successfully!',
item_type: 'assay', item_id: Assay.last.id }
@@ -71,6 +75,16 @@ def setup
sample_multi = sample_types[1].sample_attributes.detect(&:seek_sample_multi?)
assert_equal "Input (#{title})", sample_multi.title
+
+ assert_equal [this_person, other_creator], isa_assay.assay.creators
+ assert_equal 'other collaborators', isa_assay.assay.other_creators
+ end
+
+ test 'author form partial uses correct nested param attributes' do
+ get :new, params: { study_id: Factory(:study, contributor: User.current_user.person) }
+ assert_response :success
+ assert_select '#author-list[data-field-name=?]','isa_assay[assay][assets_creators_attributes]'
+ assert_select '#isa_assay_assay_other_creators'
end
test 'should show new when parameters are incomplete' do
@@ -97,10 +111,12 @@ def setup
assert_template :new
end
- test 'should edit isa assay' do
+ test 'should update isa assay' do
person = User.current_user.person
project = person.projects.first
investigation = Factory(:investigation, projects: [project])
+ other_creator = Factory(:person)
+
source_type = Factory(:isa_source_sample_type, contributor: person, projects: [project])
sample_collection_type = Factory(:isa_sample_collection_sample_type, contributor: person, projects: [project],
@@ -112,18 +128,18 @@ def setup
sops: [Factory(:sop, policy: Factory(:public_policy))],
sample_types: [source_type, sample_collection_type])
- assay = Factory(:assay, study: study, contributor: person)
- put :update, params: { id: assay, isa_assay: { assay: { title: 'assay title' } } }
- assert_redirected_to single_page_path(id: project, item_type: 'assay', item_id: assay.id)
- assert flash[:error].include?('Resource not found.')
-
assay = Factory(:assay, study: study, sample_type: assay_type, contributor: person)
- put :update, params: { id: assay, isa_assay: { assay: { title: 'assay title', sop_ids: [Factory(:sop, policy: Factory(:public_policy)).id] },
+
+ put :update, params: { id: assay, isa_assay: { assay: { title: 'assay title', sop_ids: [Factory(:sop, policy: Factory(:public_policy)).id],
+ creator_ids: [person.id, other_creator.id], other_creators: 'other collaborators' },
sample_type: { title: 'sample type title' } } }
isa_assay = assigns(:isa_assay)
assert_equal 'assay title', isa_assay.assay.title
assert_equal 'sample type title', isa_assay.sample_type.title
assert_redirected_to single_page_path(id: project, item_type: 'assay', item_id: assay.id)
+
+ assert_equal [person, other_creator], isa_assay.assay.creators
+ assert_equal 'other collaborators', isa_assay.assay.other_creators
end
end
diff --git a/test/functional/people_controller_test.rb b/test/functional/people_controller_test.rb
index 0a92fc040f..08f8987aa1 100644
--- a/test/functional/people_controller_test.rb
+++ b/test/functional/people_controller_test.rb
@@ -706,7 +706,7 @@ def test_should_add_nofollow_to_links_in_show_page
assert_select '.pagination-container li.active', text: '1'
assert_select '.list_items_container .collapse', count: 3
-
+
get :index, params: { view: 'table' }
assert_response :success
assert_equal 3, assigns(:per_page)
@@ -824,6 +824,25 @@ def test_should_add_nofollow_to_links_in_show_page
end
end
+ test 'should show empty programme as related item if programme administrator' do
+ person1 = Factory(:programme_administrator_not_in_project)
+ prog1 = Factory(:min_programme, programme_administrators: [person1])
+
+ assert person1.projects.empty?
+
+ get :show, params: { id: person1.id }
+ assert_response :success
+
+ assert_select 'h2', text: /Related items/i
+ assert_select 'div.list_items_container' do
+ assert_select 'div.list_item' do
+ assert_select 'div.list_item_title' do
+ assert_select 'a[href=?]', programme_path(prog1), text: prog1.title
+ end
+ end
+ end
+ end
+
test 'related investigations should show where person is creator' do
person = Factory(:person)
inv1 = Factory(:investigation, contributor: Factory(:person), policy: Factory(:public_policy))
diff --git a/test/functional/programmes_controller_test.rb b/test/functional/programmes_controller_test.rb
index 97df7a3b80..9bbfc6b892 100644
--- a/test/functional/programmes_controller_test.rb
+++ b/test/functional/programmes_controller_test.rb
@@ -837,4 +837,75 @@ def rdf_test_object
end
end
+ test 'people programmes through nested routing' do
+ assert_routing 'people/2/programmes', controller: 'programmes', action: 'index', person_id: '2'
+ admin = Factory(:admin)
+ person = Factory(:programme_administrator)
+ programme = person.programmes.first
+ project = Factory(:project)
+ person.add_to_project_and_institution(project, Factory(:institution))
+ programme2 = Factory(:programme, projects: [project])
+ programme3 = Factory(:programme)
+ person.save!
+ person.reload
+ assert_equal [programme, programme2], person.related_programmes
+
+ get :index, params: { person_id: person.id }
+ assert_response :success
+ assert_select 'div.list_item_title' do
+ assert_select 'a[href=?]', programme_path(programme), text: programme.title
+ assert_select 'a[href=?]', programme_path(programme2), text: programme2.title
+ assert_select 'a[href=?]', programme_path(programme3), text: programme3.title, count: 0
+ end
+
+ # inactive should be hidden from non admins
+ programme.update_column(:is_activated, false)
+
+ get :index, params: { person_id: person.id }
+ assert_response :success
+ assert_select 'div.list_item_title' do
+ assert_select 'a[href=?]', programme_path(programme), text: programme.title, count: 0
+ assert_select 'a[href=?]', programme_path(programme2), text: programme2.title
+ assert_select 'a[href=?]', programme_path(programme3), text: programme3.title, count: 0
+ end
+
+ login_as(person)
+ get :index, params: { person_id: person.id }
+ assert_response :success
+ assert_select 'div.list_item_title' do
+ assert_select 'a[href=?]', programme_path(programme), text: programme.title
+ assert_select 'a[href=?]', programme_path(programme2), text: programme2.title
+ assert_select 'a[href=?]', programme_path(programme3), text: programme3.title, count: 0
+ end
+
+ login_as(admin)
+ get :index, params: { person_id: person.id }
+ assert_response :success
+ assert_select 'div.list_item_title' do
+ assert_select 'a[href=?]', programme_path(programme), text: programme.title
+ assert_select 'a[href=?]', programme_path(programme2), text: programme2.title
+ assert_select 'a[href=?]', programme_path(programme3), text: programme3.title, count: 0
+ end
+ end
+
+ test 'Empty programmes should show programme administrators as related people' do
+ person1 = Factory(:programme_administrator_not_in_project)
+ person2 = Factory(:programme_administrator_not_in_project)
+ prog1 = Factory(:min_programme, programme_administrators: [person1, person2])
+
+ assert person1.projects.empty?
+
+ get :show, params: { id: prog1.id }
+ assert_response :success
+
+ assert_select 'h2', text: /Related items/i
+ assert_select 'div.list_items_container' do
+ assert_select 'div.list_item' do
+ assert_select 'div.list_item_title' do
+ assert_select 'a[href=?]', person_path(person1), text: person1.title
+ assert_select 'a[href=?]', person_path(person2), text: person2.title
+ end
+ end
+ end
+ end
end
diff --git a/test/functional/sharing/batch_sharing_change_test.rb b/test/functional/sharing/batch_sharing_change_test.rb
index c2449b72b5..13a0a521f1 100644
--- a/test/functional/sharing/batch_sharing_change_test.rb
+++ b/test/functional/sharing/batch_sharing_change_test.rb
@@ -92,7 +92,6 @@ def setup
test 'should bulk change sharing permissions of selected items' do
-
model = Factory(:model, contributor: @person, projects: [@person.projects.first], policy: Factory(:private_policy))
df = Factory(:data_file, contributor: @person, policy: Factory(:private_policy))
@@ -110,7 +109,7 @@ def setup
params[:share_not_isa][model.class.name][model.id.to_s] = '1'
params[:share_isa][df.class.name]||= {}
params[:share_isa][df.class.name][df.id.to_s] = '1'
-
+ params[:share_isa]['Banana'] = { '123' => '1' } # Should be ignored
# batch change sharing policy and grant other_people manage right
params[:policy_attributes] = {access_type: Policy::NO_ACCESS, permissions_attributes: {'1' => {contributor_type: 'Person', contributor_id: other_person.id, access_type: Policy::MANAGING}}}
@@ -128,11 +127,8 @@ def setup
assert !df.can_view?
assert !model.can_download?
assert !df.can_download?
-
end
-
-
private
def bulk_create_sharing_assets
diff --git a/test/functional/studies_controller_test.rb b/test/functional/studies_controller_test.rb
index 93a193e9e6..2d54a17361 100644
--- a/test/functional/studies_controller_test.rb
+++ b/test/functional/studies_controller_test.rb
@@ -697,12 +697,12 @@ def test_should_show_investigation_tab
assert_difference('Study.count') do
investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
study_attributes = { title: 'test', investigation_id: investigation.id }
- cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id,
+ cm_attributes = {custom_metadata_attributes:{ custom_metadata_type_id: cmt.id,
data:{
"name":'fred',
"age":22}}}
- put :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
end
assert study=assigns(:study)
@@ -731,7 +731,6 @@ def test_should_show_investigation_tab
assert_equal 'max', new_study.custom_metadata.get_attribute_value('name')
assert_equal '20', new_study.custom_metadata.get_attribute_value('age')
assert_equal old_id, new_study.custom_metadata.id
-
end
test 'create a study with custom metadata validated' do
@@ -862,7 +861,7 @@ def test_should_show_investigation_tab
"apple list":['Granny Smith','Bramley'],
"apple controlled vocab": 'Granny Smith'}}}
- put :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
end
assert study=assigns(:study)
@@ -880,6 +879,260 @@ def test_should_show_investigation_tab
assert_select 'p',text:/Granny Smith/, count:2
end
+ test 'should create and update study with linked custom metadata type' do
+
+ cmt = Factory(:role_custom_metadata_type)
+ login_as(Factory(:person))
+ linked_cmt = cmt.attributes_with_linked_custom_metadata_type.first.linked_custom_metadata_type
+
+ # test create
+ assert_difference('Study.count') do
+ assert_difference('CustomMetadata.count',2) do
+ investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+ study_attributes = { title: 'Alice in Wonderland', investigation_id: investigation.id }
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id, data: {
+ "role_email":"alice@email.com",
+ "role_phone":"0012345",
+ "role_name": {
+ custom_metadata_type_id:linked_cmt.id,
+ custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id,
+ data:{
+ "first_name":"alice",
+ "last_name": "liddell"
+ }
+ }
+ }
+ }
+ }
+
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ end
+ end
+
+ assert study = assigns(:study)
+ assert cm = study.custom_metadata
+ assert_equal cmt, cm.custom_metadata_type
+ assert_equal "alice@email.com",cm.get_attribute_value('role_email')
+ assert_equal '0012345',cm.get_attribute_value('role_phone')
+ assert_equal 'alice', cm.linked_custom_metadatas.first.get_attribute_value('first_name')
+ assert_equal 'liddell', cm.linked_custom_metadatas.first.get_attribute_value('last_name')
+
+ # test show
+ get :show, params:{ id:study}
+ assert_response :success
+
+
+ # test update
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass",
+ custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id, id:cm.id, data: {
+ "role_email":"rabbit@email.com",
+ "role_name":{
+ custom_metadata_type_id: linked_cmt.id,
+ custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id,
+ id: cm.linked_custom_metadatas.first.id,
+ data:{
+ "first_name":"rabbit"
+ }
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+
+ assert new_study = assigns(:study)
+ assert_equal 'Alice Through the Looking Glass', new_study.title
+ assert_equal 'rabbit@email.com', new_study.custom_metadata.get_attribute_value('role_email')
+ assert_equal 'rabbit', new_study.custom_metadata.linked_custom_metadatas.first.get_attribute_value('first_name')
+ end
+
+ test 'should create and update study which has multiple custom metadata attributes, which link to the same custom metadata type' do
+ cmt = Factory(:family_custom_metadata_type)
+ login_as(Factory(:person))
+ linked_cmts = cmt.attributes_with_linked_custom_metadata_type
+ assert_difference('Study.count') do
+ assert_difference('CustomMetadata.count',4) do
+ investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+ study_attributes = { title: 'Family', investigation_id: investigation.id }
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id, data: {
+ "dad": {
+ custom_metadata_type_id:linked_cmts[0].linked_custom_metadata_type.id,
+ custom_metadata_attribute_id:linked_cmts[0].id,
+ data:{
+ "first_name":"john",
+ "last_name": "liddell"
+ }
+ },
+ "mom": {
+ custom_metadata_type_id:linked_cmts[1].linked_custom_metadata_type.id,
+ custom_metadata_attribute_id:linked_cmts[1].id,
+ data:{
+ "first_name":"lily",
+ "last_name": "liddell"
+ }
+ },
+ "child": {
+ custom_metadata_type_id:linked_cmts[2].linked_custom_metadata_type.id,
+ custom_metadata_attribute_id:linked_cmts[2].id,
+ data:{
+ "first_name":"alice",
+ "last_name": "liddell"
+ }
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ end
+ end
+
+ assert study = assigns(:study)
+ assert cm = study.custom_metadata
+ assert_equal cmt, cm.custom_metadata_type
+
+ assert_equal "john",cm.linked_custom_metadatas[0].get_attribute_value('first_name')
+ assert_equal "liddell",cm.linked_custom_metadatas[0].get_attribute_value('last_name')
+ assert_equal "lily",cm.linked_custom_metadatas[1].get_attribute_value('first_name')
+ assert_equal "alice",cm.linked_custom_metadatas[2].get_attribute_value('first_name')
+
+ # test show
+ get :show, params:{ id:study}
+ assert_response :success
+
+ # test update
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass",
+ custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id, id:cm.id, data: {
+ "dad": {
+ custom_metadata_type_id:linked_cmts[0].linked_custom_metadata_type.id,
+ custom_metadata_attribute_id:linked_cmts[0].id,
+ data:{
+ "first_name":"tom",
+ "last_name": "liddell"
+ }
+ },
+ "child": {
+ custom_metadata_type_id:linked_cmts[2].linked_custom_metadata_type.id,
+ custom_metadata_attribute_id:linked_cmts[2].id,
+ data:{
+ "first_name":"rabbit",
+ "last_name": "wonderland"
+ }
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+ assert new_study = assigns(:study)
+ cm = new_study.custom_metadata
+
+ assert_equal "tom",cm.linked_custom_metadatas[0].get_attribute_value('first_name')
+ assert_equal "liddell",cm.linked_custom_metadatas[0].get_attribute_value('last_name')
+ assert_equal "lily",cm.linked_custom_metadatas[1].get_attribute_value('first_name')
+ assert_equal "liddell",cm.linked_custom_metadatas[1].get_attribute_value('last_name')
+ assert_equal "rabbit",cm.linked_custom_metadatas[2].get_attribute_value('first_name')
+ assert_equal "wonderland",cm.linked_custom_metadatas[2].get_attribute_value('last_name')
+
+
+
+ end
+
+ test 'should create and update study with multiple linked custom metadata types' do
+ cmt = Factory(:role_multiple_custom_metadata_type)
+ login_as(Factory(:person))
+ linked_name_cmt = cmt.attributes_with_linked_custom_metadata_type.first.linked_custom_metadata_type
+ linked_addr_cmt = cmt.attributes_with_linked_custom_metadata_type.last.linked_custom_metadata_type
+ # test create
+ assert_difference('Study.count') do
+ assert_difference('CustomMetadata.count',3) do
+ investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person)
+ study_attributes = { title: 'Alice in Wonderland', investigation_id: investigation.id }
+ cm_attributes = { custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id, data: {
+ "role_email":"alice@email.com",
+ "role_phone":"0012345",
+ "role_name": {
+ custom_metadata_type_id:linked_name_cmt.id,
+ custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id,
+ data:{
+ "first_name":"alice",
+ "last_name": "liddell"
+ }
+ },
+ "role_address": {
+ custom_metadata_type_id:linked_addr_cmt.id,
+ custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.last.id,
+ data:{
+ "street":"wonder",
+ "city": "land"
+ }
+ }
+ }
+ }
+ }
+ post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing }
+ end
+ end
+
+ assert study = assigns(:study)
+ assert cm = study.custom_metadata
+ assert_equal cmt, cm.custom_metadata_type
+ assert_equal "alice@email.com",cm.get_attribute_value('role_email')
+ assert_equal '0012345',cm.get_attribute_value('role_phone')
+ assert_equal 'alice', cm.linked_custom_metadatas.first.get_attribute_value('first_name')
+ assert_equal 'liddell', cm.linked_custom_metadatas.first.get_attribute_value('last_name')
+ assert_equal 'wonder', cm.linked_custom_metadatas.last.get_attribute_value('street')
+ assert_equal 'land', cm.linked_custom_metadatas.last.get_attribute_value('city')
+
+ # test show
+ get :show, params:{ id:study}
+ assert_response :success
+
+
+ # test update
+ assert_no_difference('Study.count') do
+ assert_no_difference('CustomMetadata.count') do
+ put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass",
+ custom_metadata_attributes: {
+ custom_metadata_type_id: cmt.id, id:cm.id, data: {
+ "role_email":"rabbit@email.com",
+ "role_name":{
+ custom_metadata_type_id: linked_name_cmt.id,
+ custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id,
+ id: cm.linked_custom_metadatas.first.id,
+ data:{
+ "first_name":"rabbit"
+ }
+ }
+ }
+ }
+ }
+ }
+ end
+ end
+
+
+ assert new_study = assigns(:study)
+ assert_equal 'Alice Through the Looking Glass', new_study.title
+ assert_equal 'rabbit@email.com', new_study.custom_metadata.get_attribute_value('role_email')
+ assert_equal 'rabbit', new_study.custom_metadata.linked_custom_metadatas.first.get_attribute_value('first_name')
+
+
+
+ end
+
+
test 'experimentalists only shown if set' do
person = Factory(:person)
login_as(person)
diff --git a/test/functional/workflows_controller_test.rb b/test/functional/workflows_controller_test.rb
index 802f574d55..7f806a11cd 100644
--- a/test/functional/workflows_controller_test.rb
+++ b/test/functional/workflows_controller_test.rb
@@ -1599,4 +1599,60 @@ def bad_generator.write_graph(struct)
assert_redirected_to login_path
assert flash[:error].include?('need to be logged in')
end
+
+ test 'lists creators in index in condensed and table views' do
+ Workflow.delete_all
+
+ person = Factory(:person, first_name: 'Jessica', last_name: 'Three')
+ workflow = Factory(:public_workflow, other_creators: 'Joy Five')
+ disable_authorization_checks do
+ workflow.assets_creators.create!(given_name: 'Julia', family_name: 'Two', pos: 2, affiliation: 'University of Sheffield', orcid: 'https://orcid.org/0000-0001-8172-8981')
+ workflow.assets_creators.create!(creator: person, pos: 3)
+ workflow.assets_creators.create!(given_name: 'Jill', family_name: 'One', pos: 1)
+ workflow.assets_creators.create!(given_name: 'Jane', family_name: 'Four', pos: 4, affiliation: 'University of Edinburgh')
+ end
+
+ get :index, params: { view: 'condensed' }
+ assert_response :success
+ assert_select '#resource-condensed-view .list_item', count: 1
+ assert_select '#resource-condensed-view .list_item .rli-head' do
+ assert_select '.rli-condensed-attribute', text: 'Creators: Jill One, Julia Two, Jessica Three, Jane Four, Joy Five'
+ assert_select '.rli-condensed-attribute' do
+ assert_select ':nth-child(2)', text: 'Jill One'
+
+ assert_select ':nth-child(3)', text: 'Julia Two'
+ assert_select ':nth-child(3)[title=?]', 'Julia Two, University of Sheffield'
+ assert_select ':nth-child(3)[href=?]', 'https://orcid.org/0000-0001-8172-8981'
+
+ assert_select ':nth-child(4)', text: 'Jessica Three'
+ assert_select ':nth-child(4)[href=?]', person_path(person)
+
+ assert_select ':nth-child(5)', text: 'Jane Four'
+ assert_select ':nth-child(5)[title=?]', 'Jane Four, University of Edinburgh'
+ end
+ end
+
+ get :index, params: { view: 'table' }
+ assert_response :success
+ assert_select '.list_items_container tbody tr', count: 1
+ assert_select '.list_items_container tbody tr' do
+ assert_select 'td', text: 'Jill One, Julia Two, Jessica Three, Jane Four, Joy Five'
+ assert_select 'td' do
+ assert_select ':nth-child(1)', text: 'Jill One'
+
+ assert_select ':nth-child(2)', text: 'Julia Two'
+ assert_select ':nth-child(2)[title=?]', 'Julia Two, University of Sheffield'
+ assert_select ':nth-child(2)[href=?]', 'https://orcid.org/0000-0001-8172-8981'
+
+ assert_select ':nth-child(3)', text: 'Jessica Three'
+ assert_select ':nth-child(3)[href=?]', person_path(person)
+
+ assert_select ':nth-child(4)', text: 'Jane Four'
+ assert_select ':nth-child(4)[title=?]', 'Jane Four, University of Edinburgh'
+ end
+ end
+
+ # Reset the view parameter
+ session.delete(:view)
+ end
end
diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb
index 55292c12ad..487f374f05 100644
--- a/test/integration/routing_test.rb
+++ b/test/integration/routing_test.rb
@@ -1,7 +1,7 @@
require 'test_helper'
# tests related to general routes, that are not tied to a particular controller
-class ScheduleTest < ActionDispatch::IntegrationTest
+class RoutingTest < ActionDispatch::IntegrationTest
test 'related items routes' do
# searchable_types covers all creatable types, plus some others that can be displayed and my have related items
diff --git a/test/integration/schedule_test.rb b/test/integration/schedule_test.rb
index 2e84330580..875b1b53e6 100644
--- a/test/integration/schedule_test.rb
+++ b/test/integration/schedule_test.rb
@@ -13,21 +13,21 @@ class ScheduleTest < ActionDispatch::IntegrationTest
weekly = pop_task(runners, "PeriodicSubscriptionEmailJob.new('weekly').queue_job")
monthly = pop_task(runners, "PeriodicSubscriptionEmailJob.new('monthly').queue_job")
assert daily
- assert_equal [1.day], daily[:every]
+ assert_equal [1.day, { at: '12:00am' }], daily[:every]
assert weekly
- assert_equal [1.week], weekly[:every]
+ assert_equal [1.week, { at: '12:00am' }], weekly[:every]
assert monthly
- assert_equal [1.month], monthly[:every]
+ assert_equal [1.month, { at: '12:00am' }], monthly[:every]
- # ContentBlob cleaner
- cleaner = pop_task(runners, "RegularMaintenanceJob.perform_later")
- assert cleaner
- assert_equal [RegularMaintenanceJob::RUN_PERIOD], cleaner[:every]
+ # RegularMaintenanceJob
+ regular = pop_task(runners, "RegularMaintenanceJob.perform_later")
+ assert regular
+ assert_equal [RegularMaintenanceJob::RUN_PERIOD, { at: '1:00am' }], regular[:every]
# LifeMonitor status
lm_status = pop_task(runners, "LifeMonitorStatusJob.perform_later")
assert lm_status
- assert_equal [LifeMonitorStatusJob::PERIOD], lm_status[:every]
+ assert_equal [LifeMonitorStatusJob::PERIOD, { at: '2:00am' }], lm_status[:every]
# Newsfeed refresh
news_refresh = pop_task(runners, "NewsFeedRefreshJob.set(priority: 3).perform_later")
@@ -47,7 +47,7 @@ class ScheduleTest < ActionDispatch::IntegrationTest
# Galaxy::ToolMap.instance.refresh
tool_map_refresh = pop_task(runners, "Galaxy::ToolMap.instance.refresh")
assert tool_map_refresh
- assert_equal [1.day], tool_map_refresh[:every]
+ assert_equal [1.day, { at: '3:00am' }], tool_map_refresh[:every]
assert_empty runners, "Found untested runner(s) in schedule"
end
@@ -92,6 +92,36 @@ class ScheduleTest < ActionDispatch::IntegrationTest
end
end
+ test 'should offset daily job runtime by configured amount' do
+ plus_43_schedule = nil
+ with_config_value(:regular_job_offset, 43) do
+ plus_43_schedule = Whenever::Test::Schedule.new(file: 'config/schedule.rb')
+ end
+ plus_43_runners = plus_43_schedule.jobs[:runner]
+
+ minus_237_schedule = nil
+ with_config_value(:regular_job_offset, -237) do
+ minus_237_schedule = Whenever::Test::Schedule.new(file: 'config/schedule.rb')
+ end
+ minus_237_runners = minus_237_schedule.jobs[:runner]
+
+ # For jobs that are not run daily, such as this one, which is run every 4 hours, only the minute offsets are applied.
+ assert_equal [RegularMaintenanceJob::RUN_PERIOD, { at: '1:43am' }],
+ pop_task(plus_43_runners, "RegularMaintenanceJob.perform_later")[:every]
+ assert_equal [RegularMaintenanceJob::RUN_PERIOD, { at: '9:03pm' }],
+ pop_task(minus_237_runners, "RegularMaintenanceJob.perform_later")[:every]
+
+ assert_equal [LifeMonitorStatusJob::PERIOD, { at: '2:43am' }],
+ pop_task(plus_43_runners, "LifeMonitorStatusJob.perform_later")[:every]
+ assert_equal [LifeMonitorStatusJob::PERIOD, { at: '10:03pm' }],
+ pop_task(minus_237_runners, "LifeMonitorStatusJob.perform_later")[:every]
+
+ assert_equal [1.day, { at: '3:43am' }],
+ pop_task(plus_43_runners, "Galaxy::ToolMap.instance.refresh")[:every]
+ assert_equal [1.day, { at: '11:03pm' }],
+ pop_task(minus_237_runners, "Galaxy::ToolMap.instance.refresh")[:every]
+ end
+
private
def pop_task(runners, task)
diff --git a/test/unit/config_test.rb b/test/unit/config_test.rb
index 870064cf9b..d49311914e 100644
--- a/test/unit/config_test.rb
+++ b/test/unit/config_test.rb
@@ -358,6 +358,14 @@ class ConfigTest < ActiveSupport::TestCase
refute setting[:encrypted_value].include?(password)
end
+ test 'set enable_starttls_auto to false' do
+ Seek::Config.set_smtp_settings 'enable_starttls_auto', false
+
+ # must be false and not nil
+ refute_nil ActionMailer::Base.smtp_settings[:enable_starttls_auto]
+ refute ActionMailer::Base.smtp_settings[:enable_starttls_auto]
+ end
+
test 'doi_prefix, doi_suffix' do
assert_equal '10.5072', Seek::Config.doi_prefix
assert_equal 'Sysmo.SEEK', Seek::Config.doi_suffix
diff --git a/test/unit/custom_metadata_attribute_test.rb b/test/unit/custom_metadata_attribute_test.rb
index d8bdb673f5..559651cde5 100644
--- a/test/unit/custom_metadata_attribute_test.rb
+++ b/test/unit/custom_metadata_attribute_test.rb
@@ -74,6 +74,11 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase
refute attribute.validate_value?('Granny Smith')
refute attribute.validate_value?(['Peter','Granny Smith'])
+
+ attribute = CustomMetadataAttribute.new(title: 'role', sample_attribute_type: Factory(:custom_metadata_sample_attribute_type),
+ linked_custom_metadata_type: Factory(:role_name_custom_metadata_type))
+ assert attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?('first name')
+ refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?(nil)
end
test 'validate value with required' do
diff --git a/test/unit/helpers/resource_list_helper_test.rb b/test/unit/helpers/resource_list_helper_test.rb
index b9b880b982..0db9d7844f 100644
--- a/test/unit/helpers/resource_list_helper_test.rb
+++ b/test/unit/helpers/resource_list_helper_test.rb
@@ -12,7 +12,7 @@ class ResourceListHelperTest < ActionView::TestCase
event = Factory(:event)
assert event.default_table_columns.count >= 3
html = resource_list_condensed_row(event)
- assert_equal 3, html.scan(/div class=\"col-sm-3\"/).count
+ assert_equal 3, html.scan(/div class=\"rli-condensed-attribute\"/).count
end
test 'resource_list_column_display_value' do
diff --git a/test/unit/person_test.rb b/test/unit/person_test.rb
index 7a2274d460..908e758131 100644
--- a/test/unit/person_test.rb
+++ b/test/unit/person_test.rb
@@ -75,6 +75,25 @@ def test_work_groups
refute_includes person1.programmes, prog2
end
+ test 'show related empty programmes' do
+ person1 = Factory(:programme_administrator_not_in_project)
+ person2 = Factory(:programme_administrator_not_in_project)
+ person3 = Factory(:programme_administrator_not_in_project) # Programme administrator not in empty_programme1
+ empty_programme1 = Factory(:min_programme, programme_administrators: [person1, person2])
+
+ [person1, person2].each do |p|
+ assert_includes p.related_programmes, empty_programme1
+ end
+ refute_includes person3.related_programmes, empty_programme1
+
+ person4 = Factory(:person_in_project) # Member of a project in prog 2, not a programme administrator
+ prog2 = Factory(:programme, projects: person4.projects, programme_administrators: [person1, person3])
+
+ [person1, person3, person4].each do |p|
+ assert_includes p.related_programmes, prog2
+ end
+ end
+
test 'can be administered by' do
admin = Factory(:admin)
admin2 = Factory(:admin)
diff --git a/test/unit/programme_test.rb b/test/unit/programme_test.rb
index 17b21cc775..1c536b50a0 100644
--- a/test/unit/programme_test.rb
+++ b/test/unit/programme_test.rb
@@ -572,6 +572,15 @@ class ProgrammeTest < ActiveSupport::TestCase
assert closed_programme.can_associate_projects?
end
end
+ end
+
+ test 'get related people of empty programmes' do
+ person1 = Factory(:programme_administrator_not_in_project)
+ person2 = Factory(:programme_administrator_not_in_project)
+ prog = Factory(:min_programme, programme_administrators: [person1, person2])
+ [person1, person2].each do |p|
+ assert_includes prog.related_people, p
+ end
end
end
diff --git a/test/unit/samples/base_types_test.rb b/test/unit/samples/base_types_test.rb
index dc66ef9636..782fc181d2 100644
--- a/test/unit/samples/base_types_test.rb
+++ b/test/unit/samples/base_types_test.rb
@@ -2,7 +2,7 @@
class BaseTypeTest < ActiveSupport::TestCase
test 'all types' do
- assert_equal %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList).sort,
+ assert_equal %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList LinkedCustomMetadata).sort,
Seek::Samples::BaseType::ALL_TYPES.sort
end
@@ -20,6 +20,7 @@ class BaseTypeTest < ActiveSupport::TestCase
assert_equal 'CV', Seek::Samples::BaseType::CV
assert_equal 'SeekDataFile',Seek::Samples::BaseType::SEEK_DATA_FILE
assert_equal 'CVList',Seek::Samples::BaseType::CV_LIST
+ assert_equal 'LinkedCustomMetadata',Seek::Samples::BaseType::LINKED_CUSTOM_METADATA
end
test 'valid?' do
|