diff options
author | Orangerot <purple@orangerot.dev> | 2024-05-24 17:42:08 +0200 |
---|---|---|
committer | Orangerot <purple@orangerot.dev> | 2024-05-24 17:47:22 +0200 |
commit | 7fcdc1c788725f866de71fc9dfd8c4d1cb132b57 (patch) | |
tree | 89931c85ae3f149884ba02c69862558e93f01531 /20-implementierungsheft/sections |
Diffstat (limited to '20-implementierungsheft/sections')
-rw-r--r-- | 20-implementierungsheft/sections/anforderungsanalyse.tex | 185 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/apidoc.tex | 191 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/aufbau.tex | 47 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/backend.tex | 28 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/changes.tex | 241 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/einleitung.tex | 11 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/features.tex | 43 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/features.tex.orig | 82 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/frontend.tex | 196 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/glossar.tex | 371 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/methodology.tex | 16 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/tests.tex | 21 | ||||
-rw-r--r-- | 20-implementierungsheft/sections/timeline.tex | 7 |
13 files changed, 1439 insertions, 0 deletions
diff --git a/20-implementierungsheft/sections/anforderungsanalyse.tex b/20-implementierungsheft/sections/anforderungsanalyse.tex new file mode 100644 index 0000000..9af8d4d --- /dev/null +++ b/20-implementierungsheft/sections/anforderungsanalyse.tex @@ -0,0 +1,185 @@ +\newcommand{\newrequirementlist}[1]{ + % https://www.overleaf.com/learn/latex/Lists#Creating_a_new_list_with_enumitem + \newlist{#1list}{enumerate}{1} + \setlist[#1list, 1] + { + before=\leavevmode, + label=\upshape\textlangle #1\arabic*\textrangle, + ref=\upshape\textlangle #1\arabic*\textrangle, + resume=#1list + } +} + +\newrequirementlist{RM} +\newrequirementlist{RS} +\newrequirementlist{RC} +\newrequirementlist{RW} + +\section{Anforderungsanalyse} + +\subsection{ Musskriterien }\label{r:musskriterien} + +Musskriterien: unabdingbare Leistungen der Software. + +\subsubsection*{ Funktionale Anforderungen } + +\begin{RMlist} + \item\label{r:login} Der Benutzer kann sich im Webfrontend mit einer + E-Mail-Adresse und einem Pass\-wort erstmalig registrieren und bei + abgeschlossener Registrierung fortan mit denselben Informationen + anmelden. + Für eine erfolgreiche Registrierung muss die angegebene + E-Mail-Adresse zuerst verifiziert werden.\\ + \item\label{r:store} Die Liste der \Glspl{abo} eines Benutzers sowie + der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder begonnen + \Gls{episode} werden für jeden Benutzer gespeichert. + \item\label{r:sync} Die Liste der \Glspl{abo} eines Benutzers + sowie der zeitliche Fortschritt beim Anhören(/Ansehen) von jeder + begonnenen \Gls{episode} wird automatisch über alle von einem Benutzer + verknüpften \Gls{podcatcher} aktualisiert. + Dabei sind der zu synchronisierende Stand der \Glspl{abo} und der + zeitliche Fortschritt jeweils definiert als derjenige Stand, der + zeitlich am kürzesten zurückliegt.\\ + \item\label{r:ui} Das Webfrontend bietet dem Benutzer eine graphische + Benutzeroberfläche zur Navigation und zur Ansteuerung einzelner + Funktionalitäten.\\ + \item\label{r:reset-pw} Der Benutzer kann sein Passwort ändern und es + gibt eine ,,Passwort vergessen''-Funktion. + So kann ein angemeldeter Benutzer sein Passwort direkt im Webfrontend + ändern. + Im nicht angemeldeten Zustand kann der Benutzer sein Passwort über + die registrierte E-Mail-Adresse zurücksetzen.\\ + \item\label{r:show-podcasts} Das Webfrontend bietet dem Benutzer die + Möglichkeit, sich die Liste seiner \Glspl{abo} anzeigen zu + lassen. + Die dabei dargestellten Informationen beinhalten den Namen des + \Glspl{abo} und eine gerundete Angabe darüber, wie lange es her ist, + dass der Benutzer das letzte Mal eine \Gls{episode} dieses \Glspl{abo} + konsumiert hat.\\ +\end{RMlist} + +\subsubsection*{ Nicht-funktionale Anforderungen } + +\begin{RMlist} + \item\label{r:requests} Der Synchronisations-Server kann mindestens + 50 Anfragen pro Sekunde verarbeiten.\\ + \item\label{r:desktop-first} Das Webfrontend ist primär für + Desktop-Benutzer ausgelegt. + \item\label{r:gpodder} Der Datenaustausch erfolgt über die Gpodder + \Gls{rest-api} unter Verwendung des Datenformats \Gls{json}. + \item\label{r:persistent-storage} Die Speicherung der Daten eines + Benutzers \ref{r:store} über den Synchronisations-Server erfolgt + persistent in einer \Gls{db}. Diese Daten des Benutzers sind die + Liste seiner \Glspl{abo} und der zeitliche Fortschritt beim Anhören + (/Ansehen) aller begonnenen \Glspl{episode}. + \item\label{r:api-extension} Die \Gls{gpodder} wird um Funktionalitäten + zur verbesserten Kommunikation zwischen Front- und Backend erweitert + (siehe \ref{r:login}).\\ +\end{RMlist} + + +\subsection{ Sollkriterien }\label{r:sollkriterien} + +Sollkriterien: erstrebenswerte Leistungen. + +\subsubsection*{ Funktionale Anforderungen } + +\begin{RSlist} + \item\label{r:man} Das Webfrontend bietet die Möglichkeit eine nicht + ausgefüllte Benutzeranleitung für das Synchronisieren von \Glspl{podcast} + anzuzeigen.\\ + \item\label{r:delete-acc} Der Benutzer kann seinen Account löschen. + Daraufhin werden alle auf diesen Benutzer bezogenen Daten gelöscht.\\ +\end{RSlist} + +\subsubsection*{ Nicht-funktionale Anforderungen } + +\begin{RSlist} + \item\label{r:backend-libs} Das Backend wird in \Gls{java} unter Verwendung des + quelloffenen Frameworks \Gls{spring} implementiert. Weiter wird für die + \Gls{db} das relationale Open-Source Datenbankverwaltungssystem MariaDB + eingesetzt. + \item\label{r:ui-libs} Die Weboberfläche wird mithilfe der + \Gls{ui-lib} React oder des Webframeworks Vue in JavaScript und + mit dem Frontend-CSS-Framework Bootstrap entwickelt. + \item\label{r:ui-source} + Verwendete \Glspl{ui-lib} werden von einem \Gls{packagemanager}, wie dem Node + Package Manager (npm) bezogen. Ein \Gls{bundler}, wie vite oder Webpack, + stellt ein minimiertes Skript von den Teilen der Bibliotheken zusammen, + die vom Code verwendet werden. Das minimierte Skript wird dann auf einem + eigenen Server für die Weboberfläche bereitgestellt. + \item\label{r:spa} Die Weboberfläche wird als \Gls{spa} + entworfen und aktualisiert dynamisch ihren Inhalt, sobald es eine + Antwort auf eine Anfrage an die \Gls{gpodder} \ref{r:api-compat} erhält. + \item\label{r:parse-metadata} Das Backend kann die Metadaten von + \Gls{podcast} aus + deren \Gls{rss}-Feeds (XML-Dateien) für die Anzeige im Webfrontend + \ref{r:show-podcasts} parsen. + \item\label{r:pw-requirements} Verwendete Passwörter müssen mindestens 8 Zeichen, + ein Sonderzeichen, eine Zahl sowie einen Klein- und einen Großbuchstaben + enthalten. + Diese Anforderungen gelten also insbesondere für über die Funktionen + \ref{r:login} und \ref{r:reset-pw} neu gewählte Passwörter.\\ + \item\label{r:save-pw} Passwörter werden sicher mittels \Gls{salt-hash} + gespeichert. + \item\label{r:session} Im Webfrontend angemeldete Benutzer bleiben dort + angemeldet. Hierfür wird eine Kombination aus einem \Gls{session-token} und + einem \Gls{cookie} verwendet.\\ +\end{RSlist} + +\subsection{ Kannkriterien } + +Kannkriterien: Leistungen, die enthalten sein können. + +\subsubsection*{ Funktionale Anforderungen } + +\begin{RClist} + \item\label{r:subscribe} Ein Benutzer kann über die Weboberfläche einen + abonnierten \Gls{podcast} über einen generierten Link teilen. + Öffnet nun ein anderer Nutzer den Link wird dieser zur Weboberfläche + weitergeleitet und mit einem Pop-up gefragt, ob dieser den + \Gls{podcast} abonnieren + möchte, falls noch nicht geschehen. + Akzeptiert der Nutzer, so wird der \Gls{podcast} zur Liste der + \Glspl{abo} des + Nutzers hinzugefügt. + Gegebenenfalls muss sich der Benutzer dafür zuerst anmelden. + Der Link setzt sich dabei unter anderem aus der URL des Webfrontends oder + einem \Gls{pseudoprotocol} und dem \Gls{podcast}-Link des Providers zusammen. + \item\label{r:unsubscribe} Das Webfrontend bietet dem Benutzer die Möglichkeit, + \Glspl{abo} zu entfernen beziehungsweise \Glspl{podcast} zu deabonnieren. + \item\label{r:import} Das Importieren und Exportieren aller benutzerbezogenen + Daten wird unterstützt (siehe \ref{r:dsgvo}). + \item\label{r:import-other} Das Umsiedeln von anderen \Gls{gpodder}-Plattformen und + damit insbesondere der damit verbundene Datenimport wird unterstützt. + \item\label{r:api-compat} Die Weboberfläche ist kompatibel mit beliebigen + \Glspl{gpodder}. + \item\label{r:responsive} Die Weboberfläche ist \gls{responsive}. + \item\label{r:admin} Es gibt Administrator Benutzerkonten. Eine angestrebte + Funktionalität dieser privilegierten Konten ist das Einsehen von Statistiken, + wie der Anzahl von Benutzern, und dem Abruf der Metadaten eines + \Glspl{abo}. +\end{RClist} + +\subsubsection*{ Nicht-funktionale Anforderungen } + +\begin{RClist} + \item\label{r:login-provider} Die Anmeldung im Webfrontend kann mit dem + offenen Protokoll \Gls{oauth} 2.0 über Google, Apple oder Facebook erfolgen. + Die bei der Verknüpfung eines \Gls{podcatcher}s mit dem Synchronisationsserver + geforderten Anmeldedaten werden dann automatisch für den betreffenden + Benutzer generiert. + Diese kann er im Webfrontend einsehen. + \item\label{r:live-update} Im Webfrontend angemeldete Benutzer bleiben dort + angemeldet, wenn das Backend ein Update bekommt. + \item\label{r:language} Die Benutzeroberfläche kann in mehreren Sprachen + angezeigt werden, wobei neben der standardmäßig deutschen + Benutzeroberfläche die zusätzliche Bereitstellung einer englischen + Version gegenüber anderen Fremdsprachen priorisiert angestrebt wird. + \item\label{r:dsgvo} Der Umgang mit personenbezogenen Daten ist konform mit + der \\\Gls{dsgvo} der Europäischen Union. + \item\label{r:docker} Die Benutzung von \Gls{docker} vereinfacht das Deployment auf + einen Server, da Abhängigkeiten bereits im \Gls{docker}-Image enthalten sind. + Außerdem bleibt bei einer Kompromittierung der Software das Host-System + durch Virtualisierung der Container sicher.\\ +\end{RClist} diff --git a/20-implementierungsheft/sections/apidoc.tex b/20-implementierungsheft/sections/apidoc.tex new file mode 100644 index 0000000..0cce48c --- /dev/null +++ b/20-implementierungsheft/sections/apidoc.tex @@ -0,0 +1,191 @@ +\newenvironment{urlParameter} +{ + \newcommand{\urlParamItem}[2] + { + \rowcolor{\methodLightColor} ##1 & ##2 \\ + } + \newcommand{\noUrlParameter}[1] + { + \small{\textit{##1}} + } + %\vspace{-0.61em} + + \arrayrulecolor{\methodColor} + + \begin{tabularx}{\textwidth}{X} + \rowcolor{\methodLightColor!20} + \textbf{URL-Parameter} \\ \hline + \end{tabularx} + + \tabularx{\textwidth}{l X} +} + +\newenvironment{pathParameter} +{ + \newcommand{\pathParamItem}[2] + { + \rowcolor{\methodLightColor} ##1 & ##2 \\ + } + \newcommand{\noPathParameter}[1] + { + \small{\textit{##1}} + } + %\vspace{-0.61em} + + \arrayrulecolor{\methodColor} + + \begin{tabularx}{\textwidth}{X} + \rowcolor{\methodLightColor!20} + \textbf{Pfad-Parameter} \\ \hline + \end{tabularx} + + \tabularx{\textwidth}{l X} +} + +\newenvironment{jsonKeys} +{ + \newcommand{\jsonKeyItem}[2] + { + \rowcolor{\methodLightColor} ##1 & ##2 \\ + } + \newcommand{\nojsonKeys}[1] + { + \small{\textit{##1}} + } + %\vspace{-0.61em} + + \arrayrulecolor{\methodColor} + + \begin{tabularx}{\textwidth}{X} + \rowcolor{\methodLightColor!20} + \textbf{Json-Keys} \\ \hline + \end{tabularx} + + \tabularx{\textwidth}{l X} +} + +\section{\Gls{api}} + +\subsection{Authentication API}\label{a:auth} + +\subsubsection{Registrierung}\label{a:register} + +\begin{apiRoute}{post}{/api/2/auth/register.json} + {Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort. + + Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.} + \begin{routeRequest}{application/json} + \begin{routeRequestBody} +{ + username: "jeff" + email: "jeff@example.com", + password: "MyNameIsJeff" +} + \end{routeRequestBody} + \end{routeRequest} + \begin{routeResponse}{application/json} + \begin{routeResponseItem}{200} + {OK: Nutzer wurde erfolgreich angelegt und E-Mail versendet.} + \end{routeResponseItem} + + \begin{routeResponseItem}{400} + {Bad Request: Fehler beim Parsen oder Eingabe nicht anforderungsgemäß.} + \end{routeResponseItem} + \end{routeResponse} +\end{apiRoute} + +Es wird nun sowohl ein Benutzername als auch eine E-Mail-Adresse für einen Nutzer gespeichert. +Der Benutzername wird in der Folge für die Authentifizierung und die Zuordnung der Anfragen verwendet. +Die E-Mail-Adresse wird vor dem Speichern mit einem festen Geheimschlüssel gesalted und gehashed. +Sie ist zum Ableich der bei der bei (ref an forgot) anzugebenden E-Mail-Adresse + +\newpage +\subsubsection{E-Mail verifizieren}\label{a:resetpassword} + +\begin{apiRoute}{get}{/api/2/auth/\{username\}/verify.json} + {Verifiziere die bei der Registrierung angegebene E-Mail-Adresse durch diese, per E-Mail versendete, URL.} + \begin{pathParameter} + \pathParamItem{username}{Nutzername des betreffenden Nutzers} + \end{pathParameter} + \begin{urlParameter} + \urlParamItem{token}{JSON-Web-Token (24h gültig)} + \end{urlParameter} + \begin{routeResponse}{application/json} + \begin{routeResponseItem}{200} + {OK: Der Benutzer wurde erfolgreich aktiviert und kann sich nun anmelden.} + \end{routeResponseItem} + + \begin{routeResponseItem}{400} + {Bad Request: Der Nutzer mit dem angegebenen Namen ist bereits verifiziert. } + \end{routeResponseItem} + + \begin{routeResponseItem}{401} + {Unauthorized: Der JWT ist ungültig. } + \end{routeResponseItem} + + \begin{routeResponseItem}{404} + {Not Found: Es exisitiert kein Nutzer mit dem angegebenen Benutzernamen. } + \end{routeResponseItem} + \end{routeResponse} +\end{apiRoute} + +Dieser Endpunkt wurde zur Verifizierung der bei der Registrierung angegebenen E-Mail-Adresse hinzugefügt. +Nach der Registrierung wird dem Benutzer eine E-Mail mit der URL dieses Endpunkts (inklusive Benutzernamen und JWT) +zugesendet. Klickt der Benutzer auf den Link wird die Anfrage im Backend verarbeitet und der Nutzer automatisch +zum Webfrontend weitergeleitet. Erst nach der Verifizierung der E-Mail-Adresse ist die Registrierung vollständig +abgeschlossen und der Account aktiviert - nun kann sich der Nutzer anmelden. + +\newpage +\subsubsection{Passwort vergessen}\label{a:forgot} + +\begin{apiRoute}{post}{/api/2/auth/\{email\}/forgot.json} + {Sende eine E-Mail zum Zurücksetzen des Passworts.} + \begin{pathParameter} + \pathParamItem{email}{E-Mail-Adresse des betreffenden Nutzers} + \end{pathParameter} + \begin{routeResponse}{application/json} + \begin{routeResponseItem}{200} + {OK: E-Mail wurde erfolgreich versendet.} + \end{routeResponseItem} + + \begin{routeResponseItem}{404} + {Not Found: Es exisitiert kein Nutzer mit der angegeben E-Mail-Adresse.} + \end{routeResponseItem} + \end{routeResponse} +\end{apiRoute} + +Die E-Mail-Adresse des Benutzers, der sein Passwort vergessen hat, wird nicht mehr im Request-Body +als \GLS{json}-Payload, sondern als Pfadvariable in der URL übergeben. + +\subsubsection{Passwort zurücksetzen}\label{a:resetpassword} + +\begin{apiRoute}{put}{/api/2/auth/\{username\}/resetpassword.json} + {Passwort des gegebenen Nutzers ändern nachdem dieser sein Passwort + vergessen hat. } + \begin{pathParameter} + \pathParamItem{username}{Nutzername des betreffenden Nutzers} + \end{pathParameter} + \begin{urlParameter} + \urlParamItem{token}{JSON-Web-Token} + \end{urlParameter} + \begin{routeRequest}{application/json} + \begin{routeRequestBody} +{ + password: "APasswordIWontForgetAgain" +} + \end{routeRequestBody} + \end{routeRequest} + \begin{routeResponse}{application/json} + \begin{routeResponseItem}{200} + {OK: Das Passwort wurde erfolgreich geändert.} + \end{routeResponseItem} + + \begin{routeResponseItem}{400} + {Bad Request: Fehler beim Parsen der Anfragen. } + \end{routeResponseItem} + + \begin{routeResponseItem}{401} + {Unauthorized: JWT ist ungültig. } + \end{routeResponseItem} + \end{routeResponse} +\end{apiRoute}
\ No newline at end of file diff --git a/20-implementierungsheft/sections/aufbau.tex b/20-implementierungsheft/sections/aufbau.tex new file mode 100644 index 0000000..41a5839 --- /dev/null +++ b/20-implementierungsheft/sections/aufbau.tex @@ -0,0 +1,47 @@ +\section{Aufbau} + +\begin{landscape} + +\subsection{Klassendiagramm Backend} +Das Klassendiagramm zeigt alle für den Entwurf relevanten Klassen des Backends mit ihren öffentlichen Methoden. +Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver. + +% \input{assets/diagrams/classdiagram.latex} +\includegraphics[width=\linewidth]{assets/diagrams/classdiagram} +\end{landscape} + +\subsection{Sequenzdiagramme} + +\subsubsection{Authentication \Gls{api}} +\subsubsection*{Registrierung \scriptsize{(\ref{a:register})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-register} +\subsubsection*{Passwort vergessen und zurücksetzen \scriptsize{(\ref{a:forgot}, \ref{a:resetpassword})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-forgotAndResetPW} + +\subsubsection{Subscriptions \Gls{api}} +\subsubsection*{Abonnements hochladen \scriptsize{(\ref{a:uploadSubs})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadSubscriptions} + +\subsubsection*{Abrufen aller Abonnements \scriptsize{(\ref{a:getSubs})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getSubscriptions} + +\subsubsection{Episode Actions \Gls{api}} +\subsubsection*{Episode Actions hochladen \scriptsize{(\ref{a:uploadEpisodeActions})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-uploadEpisodeActions} + +\subsubsection*{Abrufen aller Episode Actions seit einem Zeitpunkt \scriptsize{(\ref{a:getEpisodeActions})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince} + +\subsubsection*{Abrufen aller Episode Actions \scriptsize{(\ref{a:getEpisodeActions})}} +\includegraphics[width=\textwidth]{assets/diagrams/sequencediagram-getEpisodeActions} + +\subsection{Komponentendiagramm Backend} +\includegraphics[width=\textwidth]{assets/diagrams/backendComponentDiagram} + +\subsection{Verteilungsdiagram} +\includegraphics[width=\textwidth]{assets/diagrams/deployment} + +\subsection{\Gls{db}-Modell} + +\includegraphics[width=\textwidth]{assets/diagrams/db} + diff --git a/20-implementierungsheft/sections/backend.tex b/20-implementierungsheft/sections/backend.tex new file mode 100644 index 0000000..19efd65 --- /dev/null +++ b/20-implementierungsheft/sections/backend.tex @@ -0,0 +1,28 @@ +\section{Backend} + +Für das Backend wird das \Gls{java}-Framework \Gls{spring} verwendet. Neben seiner Modularität, +bietet es viele Funktionen, die unter +anderem die Entwicklung von Backend-Anwendungen vereinfachen. +Darunter fällt zum Beispiel die Unterstützung von Dependency Injection, dessen +Vorteile bereits beschrieben wurden. +Außerdem unterstützt \Gls{java} \Gls{spring} intern eine Verwaltung von \Glspl{db}, sodass +sich nicht mit dem \Gls{SQL}-Code an sich befasst werden muss. +Auch bezüglich Authentifizierung und Sicherheit bietet \Gls{spring} eigene Funktionalitäten. + +Zusätzlich dazu wird als Build-System für das \Gls{java}-\Gls{spring}-Backend Maven verwendet. +Maven hilft dabei alle Abhängigkeiten des Projekts zu verwalten und automatisiert +den Build Prozess. +Durch die zusätzliche Unterstützung von Versionskontrollsystemen und der Kompatibilität +zu vielen Continuous Integration-Tools wird außerdem die Entwicklung in einem Team erleichtert +und optimiert. Denn dadurch können Build- und Deployment-Prozesse automatisiert werden. +Außerdem bietet Maven Bibliotheken zum Testen sowie zur Generierung von Dokumentationen an. + +Vom Backend benötigte Abhängigkeiten: +\begin{itemize} + \item \Gls{spring} Web + \item \Gls{spring} Security + \item \Gls{spring} Mail Sender + \item \Gls{spring} Data JPA + \item Lombok + \item Rome (\Gls{rss} parsing/fetching) +\end{itemize}
\ No newline at end of file diff --git a/20-implementierungsheft/sections/changes.tex b/20-implementierungsheft/sections/changes.tex new file mode 100644 index 0000000..20df017 --- /dev/null +++ b/20-implementierungsheft/sections/changes.tex @@ -0,0 +1,241 @@ +\newenvironment{urlParameter} +{ + \newcommand{\urlParamItem}[2] + { + \rowcolor{\methodLightColor} ##1 & ##2 \\ + } + \newcommand{\noUrlParameter}[1] + { + \small{\textit{##1}} + } + %\vspace{-0.61em} + + \arrayrulecolor{\methodColor} + + \begin{tabularx}{\textwidth}{X} + \rowcolor{\methodLightColor!20} + \textbf{URL-Parameter} \\ \hline + \end{tabularx} + + \tabularx{\textwidth}{l X} +} + +\newenvironment{pathParameter} +{ + \newcommand{\pathParamItem}[2] + { + \rowcolor{\methodLightColor} ##1 & ##2 \\ + } + \newcommand{\noPathParameter}[1] + { + \small{\textit{##1}} + } + %\vspace{-0.61em} + + \arrayrulecolor{\methodColor} + + \begin{tabularx}{\textwidth}{X} + \rowcolor{\methodLightColor!20} + \textbf{Pfad-Parameter} \\ \hline + \end{tabularx} + + \tabularx{\textwidth}{l X} +} + +\newenvironment{jsonKeys} +{ + \newcommand{\jsonKeyItem}[2] + { + \rowcolor{\methodLightColor} ##1 & ##2 \\ + } + \newcommand{\nojsonKeys}[1] + { + \small{\textit{##1}} + } + %\vspace{-0.61em} + + \arrayrulecolor{\methodColor} + + \begin{tabularx}{\textwidth}{X} + \rowcolor{\methodLightColor!20} + \textbf{Json-Keys} \\ \hline + \end{tabularx} + + \tabularx{\textwidth}{l X} +} + + +\section{Änderungen zum Entwurfsheft} + +Im Folgenden werden die Änderungen zum Entwurfsheft aufgelistet und erläutert warum diese +Änderungen gemacht wurden. + + +\subsection{Kompatibilität mit \Glspl{podcatcher}} + +Um die Kompatibilität mit \Glspl{podcatcher} - insbesondere AntennaPod und Kasts - sicherzustellen, mussten einige Änderungen vorgenommen werden. + +\subsubsection*{Speicherung von Benutzernamen und E-Mail-Adressen} + +AntennaPod erlaubt bei der Verknüpfung mit einem Synchronisations-Server nur die Anmeldung mit einem Benutzername, der keine E-Mail-Adresse ist. +Deshalb werden nun sowohl ein Benutzername als auch eine E-Mail-Adresse für jeden Nutzer gespeichert. +Der Benutzername wird dabei unverschlüsselt gespeichert. +Er wird zur Authentifizierung sowie für die Zuordnung der Anfragen verwendet. +Die E-Mail-Adresse hingegen, wird vor der Speicherung mit einem festen Geheimschlüssel gesalted und anschließend gehashed. +Sie existiert lediglich um bei einer Passwort-vergessen-Anfrage denjenigen Nutzer zu finden, zu dem die übergebene E-Mail-Adresse gehört, beziehungsweise dessen Existenz zu überprüfen. +Diese Änderung impliziert eine Anpassung des Formats, in dem Registrierungsanfragen als \GLS{json}-Payload übergeben werden. +Wie in der folgenden aktualisierten Spezifikation zu sehen existiert nun ein zusätzliches \GLS{json}-Attribut namens \enquote{username}. +\newline + +\begin{apiRoute}{post}{/api/2/auth/register.json} + {Registriert einen Nutzer mit einer E-Mail-Adresse und Passwort. + + Versendet E-Mail mit Bestätigungslink an die angegebene E-Mail-Adresse.} + \begin{routeRequest}{application/json} + \begin{routeRequestBody} +{ + "username": "jeff", + "email": "jeff@example.com", + "password": "MyNameIsJeff" +} + \end{routeRequestBody} + \end{routeRequest} + \begin{routeResponse}{application/json} + \begin{routeResponseItem}{200} + {OK: Nutzer wurde erfolgreich angelegt und E-Mail versendet.} + \end{routeResponseItem} + + \begin{routeResponseItem}{400} + {Bad Request: Fehler beim Parsen oder Eingabe nicht anforderungsgemäß.} + \end{routeResponseItem} + \end{routeResponse} +\end{apiRoute} + +\subsubsection*{Device API} + +Beim Einrichten eines Synchronisations-Servers rufen sowohl AntennaPod als auch Kasts statt einem anfänglichen Login sofort den List-Devices-Endpunkt der \gls{gpodder}.net API auf. +Dieser Endpunkt wurde entsprechend hinzugefügt. +Da jedoch explizit keine Unterscheidung von Geräten bei der Synchronisation unterstützt wird, wird dieser intern wie ein Login-Aufruf behandelt. +\newline + +\begin{apiRoute}{get}{/api/2/devices/\{username\}.json} + {Gegebenen Nutzer des gegebenen Geräts mithilfe HTTP Basic Auth einloggen oder Gültigkeit des im \enquote{sessionid} \Gls{cookie} gespeicherten JWTs bestätigen. + + Gibt außerdem eine Liste mit einem Dummy-Device zurück, damit die Einrichtung der Synchronisation mit AntennaPod und Kasts möglich ist.} + \begin{pathParameter} + \pathParamItem{username}{Nutzername des einzuloggenden Nutzers} + \end{pathParameter} + \begin{routeResponse}{application/json} + \begin{routeResponseItem}{200} + {OK: Der Benutzer wurde erfolgreich mittles HTTP Basic Auth oder JWT eingeloggt und das \enquote{sessionid} Cookie wurde auf ein gültiges JWT gesetzt.} + \newline + \begin{routeResponseItemBody} +[ + { + "id": "dummy", + "caption": "device", + "type": "other", + "subscriptions": 0 + } +] + \end{routeResponseItemBody} + \end{routeResponseItem} + + \begin{routeResponseItem}{401} + {Unauthorized: Es liegen falsche Anmeldedaten oder ein ungültiges JWT vor.} + \end{routeResponseItem} + \end{routeResponse} + \begin{jsonKeys} + \jsonKeyItem{id}{Geräte-ID} + \jsonKeyItem{caption}{Ein für Menschen lesbarer Name für das Gerät} + \jsonKeyItem{type}{Typ des Geräts - mögliche Typen: desktop, laptop, mobile, server, other} + \jsonKeyItem{subscriptions}{Anzahl der Subscriptions auf dem Gerät} + \end{jsonKeys} +\end{apiRoute} + +\newpage +\subsection{Verifizierung der E-Mail-Adresse} + +Dieser Endpunkt wurde zur Verifizierung der bei der Registrierung angegebenen E-Mail-Adresse hinzugefügt. +Nach der Registrierung wird dem Benutzer eine E-Mail mit der URL dieses Endpunkts (inklusive Benutzernamen und JWT) +zugesendet. Klickt der Benutzer auf den Link wird die Anfrage im Backend verarbeitet und der Nutzer automatisch +zum Webfrontend weitergeleitet. Erst nach der Verifizierung der E-Mail-Adresse ist die Registrierung vollständig +abgeschlossen und der Account aktiviert - nun kann sich der Nutzer anmelden. +\newline + +\begin{apiRoute}{get}{/api/2/auth/\{username\}/verify.json} + {Verifiziere die bei der Registrierung angegebene E-Mail-Adresse durch diese, per E-Mail versendete, URL.} + \begin{pathParameter} + \pathParamItem{username}{Nutzername des betreffenden Nutzers} + \end{pathParameter} + \begin{urlParameter} + \urlParamItem{token}{JSON-Web-Token (24h gültig)} + \end{urlParameter} + \begin{routeResponse}{application/json} + \begin{routeResponseItem}{200} + {OK: Der Benutzer wurde erfolgreich aktiviert und kann sich nun anmelden.} + \end{routeResponseItem} + + \begin{routeResponseItem}{400} + {Bad Request: Der Nutzer mit dem angegebenen Namen ist bereits verifiziert. } + \end{routeResponseItem} + + \begin{routeResponseItem}{401} + {Unauthorized: Der JWT ist ungültig. } + \end{routeResponseItem} + + \begin{routeResponseItem}{404} + {Not Found: Es exisitiert kein Nutzer mit dem angegebenen Benutzernamen. } + \end{routeResponseItem} + \end{routeResponse} +\end{apiRoute} + + +\newpage +\subsection{RSSParser} + +Das primäre Ziel beim Entwurf des RSSParsers war es den Rest der Anwendung nicht +aufzuhalten, da das fetchen und parsen länger dauert. Daher soll der RSSParser asynchron +ausgeführt werden. +Damit das für die Implementierung verwendete Framework \Gls{spring} dies unterstützt müssen +mehr Bedingungen erfüllt sein als im Entwurf berücksichtigt wurden, weshalb dieser abgeändert werden musste. + +Unter anderem können nur Komponenten die von \Gls{spring} verwaltet werden asynchron ausgeführt werden. +Weiter können nur öffentliche Methoden von \Gls{spring} als asynchron erkannt werden und bei +dem Aufruf einer asynchronen Methode muss die Klasse gewechselt werden damit diese asynchron +ausgeführt wird. + +Um diese Bedingungen zu erfüllen ruft der SubscriptionService oder der EpisodeActionService +die Validate Methode des RSSParsers mit der Subscription die überprüft werden +soll auf. Dies geschieht asynchron nach dem \enquote{Fire and Forget} Prinzip. Daher können +die Services unmittelbar weiter arbeiten und dem Nutzer so möglichst schnell eine Antwort +liefern. + +Die Validate Methode fragt den aktuellen \GLS{rss}-Feed der Subscription ab und parsed diesen. +Erfüllt der Feed die von Apple und Google für \Glspl{podcast} definierten Anforderungen +werden die Informationen aus dem Feed gespeichert. Dabei werden nur die \Glspl{episode} gespeichert, +die von mindestens einem Nutzer gehört wurden. Ist der Feed der Subscription nicht +valide wird die Subscription gelöscht. Um das Löschen und Speichern ausführen zu können +hält der Parser Referenzen auf das SubscriptionDao und EpisodeDao. + +Die im Entwurfsheft definierten Getter werden nicht mehr oder nur +noch als private Hilfsmethoden benötigt. + +\subsection{Reduzierte Datenzugriffsschicht} + +Mithilfe von JPA Repositories können Datenbankzugriffe und Abfragen ohne weitere Logik in den DAO-Schnittstellen einfach implementiert werden. +Wird beispielsweise nach einem \Gls{abo} anhand einer URL gesucht, so wird eine Methode der Form \textit{Optional<Subscription> findByUrl(String url)} in der SubscriptionDao deklariert. +Um die Implementierung dieser Abfrage kümmert sich JPA. + +Damit fallen alle ursprünglich geplanten DAO-Implementierungen weg, was für eine bessere Übersicht in der Datenzugriffsschicht sorgt. +\newpage + +\begin{landscape} + +\subsection{Überarbeitetes Klassendiagramm des Backends} +Das Klassendiagramm zeigt alle den überarbeiteten Entwurf des Backends. +Weiter zeigt das Diagramm die Aufteilung der Klassen in Pakete sowie schemenhaft dargestellte Verbindungen zu \Gls{db} und Webserver. + +% \input{assets/diagrams/classdiagram.latex} +\includegraphics[width=\linewidth]{assets/diagrams/class_after} +\end{landscape}
\ No newline at end of file diff --git a/20-implementierungsheft/sections/einleitung.tex b/20-implementierungsheft/sections/einleitung.tex new file mode 100644 index 0000000..5f6080d --- /dev/null +++ b/20-implementierungsheft/sections/einleitung.tex @@ -0,0 +1,11 @@ +\section{Einleitung} + +Im vorangegangenen Pflichtenheft und Entwurfsheft wurde zuerst abstrahiert +die Idee des Podcast Synchronisationsservers beschrieben und die Ziele in Form von +Anforderungen definiert. Dabei soll sowohl ein Backend mit \Gls{db} als auch ein Frontend +zur Dateneinsicht und Verwaltung entstehen. Dann wurde die Implementierung diese Projekts +mittels eines Entwurfs geplant. + +In diesem Dokument wird die Implementierung des entworfenen Produkts dokumentiert. +Dabei wird auf Probleme und Änderungen gegenüber dem Pflichtenheft und Entwurfsheft eingegangen, +die Testfälle erläutert und der geplante und tatsächliche zeitliche Ablauf der Implementierung dokumentiert.
\ No newline at end of file diff --git a/20-implementierungsheft/sections/features.tex b/20-implementierungsheft/sections/features.tex new file mode 100644 index 0000000..0ccf47e --- /dev/null +++ b/20-implementierungsheft/sections/features.tex @@ -0,0 +1,43 @@ +\section{Implementierte Muss-, Soll- und Kannkriterien} + +Nachdem nun die vorgenommenen Änderungen des Entwurfs behandelt wurden, geht es nun zu der eigentlichen Frage: +Was wurde umgesetzt? + +In der folgenden Tabelle werden alle im Pflichtenheft vorgestellten und im Entwurfsheft überarbeiteten Kriterien mit der Kriterienbezeichnung, einer kleinen Zusammenfassung und einer Info, ob die Kriterien implementiert wurden, aufgelistet. + +\begin{tabular}{l|c|c} + Bezeichner & Zusammenfassung & Implementiert\\\hline + RM1 & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\ + RM2 & Speichern von \Glspl{abo} und \Glspl{episode} auf dem Server & Ja\\ + RM3 & Synchronisierung zwischen \Glspl{podcatcher} & Ja\\ + RM4 & Eine Weboberfläche & Ja\\ + RM5 & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\ + RM6 & \Gls{abo}liste in der Weboberfläche & Ja\\ + RM7 & 50 Anfragen / Sekunde bearbeiten & Zu testen\\ + RM8 & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\ + RM9 & Unterstützung der \gls{gpodder}.net \Gls{rest-api} & Ja\\ + RM10 & Das Nutzen einer \Gls{db} zur Speicherung von Daten & Ja\\ + RM11 & Erweiterte \GLS{api} für Kommunikation zwischen Front- und Backend & Ja\\\hline + RS1 & Eine Anleitung (Platzhalter) & Ja\\ + RS2 & Die Möglichkeit einen Account zu löschen & Ja\\ + RS3 & \Gls{spring} für das Backend und MariaDB als \Gls{db} & Ja\\ + RS4 & Vue.js und Bootstrap für das Frontend & Ja\\ + RS5 & npm und vite für das Frontend & Ja\\ + RS6 & \makecell{Eine \Gls{spa} als Frontend\\mit dynamischer Aktualisierung} & Ja\\ + RS7 & Ein \GLS{rss}-Parser um Daten aus einem \GLS{rss}-Feed zu lesen & Ja\\ + RS8 & Mindestanforderungen an ein Passwort & Ja\\ + RS9 & \Gls{salt-hash} für Verschlüsselung der Personenbezogenen Daten & Ja\\ + RS10 & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja\\\hline + RC1 & Abonnierten \Gls{podcast} in Weboberfläche über Link teilen und hinzufügen & Ja\\ + RC2 & \Glspl{abo} in Weboberfläche deabonnieren & Nein\\ + RC3 & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\ + RC4 & Umsiedeln von anderen \Gls{gpodder}-Plattformen & Ja\\ + RC5 & Kompatible Weboberfläche für beliebige \gls{gpodder}.net APIs & Entfernt\\ + RC6 & \Gls{responsive} designte Weboberfläche & Ja\\ + RC7 & Administratorkonten mit privilegierten Funktionen & Nein\\ + RC8 & \Gls{oauth} 2.0 im Webfrontend & Nein\\ + RC9 & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\ + RC10 & Mehrsprachige Weboberfläche & Ja\\ + RC11 & Erfüllung der DSGVO & Teils\\ + RC12 & \Gls{docker} für einfaches Deployment und Sicherheit & Ja +\end{tabular}
\ No newline at end of file diff --git a/20-implementierungsheft/sections/features.tex.orig b/20-implementierungsheft/sections/features.tex.orig new file mode 100644 index 0000000..78839cf --- /dev/null +++ b/20-implementierungsheft/sections/features.tex.orig @@ -0,0 +1,82 @@ +\section{Implementierte Muss-, Soll- und Kannkriterien} + +Nachdem nun die vorgenommenen Änderungen des Entwurfs behandelt wurden, geht es nun zu der eigentlichen Frage: +Was wurde umgesetzt? + +In der folgenden Tabelle werden alle im Pflichtenheft vorgestellten und im Entwurfsheft überarbeiteten Kriterien mit der Kriterienbezeichnung, einer kleinen Zusammenfassung und einer Info, ob die Kriterien implementiert wurden, aufgelistet. + +\hspace{-1cm} +\begin{tabular}{l|c|c} +<<<<<<< HEAD + Bezeichner & Zusammenfassung & Implementiert\\\hline + \textlangle RM1 \textrangle & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\ + \textlangle RM2 \textrangle & Speichern von Abonnements und Episoden auf dem Server & Ja\\ + \textlangle RM3 \textrangle & Synchronisierung zwischen Podcatchern & Ja\\ + \textlangle RM4 \textrangle & Eine Weboberfläche & Ja\\ + \textlangle RM5 \textrangle & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\ + \textlangle RM6 \textrangle & Abonnementliste in der Weboberfläche & Ja\\ + \textlangle RM7 \textrangle & 50 Anfragen / Sekunde bearbeiten & Zu testen\\ + \textlangle RM8 \textrangle & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\ + \textlangle RM9 \textrangle & Unterstützung der gpodder.net RESTful-API & Ja\\ + \textlangle RM10\textrangle & Das Nutzen einer Datenbank zur Speicherung von Daten & Ja\\ + \textlangle RM11\textrangle & Erweiterte API für Kommunikation zwischen Front- und Backend & Ja\\\hline\hline + \textlangle RS1 \textrangle & Eine Anleitung (Platzhalter) & Ja\\ + \textlangle RS2 \textrangle & Die Möglichkeit einen Account zu löschen & Ja\\ + \textlangle RS3 \textrangle & Spring für das Backend und MariaDB als Datenbank & Ja\\ + \textlangle RS4 \textrangle & Vue.js und Bootstrap für das Frontend & Ja\\ + \textlangle RS5 \textrangle & npm und vite für das Frontend & Ja\\ + \textlangle RS6 \textrangle & \makecell{Eine Single-Page-Application als Frontend\\mit dynamischer Aktualisierung} & Ja\\ + \textlangle RS7 \textrangle & Ein RSS-Parser um Daten aus einem RSS-Feed zu lesen & Ja\\ + \textlangle RS8 \textrangle & Mindestanforderungen an ein Passwort & Ja\\ + \textlangle RS9 \textrangle & Salting und Hashing für Verschlüsselung der Personenbezogenen Daten & Ja\\ + \textlangle RS10\textrangle & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja\\\hline\hline + \textlangle RC1 \textrangle & Abonnierten Podcast in Weboberfläche über Link teilen und hinzufügen & Ja\\ + \textlangle RC2 \textrangle & Abonnements in Weboberfläche deabonnieren & Nein\\ + \textlangle RC3 \textrangle & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\ + \textlangle RC4 \textrangle & Umsiedeln von anderen Gpodder-Plattformen & Ja\\ + \textlangle RC5 \textrangle & Kompatible Weboberfläche für beliebige gpodder.net APIs & Entfernt\\ + \textlangle RC6 \textrangle & Responsive designte Weboberfläche & Ja\\ + \textlangle RC7 \textrangle & Administratorkonten mit privilegierten Funktionen & Nein\\ + \textlangle RC8 \textrangle & OAuth 2.0 im Webfrontend & Nein\\ + \textlangle RC9 \textrangle & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\ + \textlangle RC10\textrangle & Mehrsprachige Weboberfläche & Ja\\ + \textlangle RC11\textrangle & Erfüllung der DSGVO & Teils\\ + \textlangle RC12\textrangle & Docker für einfaches Deployment und Sicherheit & Ja +\end{tabular} +======= + Bezeichner & Zusammenfassung & Implementiert\\\hline + RM1 & \makecell{Registrierung, Bestätigung und Anmeldung\\ eines Accounts über das Frontend} & Ja\\ + RM2 & Speichern von \Glspl{abo} und \Glspl{episode} auf dem Server & Ja\\ + RM3 & Synchronisierung zwischen \Glspl{podcatcher} & Ja\\ + RM4 & Eine Weboberfläche & Ja\\ + RM5 & Möglichkeit das eigene Passwort zu ändern / zurückzusetzen & Ja\\ + RM6 & \Gls{abo}liste in der Weboberfläche & Ja\\ + RM7 & 50 Anfragen / Sekunde bearbeiten & Zu testen\\ + RM8 & Primäre Auslegung des Webfrontends für Desktop-Nutzer & Ja\\ + RM9 & Unterstützung der \gls{gpodder}.net \Gls{rest-api} & Ja\\ + RM10 & Das Nutzen einer \Gls{db} zur Speicherung von Daten & Ja\\ + RM11 & Erweiterte \GLS{api} für Kommunikation zwischen Front- und Backend & Ja\\\hline + RS1 & Eine Anleitung (Platzhalter) & Ja\\ + RS2 & Die Möglichkeit einen Account zu löschen & Ja\\ + RS3 & \Gls{spring} für das Backend und MariaDB als \Gls{db} & Ja\\ + RS4 & Vue.js und Bootstrap für das Frontend & Ja\\ + RS5 & npm und vite für das Frontend & Ja\\ + RS6 & \makecell{Eine \Gls{spa} als Frontend\\mit dynamischer Aktualisierung} & Ja\\ + RS7 & Ein \GLS{rss}-Parser um Daten aus einem \GLS{rss}-Feed zu lesen & Ja\\ + RS8 & Mindestanforderungen an ein Passwort & Ja\\ + RS9 & \Gls{salt-hash} für Verschlüsselung der Personenbezogenen Daten & Ja\\ + RS10 & Nutzer bleibt über JWT angemeldet und authentifiziert & Ja\\\hline + RC1 & Abonnierten \Gls{podcast} in Weboberfläche über Link teilen und hinzufügen & Ja\\ + RC2 & \Glspl{abo} in Weboberfläche deabonnieren & Nein\\ + RC3 & Importieren und Exportieren aller benutzerbezogenen Daten & Ja\\ + RC4 & Umsiedeln von anderen \Gls{gpodder}-Plattformen & Ja\\ + RC5 & Kompatible Weboberfläche für beliebige \gls{gpodder}.net APIs & Entfernt\\ + RC6 & \Gls{responsive} designte Weboberfläche & Ja\\ + RC7 & Administratorkonten mit privilegierten Funktionen & Nein\\ + RC8 & \Gls{oauth} 2.0 im Webfrontend & Nein\\ + RC9 & Bei Ausfall des Backends im Frontend angemeldet bleiben & Ja\\ + RC10 & Mehrsprachige Weboberfläche & Ja\\ + RC11 & Erfüllung der DSGVO & Teils\\ + RC12 & \Gls{docker} für einfaches Deployment und Sicherheit & Ja +\end{tabular} +>>>>>>> main diff --git a/20-implementierungsheft/sections/frontend.tex b/20-implementierungsheft/sections/frontend.tex new file mode 100644 index 0000000..ae5be0e --- /dev/null +++ b/20-implementierungsheft/sections/frontend.tex @@ -0,0 +1,196 @@ +\section{Weboberfläche} + +Die Weboberfläche wird mit dem Frontend-Web-Framework Vue.js erstellt. Mit Vue +werden wiederverwendbare, auf Datenänderungen reagierende Komponenten erstellt. +Die Komponenten nutzen ein fertiges Aussehen von dem Frontend-CSS-Framework +Bootstrap. Außerdem werden Icons der freien Schriftart fontawesome +verwendet. + +An der generellen Struktur und wichtigen Komponenten hat sich in der +Implementierung nichts großes zum Entwurf geändert. Einige Komponenten konnten +in der Implementierung allerdings abstrahiert werden, sodass weniger Code +dupliziert werden musste. Dazu gehören zum Beispiel die Komponenten, welche ein +Eingabefeld bereit stellen. + +Durch eine gute Arbeitsteilung blieb genug Zeit, um auch einige Kann-Kriterien +zu implementieren, weshalb ein paar Abhängigkeiten hinzugekommen sind. So werden +jszip und file-saver benötigt, um das Kann-Kriterium RC3 umzusetzen, durch +welches man Nutzerdaten im- und exportieren kann. + +Pinia konnten wir als Abhängigkeit entfernen, weil Vue von sich aus genügend +Funktionalität bietet die Nutzerdaten global allen Komponenten bereit zu +stellen. + +Anfangs überlegten wir den Wrapper \texttt{bootstrap-vue} zu verwenden, welcher +Bootstrap-HTML-Strukturen als Vue-Komponenten bereit stellt. Dies hätte des +Vorteil, dass man nur jene Komponenten importieren müsste, die man auch +benötigt. Es stellte sich heraus, dass \texttt{vue-bootstrap} nicht mit neusten +Version Vue3 kompatibel ist, weshalb wir uns entschieden Bootstrap wie gewohnt +komplett einzubinden. + +Während der Implementierung sind wir auf die Bibliothek \texttt{VueUse} +gestoßen, mit der man die Abhängigkeit \texttt{file-saver} und mehrere eigene +Wrapper für Browser-\Gls{api}s ersetzen könnte. So kann man das \Gls{dashboard} auch in +Zukunft noch weiter verbessern. + +Vom Frontend benötigte Abhängigkeiten: +\begin{itemize} + \item vite + \item vue + \item vue-router + \item \textcolor{red}{\sout{Pinia} wird durch globale Vue-Interne \texttt{ref} ersetzt} + \item bootstrap + \item fontawesome + \item vue-i18n (Support für mehrere Sprachen) + \item \textcolor{Green}{dayjs (Rechnen und formatieren von Zeiten)} + \item \textcolor{Green}{jszip (erstellen von Im-/Exports)} + \item \textcolor{Green}{file-saver (Abstraktion für Datei-Speichern-Dialog)} +\end{itemize} + +\subsection{Komponentendiagramm Web-Frontend} +\includegraphics[width=\textwidth]{assets/diagrams/componentdiagram} + +\subsection{Hinzugefügte Komponenten} + +% PasswordInput +% PasswordValidator +% FloatingLabelInput +% Loading +% ErrorLog +% ProgressTime + +\begin{minipage}{.7\linewidth} + +\subsubsection*{FloatingLabelInput} + +\begin{description} +\item[Tag] \texttt{<FloatingLabelInput type label>} +\item[Props] \mbox{} \\ + \emph{type} \mbox{} Beschreibt den Inhalt des Eingabefelder. Handelt es sich + um eine E-Mail, ein Passwort oder nur Text? \\ + \emph{label} \mbox{} Das Label wird als Platzhalter und kleine Überschrift + angezeigt. +\item[Beschreibung] Abstrahiert eine HTML-Struktur von Bootstrap, um ein schönes + Eingabefeld anzuzeigen. +\end{description} +\end{minipage} +\begin{minipage}{.3\linewidth} + \begin{figure}[H] + \includegraphics[width=\textwidth]{assets/floatinglabelinput.png} + \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{PasswordInput} + +\begin{description} +\item[Tag] \texttt{<PasswordInput type label>} +\item[Props] \mbox{} \\ + \emph{label} \mbox{} Das Label wird als Platzhalter und kleine Überschrift + angezeigt. +\item[Beschreibung] Erweitert den FloatingLabelInput um einen Knopf mit dem die + Sichtbarkeit des Eingabefeldes gewechselt werden kann. Dabei wird intern der + Typ des Eingabefeldes zwischen Text and Passwort gewechselt. +\end{description} +\end{minipage} +\begin{minipage}{.3\linewidth} + \begin{figure}[H] + \includegraphics[width=\textwidth]{assets/passwordinput.png} + \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{PasswordValidator} + +\begin{description} +\item[Tag] \texttt{<PasswordValidator>} +\item[Beschreibung] Besteht aus zwei PasswordInputs und überprüft diese auf + Gleichheit und Kriterien für eine gutes Passwort. +\end{description} +\end{minipage} +\begin{minipage}{.3\linewidth} + \begin{figure}[H] + \includegraphics[width=\textwidth]{assets/passwordvalidator.png} + \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{Loading} + +\begin{description} +\item[Tag] \texttt{<Loading waitingFor>...<Loading/>} +\item[Props] \mbox{} \\ + \emph{waitingFor} \mbox{} Eine Referenz auf eine Bedingung wann die Kinder + der Komponente gezeigt werden sollen. +\item[Beschreibung] Zeigt solange ein Ladesymbol an, bis die Bedingung in + \texttt{waitingFor} erfüllt ist und stattdessen die Kinder der Komponente + gezeigt werden. +\end{description} +\end{minipage} +\begin{minipage}{.3\linewidth} + \begin{figure}[H] + \includegraphics[width=\textwidth]{assets/loading.png} + \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{ProgressTime} + +\begin{description} +\item[Tag] \texttt{<ProgressTime unix>} +\item[Props] \mbox{} \\ + \emph{unix} \mbox{} Anzahl an Sekunden. +\item[Beschreibung] Nimmt eine Anzahl an Sekunden und gibt an wie viele Stunden, + Minuten und Sekunden die Anzahl entspricht. +\end{description} +\end{minipage} +\begin{minipage}{.3\linewidth} + \begin{figure}[H] + \includegraphics[width=\textwidth]{assets/progresstime.png} + \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\begin{minipage}{.7\linewidth} + +\subsubsection*{ErrorLog} + +\begin{description} +\item[Tag] \texttt{<ErrorLog>} +\item[Beschreibung] Zeigt eine Liste von Warnungen an, welche aus einem globalen + Zustandsspeicher geladen werden. +\end{description} +\end{minipage} +\begin{minipage}{.3\linewidth} + \begin{figure}[H] + \includegraphics[width=\textwidth]{assets/errorlog.png} + \end{figure} +\end{minipage} + + +\vspace{.5cm} + +\subsubsection*{Dashboard/FormLayout} + +\begin{description} +\item[Tag] \texttt{<DashboardLayout> <FormLayout>} +\item[Beschreibung] Fügt den Kindern einen Seitenabstand hinzu. +\end{description} diff --git a/20-implementierungsheft/sections/glossar.tex b/20-implementierungsheft/sections/glossar.tex new file mode 100644 index 0000000..9caad87 --- /dev/null +++ b/20-implementierungsheft/sections/glossar.tex @@ -0,0 +1,371 @@ +\makeglossaries + +\newglossaryentry{spa} +{ + name=Single-Page-Application, + description={ + ist ein Webseiten-Modell, bei welchem dem Nutzer nur ein Webdokument + bereitgestellt wird. Mit einem Skript wird der Inhalt der Seite + dynamisch mit Daten einer API befüllt. Außerdem verwaltet die Seite + (nicht der Server), welcher Inhalt bei welchem Pfad angezeigt wird. Dies + erzeugt geringere Serverlast und eine bessere Nutzererfahrung, da die + Seitenstruktur beim Laden von neuen Inhalten erhalten bleibt} +} + +\newglossaryentry{packagemanager} +{ + name=Paketmanager, + description={ + ist ein Programm, welches Pakete und dessen Abhängigkeiten verwaltet, + installiert, entfernt und aktualisiert. Pakete können andere Programme, + Plugins oder Software-Bibliotheken sein} +} + +\newglossaryentry{bundler} +{ + name=Bundler, + description={ + ist ein Programm, welches genutzte Teile von Abhängigkeiten eines + Software-Projekts in passender Reihenfolge zusammensucht und daraus + Dateien erstellt, die für den Nutzer bereitgestellt werden können. Dabei + kann der Bundler mit zusätzlichen Modulen Dateien erzeugen, die + rückwärtskompatibel oder für den Nutzer schwerer einsehbar sind} +} + +\newglossaryentry{java} +{ + name=Java, + description={ + ist eine objekt-orientierte interpretierte kompilierte + Programmiersprache, welche plattformunabhängig auf einer virtuellen + Maschine ausgeführt wird} +} + +\newglossaryentry{db} +{ + name=Datenbank, + plural=Datenbanken, + description={ + ist ein System um Daten persistent zu speichern und effizient zu + verwalten. Am meisten verbreitet sind relationale Datenbanken, welche + Daten in Tabellen mit Referenzen zu Einträgen anderer Tabellen + speichern. Programme können dann über eine Anfragesprache (Structured + Query Language - \Gls{SQL}) komplexe Operationen auf den Daten ausführen} +} + +\newglossaryentry{docker} +{ + name=Docker, + description={ + ist ein Programm, das virtualisierte Container ausführt. Ein Programm in + so einem Container läuft in seiner eigenen virtuellen Umgebung, wodurch + das Host-System sicher bleibt. Zudem lassen sich die Container leicht + auf andere Systeme verteilen} +} + +% RESTfull-API, JSON, RSS-Feed, Salting and Hasing, OAuth, Cookie, Garbage +% Collection, DSGVO, Podcast, Podcatcher, Episode, Gpodder, + +\newglossaryentry{podcatcher} +{ + name=Podcatcher, + plural=Podcatchern, + description={ + ist ein Programm, über welches man Podcasts entdecken, abonnieren und + Episoden von Podcasts hören kann. Mit einem Account auf einer Plattform, + welche eine Gpodder-API zur Verfügung stellt, können Ereignisse, die von + einem Nutzer ausgehen, auf anderen Podcatchern des Nutzers + synchronisiert werden} +} + +\newglossaryentry{podcast} +{ + name=Podcast, + description={ + ist ein RSS-Feed, dessen Einträge die Episoden darstellen} +} + +\newglossaryentry{episode} +{ + name=Episode, + plural=Episoden, + description={ + ist ein Eintrag in einem Podcast. Eine URL in dem Eintrag zeigt auf eine + Medien-Datei, welche vom Podcatcher abgespielt werden kann} +} + +\newglossaryentry{rest-api} +{ + name=RESTful-API, + description={ + ist ein Schnittstellenentwurf über das Hypertext Transfer Protocol + (HTTP), bei dem die Schnittstellen strukturiert als Pfad an einem + Endpunkt erreichbar sind. Mittels verschiedener HTTP-Methoden können an + der Schnittstelle Daten abgefragt (GET), gesendet (PUT), gelöscht + (DELETE) oder geändert (POST) werden. Die Daten, die über die + Schnittstelle gesendet werden liegen meist im JSON-Format vor} +} + + +\newglossaryentry{gpodder} +{ + name=Gpodder-API, + description={ + wird von gpodder.net benutzt und entwickelt. Die API wird als + Schnittstelle zwischen Podcatchern und Podcast Synchronisationsservern + verwendet. Weitere Details sind unter + "https://gpoddernet.readthedocs.io/en/latest/api/" zu finden} +} + +\newglossaryentry{json} +{ + name=JSON, + description={ + (JavaScript Object Notation) ist ein Datenformat und wird zur + Übertragung von Strukturen und Daten eingesetzt. JSON besteht dabei aus + grundlegenden Datentypen sowie Objekten mit Schlüssel-Wert Paaren und + Listen} +} + +\newglossaryentry{oauth} +{ + name=OAuth, + description={ + (Open Authorization) ist ein offenes Protokoll, welches es Nutzern + ermöglicht, sich mit bereits bestehenden Accounts bei anderen Diensten + zu registrieren. Dabei werden benötigte Daten für die Registrierung über + die bereitgestellte Schnittstelle zur Verfügung gestellt} +} + +\newglossaryentry{garbage-collection} +{ + name=Garbage Collection, + description={ + ist eine automatische Speicherbereinigung, welche nicht mehr benötigten + Speicherplatz wieder freigibt. Die Bereinigung kann dabei in determinierten + Zeitintervallen erfolgen oder durch bestimmte Ereignisse ausgelöst + werden} +} + +\newglossaryentry{salt-hash} +{ + name=Salting und Hashing, + description={ + ist eine Methode um Passwörter so zu kodieren, dass sie nicht als + Klartext gespeichert werden und auch sicher vor Hash-Wörterbüchern sind. + Dafür wird dem Passwort ein bekanntes Wort, der Salt, angefügt, bevor + aus dem kompletten Wort eine Prüfsumme, ein Hash, generiert wird. Beim + Anmelden wird die Prüfsumme der Anmeldung mit der bekannten + Prüfsumme des Passworts verglichen} +} + +\newglossaryentry{rss} +{ + name=RSS, + description={ + (Really Simple Syndication) zeigt strukturiert Listen von Nachrichten + an. Die Änderungen werden im XML-Format in sogenannte RSS-Dateien + geschrieben, welche über einen Link abgerufen werden können} +} + +\newglossaryentry{dsgvo} +{ + name=Datenschutz-Grundverordnung, + description={ + (DSGVO) ist eine im europäischen Wirtschaftsraum + geltende Verordnung. Sie sorgt für eine Reglementierung bei der + Verarbeitung personenbezogener Daten. Unter anderem muss einsehbar sein, + welche Daten von Nutzern erhoben werden. Außerdem muss für einen Nutzer + die Möglichkeit bestehen, seine erhobenen Daten abrufen zu können} +} + +\newglossaryentry{push-pull} +{ + name=Push und Pull, + description={ + sind Methoden, um Daten auszutauschen. Bei der Pull-Methode + stellt Akteur A einem Akteur B eine Anfrage auf Daten und erhält diese + als Antwort. Damit Akteur A und B immer auf dem selben Stand sind, muss + Akteur A chronisch Anfragen an Akteur B stellen. Im Gegensatz dazu steht + die Push-Methode, bei der Akteur B den Akteuren mitteilt, dass er neue + Änderungen hat. Dafür muss Akteur B allerdings wissen mit welchen + anderen Akteuren er in Verbindung steht und diese Verbindung aufrecht + erhalten} +} + +\newglossaryentry{ui-lib} +{ + name=UI-Bibliothek, + plural=UI-Bibliotheken, + description={ + kümmert sich um das Layout einer Webseite. Dabei unterscheidet man + zwischen Design-Bibliotheken (wie Bootstrap), welche fertige + UI-Komponenten bereitstellen, und Layout-Bibliotheken (wie Vue oder + React.js), welche die Komponenten basierend auf Daten dynamisch + anzeigen} +} + +\newglossaryentry{responsive} +{ + name=Responsive, + description={ + Design ist ein Design-Prinzip für Webseiten, bei dem die selbe Webseite ihre + Komponenten dynamisch der Bildschirmbreite anpasst} +} + +\newglossaryentry{pseudoprotocol} +{ + name=Pseudoprotokoll, + description={ + ist ein URL-Schema, auf das Webseiten hören können, wenn sie sich das + URL-Schema im Browser anmelden. Bekannt Pseudoprotokolle sind: + ,,mailto:'', ,,tel:'' oder ,,irc:''} +} + +\newglossaryentry{dashboard} +{ + name=Dashboard, + description={ + ist die erste Seite auf der man landet, wenn man angemeldet ist} +} + +\newglossaryentry{abo} +{ + name=Abonnement, + description={ + ist ein abonnierter Podcast} +} + +\newglossaryentry{discovery} +{ + name=Discovery, + description={ + ist ein Feature der Gpodder-API, welches dem Nutzer eine Reihe von + Podcasts zum abonnieren anbietet} +} + +\newglossaryentry{session-token} +{ + name=Session-Token, + description={ + ist ein Wort, dass vom Client gespeichert wird solange der Nutzer + eingeloggt ist und bei jeder Anfrage an den Server mitgeschickt wird. + Der Server kann den Session-Token einem Nutzer zuordnen und so mit + nutzerspezifischen Daten antworten} +} + +\newglossaryentry{cookie} +{ + name=Cookie, + description={ + ist ein kleiner webseitenspezifischer Speicher im Browser, welcher vom + Server und von der Webseite gesetzt werden kann und bei jeder weiteren + Anfrage an den Server mitgesendet wird. Cookies bleiben entweder + temporär im Browserspeicher, bis der Browser geschlossen wird oder + permanent, bis ein optionales Verfallsdatum erreicht ist} +} + +\newglossaryentry{uiComponent} +{ + name=UI-Komponente, + plural=UI-Komponenten, + description={ + In Vue.js werden die grafischen Elemente einer Webseite in einzelne + Komponenten zerteilt. + Diese reagieren automatisch auf Änderungen und können ohne Neuladen + der Seite ihr Aussehen verändern und somit Änderungen direkt anzeigen} +} + +\newglossaryentry{spring} +{ + name=Spring, + description={ + Ein Java-Framework, welches die Entwicklung von Web-Applikationen erleichtert. + Dazu wird eine Reihe von Werkzeugsets zur Verfügung gestellt. + Unter anderem sind das Spring Web für das Erstellen von Webanwendungen, + Spring Security für die Verwaltung von Benutzerauthentifizierungen und + Spring Data JPA für die Arbeit mit relationalen Datenbanken + } +} + +\newglossaryentry{api} +{ + name=API, + plural=APIs, + description={ + Eine Schnittstelle, welche es ermöglicht auf Funktionalitäten einer Anwendung + zuzugreifen. APIs für Webanwendungen heißen WebAPIs. + Ein Beispiel für eine WebAPI ist die REST-API + } +} + +\newglossaryentry{business} +{ + name=Geschäftslogik, + description={ + Eine Schicht in der Anwendungsentwicklung, in der die Art und Weise, wie das + Programm auf Eingaben reagiert, wie Daten verarbeitet und wie sie gespeichert + werden sollen, festgelegt ist + } +} + +\newglossaryentry{solid} +{ + name=SOLID, + description={ + Eine Sammlung an Prinzipien, welche zu gutem objektorientierten Design führen soll. + Jedes Prinzip steht für einen Buchstaben in SOLID: + \textbf{S}ingle-Responsibility Prinzip, + \textbf{O}pen-Closed Prinzip, + \textbf{L}iskovsches Substitutionsprinzip, + \textbf{I}nterface Segregation Prinzip und + \textbf{D}ependency Inversion Prinzip + } +} + +\newglossaryentry{crud} +{ + name=CRUD, + description={ + CRUD steht für \textbf{C}reate, \textbf{R}ead, \textbf{U}pdate und \textbf{D}elete. + Hierbei handelt es sich um die grundlegenden Funktionen einer Anwendung, + die mit einer Datenbank arbeitet. + Hierbei können Daten angelegt, abgerufen, aktualisiert und gelöscht werden. + Auch in Web-Applikationen ist CRUD mit HTTP über die Anfragen POST, GET, PUT und DELETE + vertreten + } +} + +\newglossaryentry{SQL} +{ + name=SQL, + description={ + SQL (Structured Query Language) ist eine Sprache, die einen strukturierten Zugriff auf Datenbanken ermöglicht. + Daten können hierbei hinzugefügt, abgefragt, geändert und gelöscht werden. + Das besondere hierbei ist der strukturierte Zugriff auf Daten, indem explizit Daten mit bestimmten Kriterien und + Relationen ausgewählt und bearbeitet werden können. + SQL wird fast von allen verbreiteten Datenbanksystemen unterstützt + } +} + +\newglossaryentry{Base64} +{ + name=Base64, + description={ + Mithilfe von Base64 können 8-Bit-Binärdaten in eine ASCII-Zeichenkette + kodiert werden. So werden zum Beispiel E-Mail-Anhänge versendet + } +} + +\newglossaryentry{JSONP} +{ + name=JSONP, + description={ + JSONP ermöglicht die Übertragung von JSON-Daten zwischen verschiedenen Domains. + Dies wäre durch die Same-Origin-Policy nicht möglich. + JSONP nutzt allerdings die Tatsache aus, + dass sich Skripte domainübergreifend übertragen lassen. + Dazu werden die JSON-Daten als Argument einer übergebenen Funktion über + ein Skript-Element eingebunden + } +} diff --git a/20-implementierungsheft/sections/methodology.tex b/20-implementierungsheft/sections/methodology.tex new file mode 100644 index 0000000..87b8176 --- /dev/null +++ b/20-implementierungsheft/sections/methodology.tex @@ -0,0 +1,16 @@ +\section{Integrationsstrategie} + +Bei der Implementierung wurde nach dem Outside-In Prinzip vorangegangenen. +Dabei handelt es sich um eine inkrementelle und vorgehensorientierte Integrationsstrategie. +Sie versucht die Vorteile des Top-Down und des Bottom-Up Prinzips zu vereinen und die jeweiligen +Nachteile zu mindern. + +Bei der Outside-In Integration wird gleichzeitig auf höchster und niedrigster logischer +Ebene mit der Implementation begonnen. Das passt gut zu der gewählten Systemarchitektur. +Es wird sowohl frühzeitig die \Gls{db} eingebunden als auch das Frontend und die +Controller implementiert. Dafür wird erst später an der Service-Schicht gearbeitet. +Dieses Vorgehen wurde gewählt um die frühe Verfügbarkeit von testbaren Endpunkten zu haben. +Somit können das Front- und Backend schon nach kurzer Zeit miteinander Integriert werden, +wenn auch ohne funktionierende Serviceschicht. Außerdem wird für lange Zeit an verschiedenen +Punkten gearbeitet, sodass der Prozess dank des vorrausgegangenen Entwurfs gut auf das ganze +Team parallelisierbar ist. diff --git a/20-implementierungsheft/sections/tests.tex b/20-implementierungsheft/sections/tests.tex new file mode 100644 index 0000000..cdbf163 --- /dev/null +++ b/20-implementierungsheft/sections/tests.tex @@ -0,0 +1,21 @@ +\section{Testfälle} + +Für die Erstellung der Testfälle wurde die SpringBoot Testumgebung verwendet und +diese durch JUnit Testfälle ergänzt. + +Für das Testen wurde eine BaseTest Klasse erstellt, die grundlegende Funktionalität +einiger Kern Komponenten sicherstellt. Weiter Initialisiert sie die Anwendungsumgebung auf +der alle weiteren Tests aufbauen. + +Die Unit Tests erweitern diese BaseTest Klasse und können daher von gewisser Grundfunktionalität +ausgehen, die durch den BaseTest abgedeckt ist. Dadurch müssen nicht große Teile der +Anwendung durch Mock Objekte simuliert werden. + +Grundsätzlich wurde beim Entwurf der Testfälle nach dem Inside-Out-Prinzip vorangegangenen. +Die bisher geschriebenen Testfälle haben dabei nicht das Ziel Korrektheit zu garantieren, +sondern einen gewissen Qualitätsstandart zu sichern und gleichzeitig genug +Arbeitspunkte bereit zu stellen um im ganzen Team an diesem Projekt parallel arbeite zu können. + +Zusätzlich wurden bei der Implementierung auf ausgiebig getestete Annotationen von Spring und +Lombok zurückgegriffen die helfen die Anzahl an Fehlern bei standardisierten +\enquote{Boilerplater-Code} Aufgaben zu vermeiden.
\ No newline at end of file diff --git a/20-implementierungsheft/sections/timeline.tex b/20-implementierungsheft/sections/timeline.tex new file mode 100644 index 0000000..7fa084d --- /dev/null +++ b/20-implementierungsheft/sections/timeline.tex @@ -0,0 +1,7 @@ +\section{Zeitlicher Verlauf} + +\subsection{Plan} +\includegraphics[width=\textwidth]{assets/diagrams/gantt-plan} + +\subsection{Realität} +\includegraphics[width=\textwidth]{assets/diagrams/gantt-reality} |