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/changes.tex |
Diffstat (limited to '20-implementierungsheft/sections/changes.tex')
-rw-r--r-- | 20-implementierungsheft/sections/changes.tex | 241 |
1 files changed, 241 insertions, 0 deletions
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 |