6 Technische Umsetzung
Die nachfolgenden Abschnitte erweitern die Nutzerhilfe um die Beschreibung der technischen Umsetzung ausgewählter Elemente der Web-Applikation. Die ausgewählten Elemente sollen dabei insbesondere eine Vielzahl des verwendeteten Methodenspektrums darlegen, sodass eine nachhaltige Nutzung über die Laufzeit des Projektes hinaus erleichtert wird. Darüber hinaus sollen interessante Ansätze vorgestellt werden.
6.1 Struktur der Web-Applikation
Strukturell handelt es sich bei der Web-Applikation um eine Sammlung verschiedener Dateien innerhalb eines Ordners. Der Einstiegspunkt in die Web-Applikation ist die Datei app.R
. Alle anderen Dateien werden zur Laufzeit der Web-Applikation eingebunden. Die Web-Applikation wird gestartet, indem der Shiny Server die Datei app.R
ausführt. In app.R
werden Initialisierungen durchgeführt und die Funktionen ui
und server
definiert. Die Datei endet mit dem Aufruf shinyApp(ui, server)
, wobei die ui
-Funktion das visuelle Layout der Web-Applikation beschreibt und die server
-Funktion Eingaben verarbeitet. Mithilfe von sogenannten Modulen kann der Code strukturiert werden. Jedes Modul setzt sich dabei wiederum aus einer ui
- und einer server
-Funktion zusammen. Module bilden Teilaspekte, die unter Umständen wiederverwendet werden können, ab. [36]
6.1.1 Struktur von app.R
Wie bereits beschrieben, ist die Datei app.R
der Einstiegspunkt der Web-Applikation. Da sie Einfluss auf das Verhalten vieler weiterer Module hat, ist ihr Aufbau näher zu betrachten. Zur Übersicht werden die Inhalte verkürzt dargestellt.
- Laden benötigter Packages mit
library()
. Die Mehrzahl aller Packages wird über den::
-Operator referenziert. Nur die Packages, die zwangsläufig mitlibrary()
geladen werden müssen, also Packages, die funktionsrelevanten Code mit dem Aufruf vonlibrary()
verbinden, werden hier geladen.
library(shiny)
library(shinyjs)
library(dplyr)
library(qrcode)
- Die Funktion
source_directory()
wird manuell geladen und danach dazu verwendet, alle.R
-Dateien in den Ordnernmodules
unddb/func
einzubinden.
source("init/source_directory.R")
source_directory(
path = "modules",
encoding = "UTF-8",
modifiedOnly = FALSE,
chdir = TRUE,
recursive = TRUE,
envir = if (source_to_globalenv) globalenv() else environment()
)
- Die
ui
-Funktion bindet alle CSS- und JavaScript-Dateien ein und aktiviert spezielle Packages. Die Funktioncontainer_ui()
, die das Layout des Dashboardes festlegt, wird aufgerufen. Incontainer_ui()
wird für jeden Reiter eine eigeneui
-Funktion aufgerufen.
# UI -----------------------------------------------------------------------
<- htmltools::tagList(
ui ::includeScript("www/js/dark-mode.js"),
htmltools::includeCSS("www/css/styles.css")
htmltoolscontainer_ui(
id = "container"
),::rclipboardSetup(),
rclipboard::useShinyjs(),
shinyjs::use_waiter()
waiter )
- In der
server
-Funktion wird die.values
-Environment angelegt. Diese enthält die in Tabelle 6.1 aufgelisteten Elemente.
Name | Beschreibung |
---|---|
query$type |
Aus Query-String ausgelesene Typ-ID |
settings |
Liste, die Namenslängen festlegt und Dictionaries enthält |
update |
Liste, die reactiveVal() s enthält, die bei Datenaktualisierung getriggert werden |
user |
Liste, die Informationen zum angemeldeten Nutzer enthält |
yaml |
Inhalt von app.yml |
Diese Environment wird jeder server
-Funktion übergeben, sodass die Werte in jeder server
-Funktion verfügbar sind.
- In der
server
-Funktion vonapp.R
wird dieserver
-Funktioncontainer_server()
aufgerufen.
6.1.2 Ordnerstruktur
.gitignore
Index aller Dateien, die nicht der Versionskontrolle unterliegenapp.R
Einstiegspunkt in die Web-Applikationapp.yml
Konfigurationsdateidb/
db.sqlite
Datenbankfunc
Funktionssammlung zur Interaktion mit der Datenbank
files/
Dateiensammlung für Dateiverwaltung. Enthält drei Unterordner für Gruppen, Typen und Untertypen. Jeder dieser Unterordner enthält für jedes Element der jeweiligen Kategorie einen Ordner mit der Identifikationsnummer des jeweiligen Elementes als Nameninit/source_directory.R
Hilfsfunktion, die beim Start der Web-Applikation alle.R
-Dateien einliestmodules/
Shiny-Module und sonstige Funktionalitätencontainer.R
Definition des Dashboardsdt_options.R
Optionen fürDT::datatable
object
Generalisierte Module für Gruppen, Typen und Untertypen (z.B. Element hinzufügen, umbenennen etc.)sidebar_menu.R
Definition der Sidebartab_file_management
Dateiverwaltungtab_group
Gruppentab_login
Anmeldungtab_operate
Ausleihen & Zurückgebentab_qrcode
QR-Codetab_reporting
Bestandsinformationtab_settings
Einstellungentab_type
Typentab_user_management
Nutzerverwaltungutils.R
Hilfsfunktionen
renv
,renv.lock
Package-Managementwww/
css/
CSS-Dateienfavicon.ico
Sensotheka-Iconjs/
JavaScript-Dateien
6.2 Datenbank
Die Datenbank ist eine SQLite-Datenbank. Sie liegt in db/db.sqlite
. Der Zugriff erfolgt über das Package {DBI} [19].
6.2.1 Struktur
Alle Tabellen enthalten die Spalte rowid
, die den Primärschlüssel der jeweiligen Tabelle enthält. Diese kann somit zur eindeutigen Identifikation einer Zeile verwendet werden. Die Ablage der zu speichernden Werte erfolgt in Ergänzung dazu über weitere Spalten, die in den folgenden Unterkapiteln näher beschrieben werden. Die Beschränkung Einzigartig bezieht sich immer nur auf die nicht gelöschten Elemente (removed = 0
).
6.2.1.1 circulation
Spalte | Einschränkungen | Beschreibung |
---|---|---|
user_id | Fremdschlüssel | Identifikationsnummer des ausführenden Nutzers |
subtype_id | Fremdschlüssel | Identifikationsnummer des bearbeiteten Untertyps |
quantity | Nicht-negativ | Bearbeitete Menge |
time | Zeitpunkt der Transaktion | |
op_type | 1 oder 2 |
Transaktionsart: 1 - Ausleihen und Zurückgeben, 2 - Bestandsänderungen |
6.2.1.2 groups
Spalte | Einschränkungen | Beschreibung |
---|---|---|
group_name | Einzigartig | Gruppenname |
removed | 0 oder 1 |
0 - existent, 1 - gelöscht |
6.2.1.3 group_type
Spalte | Einschränkungen | Beschreibung |
---|---|---|
group_id | Fremdschlüssel | Identifikationsnummer der Gruppe |
type_id | Fremdschlüssel | Identifikationsnummer des Typs |
6.2.1.4 subtype
Spalte | Einschränkungen | Beschreibung |
---|---|---|
type_id | Fremdschlüssel | Identifikationsnummer des Typs |
subtype_name | Einzigartig innerhalb eines Typs | Untertypenname |
quantity | Nicht-negativ | Bestandsmenge |
removed | 0 oder 1 |
0 - existent, 1 - gelöscht |
6.2.1.5 type
Spalte | Einschränkungen | Beschreibung |
---|---|---|
type_name | Einzigartig | Typname |
removed | 0 oder 1 |
0 - existent, 1 - gelöscht |
6.2.1.6 user
Spalte | Einschränkungen | Beschreibung |
---|---|---|
hash | Verhashter Nutzername (notwendig für Cookies) | |
name | Einzigartig | Nutzername |
status | admin , mod oder user |
Nutzerrolle |
password | Verhashtes Passwort | |
added_from | Nutzeridentifikationsnummer des Hinzufügenden | |
time_added | Zeitpunkt der Kontoeröffnung | |
time_current_logged | Zeitpunkt der letzten Anmeldung | |
time_previous_logged | Zeitpunkt der vorletzten Anmeldung | |
times_logged | Anzahl der Anmeldungen | |
removed | 0 oder 1 |
0 - existent, 1 - gelöscht |
6.2.2 Zugriff
Der Zugriff auf die Datenbank erfolgt, wie beschrieben, über das Package {DBI}[19] und soll hier exemplarisch vorgeführt werden. Die Verbindung der Datenbank und R könnte dabei folgendermaßen aussehen:
library(DBI)
library(RSQLite)
# Verbinde die Datenbank mit R
<- dbConnect(SQLite(), "db/db.sqlite")
db
# Tabellennamen
dbListTables(db)
## [1] "circulation" "group_type" "groups" "subtype" "type" "user"
Beispielhaft wird die Tabelle circulation
betrachtet. Diese Tabelle speichert alle Transaktionen, die von Nutzern durchgeführt worden sind, also zum Beispiel Ausleihen, Rückgaben und Mengenänderungen.
dbReadTable(db, "circulation")
user_id | subtype_id | quantity | time | op_type |
---|---|---|---|---|
1 | 2 | 24 | 2021-02-18 18:38:00 | 2 |
1 | 3 | 12 | 2021-02-18 18:38:04 | 2 |
1 | 4 | 5 | 2021-02-18 18:38:07 | 2 |
1 | 5 | 8 | 2021-02-18 18:38:12 | 2 |
1 | 6 | 14 | 2021-02-18 18:38:16 | 2 |
1 | 11 | 4 | 2021-02-18 18:40:14 | 2 |
1 | 12 | 3 | 2021-02-18 18:41:09 | 2 |
1 | 17 | 112 | 2021-02-18 18:41:40 | 2 |
1 | 1 | 45 | 2021-02-18 19:38:35 | 2 |
4 | 7 | 6 | 2021-02-18 19:40:53 | 1 |
Der Ordner db/func/
enthält eine Sammlung von über 80 Hilfsfunktionen, die zum Erstellen, Abfragen und Modifizieren der Datenbank verwendet werden. Die Interaktion mit der Datenbank erfolgt ausschließlich über diese Hilfsfunktionen. Dadurch werden Redundanzen ausgeschlossen und es ist darüber hinaus einfacher, die korrekte Funktionalität zu gewährleisten.
Beispielhaft wird die Funktion db_get_borrowed_quantity(db, subtype_id)
betrachtet. Unter Angabe der Datenbank db
und einer oder mehrerer Untertypenidentifikationsnummern subtype_id
wird die ausgeliehene Menge dieser Untertypen zurückgegeben. In {DBI} werden Abfragen an die Datenbank mithilfe von dbGetQuery()
gestellt. Das Resultat der Abfrage wird anschließend weiterverarbeitet. Der Nutzen der Hilfsfunktion wird zusätzlich dadurch verdeutlicht, dass sowohl die abzufragende Tabelle sowie die beteiligten Zeilen und Spalten nicht gesondert angegeben werden müssen.
# Funktionsdefinition
<- function(db, subtype_id) {
db_get_borrowed_quantity <- DBI::dbGetQuery(
borrowed
db,"SELECT SUM(quantity) AS borrowed FROM circulation
WHERE subtype_id = ? AND op_type = 1",
params = list(subtype_id)
$borrowed
)
ifelse(is.na(borrowed), 0, borrowed)
}
# Abfrage der ausgeliehenen Menge für mehrere Untertypen
db_get_borrowed_quantity(db, 1:5)
## [1] 0 13 0 0 2
6.4 Deployment
Der Shiny Server liegt auf einer virtuellen Maschine (VirtualBox). Auf der virtuellen Maschine ist das Betriebssystem Ubuntu 20.04.2 LTS ohne grafische Benutzeroberfläche installiert. Änderungen am Shiny Server werden erst wirksam, nachdem der Shiny Server neugestartet wurde. Dazu kann folgender Befehl verwendet werden: sudo systemctl restart shiny-server
.
Nachfolgend wird auf Ordner verwiesen, in denen für die Web-Applikation relevante Dateien liegen.
/etc/shiny-server
Dieser Ordner enthält die Datei
shiny-server.conf
, mit der der Shiny Server konfiguriert werden kann [39]. Hier kann der Port eingestellt werden, unter dem die Web-Applikation verfügbar gemacht wird. Der Port3838
ist voreingestellt.
/srv/shiny-server/Sensotheka
Dieser Ordner enthält das Git-Repository, das die tatsächliche Web-Applikation darstellt. Es verweist auf das GitHub-Repository
https://github.com/PFA-WebApp/App.git
als Remote mit Namenorigin
. In der Dateiapp.yml
müssen die in Tabelle 6.9 aufgelisteten Einstellungen vorgenommen werden:Tabelle 6.9: Einstellungen in app.yml
Einstellung Beschreibung showcase yes
für Showcasemodus (Passwörter für Standardnutzer werden eingeblendet, Standardnutzer können nicht gelöscht werden),no
(voreingestellt) für Betriebsmodusurl Basis-URL auf welche QR-Codes verweisen (hier sind Anpassungen zwingend notwendig)
/etc/rstudio
Dieser Ordner enthält die Datei
rserver.conf
, mit der der RStudio Server konfiguriert werden kann [40]. Hier kann der Port eingestellt werden, unter dem der RStudio Server verfügbar gemacht wird. Der Port8787
ist voreingestellt. Der RStudio Server kann zur nachhaltigen Pflege und Weiterentwicklung der Web-Applikation genutzt werden. Dazu muss der Port aufgerufen werden. In der Login-Maske kann sich mithilfe des Nutzerspfa
und eines zugehörigen Passworts eingeloggt werden. Danach öffnet sich die Online-Version der Entwicklungsumgebung RStudio, deren Funktionsumfang mit dem der Desktopversion identisch ist.Für weitere Informationen siehe https://docs.rstudio.com/ide/server-pro/. Es ist zu beachten, dass es sich bei der installierten Version um die Open-Source-Version und nicht um die Pro-Version handelt.
/var/log/shiny-server/Sensotheka
Dieser Ordner enthält Log-Dateien, die vom Shiny Server erzeugt werden, wenn Komplikationen im Betrieb auftreten. Sollte das der Fall sein, ist es ratsam, diese zunächst zu konsultieren, bevor mit der Fehlerbehandlung begonnen wird.