241 lines
9.5 KiB
TeX
241 lines
9.5 KiB
TeX
\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} |