summaryrefslogtreecommitdiff
path: root/11-entwurfsheft-kolloquium/assets/diagrams
diff options
context:
space:
mode:
authorOrangerot <purple@orangerot.dev>2024-05-24 17:42:08 +0200
committerOrangerot <purple@orangerot.dev>2024-05-24 17:47:22 +0200
commit7fcdc1c788725f866de71fc9dfd8c4d1cb132b57 (patch)
tree89931c85ae3f149884ba02c69862558e93f01531 /11-entwurfsheft-kolloquium/assets/diagrams
Initial commitHEADmain
Diffstat (limited to '11-entwurfsheft-kolloquium/assets/diagrams')
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml61
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml112
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml84
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-model.puml109
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml75
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-util.puml43
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/classdiagram.puml68
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/componentdiagram.puml53
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/db.puml78
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/deployment.puml59
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml41
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml38
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml32
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml36
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-register.puml26
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml38
-rw-r--r--11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml32
17 files changed, 985 insertions, 0 deletions
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml b/11-entwurfsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml
new file mode 100644
index 0000000..806522c
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/backendComponentDiagram.puml
@@ -0,0 +1,61 @@
+@startuml
+' skinparam linetype ortho
+
+'#########################################################################
+'SubscriptionsAPI
+component SubscriptionsAPI {
+
+ component SubscriptionService
+ component SubscriptionController
+ component SubscriptionDataAccessLayer
+
+ portout "Webserver" as wSub
+ portin "Database" as dSub
+ }
+
+dSub --0)- SubscriptionDataAccessLayer
+SubscriptionDataAccessLayer --0)- SubscriptionService
+SubscriptionService --0)- SubscriptionController
+SubscriptionController --0)- wSub
+
+'#########################################################################
+
+
+'#########################################################################
+'EpisodeActionsAPI
+
+component EpisodeActionsAPI {
+ component EpisodeActionService
+ component EpisodeActionController
+ component EpisodeActionDataAccessLayer
+
+ portout "Webserver" as wEpisode
+ portin "Database" as dEpisode
+}
+
+dEpisode --0)- EpisodeActionDataAccessLayer
+EpisodeActionController --0)- wEpisode
+EpisodeActionDataAccessLayer --0)- EpisodeActionService
+EpisodeActionService --0)- EpisodeActionController
+
+'#########################################################################
+
+
+'#########################################################################
+'AuthenticationAPI
+
+component AuthenticationAPI {
+ component AuthenticationService
+ component AuthenticationController
+ component AuthenticationDataAccessLayer
+
+ portout "Webserver" as wAuth
+ portin "Database" as dAuth
+}
+
+dAuth --0)- AuthenticationDataAccessLayer
+AuthenticationController --0)- wAuth
+AuthenticationDataAccessLayer --0)- AuthenticationService
+AuthenticationService --0)- AuthenticationController
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml
new file mode 100644
index 0000000..a2b3518
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-authentication.puml
@@ -0,0 +1,112 @@
+@startuml
+
+package authenticationAPI <<Frame>> {
+ package authenticationDataAccessLayer <<Frame>> {
+ ' interface AuthenticationDao {
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ ' class AuthenticationDataAccessService <<@Respository>> {
+ ' <<create>> AuthenticationDataAccessService(JpaTemplate jpaTemplate)
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ interface UserDetailsManager {
+ void createUser(UserDetails userDetails)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note left
+ Aus org.springframework.security.provisioning
+ - liefert Methoden zum Erstellen neuer User
+ und zum Aktualisieren bestehender.
+ end note
+
+ class JdbcUserDetailsManager <<@Repository>> {
+ <<create>> JdbcUserDetailsManager(DataSource dataSource)
+ void createUser(UserDetails user)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note right
+ User Management Service aus dem Paket
+ org.springframework.security.provisioning
+ der CRUD Operationen für User bereitstellt.
+ Hier sind nur die relevanten Methoden modelliert.
+ end note
+ }
+
+ package authenticationService <<Frame>> {
+ class AuthenticationService <<@Service>> {
+ --
+ <<create>> AuthenticationService(UserDetailsManager userDetailsManager)
+ List<String> verifyLogin(String username)
+ int logout(String username)
+ int forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ .. via JdbcUserDetailsManager ..
+ int resetPassword(String username, RequestWithPassword requestWithPassword)
+ int registerUser(UserDetails user)
+ int changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ int deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class JavaMailSenderImpl {}
+ note left
+ Aus org.springframework.mail.javamail.
+ Implementierung des JavaMailSender Interfaces,
+ welches das MailSender Interface durch Unterstützung
+ von MIME Nachrichten erweitert.
+ Das MailSender Interface definiert dabei eine
+ Strategie zum Versenden einfacher Mails.
+ Unterstützt sowohl JavaMail MimeMessages und
+ Spring SimpleMailMessages.
+ end note
+ }
+
+ package authenticationController <<Frame>> {
+ class AuthenticationController <<@Controller>> {
+ <<create>> AuthenticationController(AuthenticationService authenticationService)
+ ResponseEntity<List<String>> verifyLogin(String username)
+ ResponseEntity<Integer> logout(String username)
+ ResponseEntity<Integer> forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ ResponseEntity<Integer> resetPassword(String username, RequestWithPassword requestWithPassword)
+ ResponseEntity<Integer> registerUser(UserDetails user)
+ ResponseEntity<Integer> changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ ResponseEntity<Integer> deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class ChangePasswordRequest {
+ <<create>> ChangePasswordRequest(String oldPassword, String newPassword)
+ String getOldPassword()
+ String getNewPassword()
+ }
+
+ class ForgotPasswordRequest {
+ <<create>> ForgotPasswordRequest(String email)
+ String getEmail()
+ }
+
+ class RequestWithPassword {
+ <<create>> ResetPasswordRequest(String password)
+ String getPassword()
+ }
+ }
+}
+
+' User <.. AuthenticationDataAccessService: DB
+' User <.. JdbcUserDetailsManager: DB
+UserDetailsManager <.. AuthenticationService: <<use>>
+' AuthenticationDao <.. AuthenticationService: <<use>>
+AuthenticationService --o AuthenticationController
+' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>>
+UserDetailsManager <|. JdbcUserDetailsManager: <<realize>>
+JavaMailSenderImpl <. AuthenticationService: <<use>>
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml
new file mode 100644
index 0000000..7a4530e
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-episode-actions.puml
@@ -0,0 +1,84 @@
+@startuml
+
+package episodeActionsAPI <<Frame>> {
+ package episodeActionDataAccessLayer <<Frame>> {
+ class EpisodeActionDataAccessService <<@Repository>> {
+ <<create>> EpisodeActionDataAccessService (JpaTemplate jpaTemplate)
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+
+ interface EpisodeActionDao {
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionService <<Frame>> {
+ class EpisodeActionService <<@Service>> {
+ <<create>> EpisodeActionService (EpisodeActionDao episodeActionDao)
+ LocalDateTime addEpisodeActions(String username, List<EpisodeActionPosts> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionController <<Frame>> {
+ class EpisodeActionController <<@Controller>>{
+ <<create>> EpisodeActionController (EpisodeActionService episodeActionService)
+ ResponseEntity<EpisodeActionPostResponse> addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActions(String username, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated)
+ }
+
+ class EpisodeActionPostResponse {
+ <<create>> EpisodeActionPostResponse(List<Pair<String, String>> updateURLs)
+ long getTimestamp()
+ List<Pair<String, String>> getUpdatedURLs()
+ }
+
+ class EpisodeActionPost {
+ <<create>> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position)
+ String getPodcastURL()
+ String getEpisodeURL()
+ int getGUID()
+ Action getAction()
+ LocalDateTime getTimestamp()
+ int getStarted()
+ int getPosition()
+ EpisodeAction getEpisodeAction()
+ }
+
+ class EpisodeActionPostRequest {
+ <<create>> EpisodeActionPostRequest(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ }
+
+ class EpisodeActionGetResponse {
+ <<create>> EpisodeActionGetResponse(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ long getTimestamp()
+ }
+ }
+}
+
+EpisodeActionPost -o EpisodeActionGetResponse
+EpisodeActionPost -o EpisodeActionPostRequest
+' EpisodeAction <.. EpisodeActionDataAccessService: DB
+' Episode <.. EpisodeActionDataAccessService: DB
+EpisodeActionDao <.. EpisodeActionService: <<use>>
+EpisodeActionService --o EpisodeActionController
+EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>>
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-model.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-model.puml
new file mode 100644
index 0000000..72ad49f
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-model.puml
@@ -0,0 +1,109 @@
+@startuml
+
+package model <<Frame>> {
+ class Subscription {
+ <<create>> Subscription(String url, String title)
+ int getID()
+ String getURL()
+ long getLastActionTimestamp()
+ String getTitle()
+ }
+
+ class SubscriptionAction {
+ <<create>> SubscriptionAction(int userID, int subscriptionID)
+ int getID()
+ int getUserID()
+ int getSubscriptionID()
+ long getTimestamp()
+ boolean getAdded()
+ }
+
+ class Episode {
+ <<create>> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total)
+ int getSubscriptionID()
+ int getID()
+ int getGUID()
+ String getURL()
+ String getTitle()
+ int getTotal()
+ }
+
+ enum Action {
+ Download
+ Play
+ Delete
+ New
+ Flattr
+ String getJsonProperty()
+ }
+
+ class EpisodeAction {
+ <<create>> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position)
+ int getEpisodeID()
+ Action getAction()
+ long getTimestamp()
+ int getStarted()
+ int getPosition()
+ void setEpisodeID()
+ EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL)
+ }
+
+ interface UserDetails {
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+ note left
+ Aus org.springframework.security.core.userdetails.
+ Wird für die Schnittstelle UserDetailsManager benötigt.
+ Stellt wichtige Informationen eines Users bereit.
+ Diese werden nur indirekt von Spring Security
+ benutzt, indem sie vorher in Authentication Objekten
+ gekapselt werden.
+ end note
+
+ class User {
+ --
+ <<create>> User(String username, String password)
+ int getID()
+ String getSessionToken()
+ boolean getEmailIsValidated()
+ .. interface methods ..
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+
+ interface GrantedAuthority {
+ String getAuthority()
+ }
+ note right
+ Aus org.springframework.security.core.
+ Wird für die Schnittstelle UserDetails benötigt.
+ Repräsentiert eine Autorisierung, die einem
+ Authentication Objekt gewährt wird.
+ end note
+
+ class Authority {
+ <<create>> Authority()
+ String getAuthority()
+ }
+}
+
+Subscription <. SubscriptionAction: ID
+Action <-- EpisodeAction
+EpisodeAction .> Episode: ID
+UserDetails <|.. User: <<realize>>
+User -> Authority
+GrantedAuthority <|.. Authority: <<realize>>
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml
new file mode 100644
index 0000000..432f185
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-subscriptions.puml
@@ -0,0 +1,75 @@
+@startuml
+
+package subscriptionsAPI <<Frame>> {
+ package subscriptionDataAccessLayer <<Frame>> {
+ class SubscriptionDataAccessService <<@Repository>> {
+ <<create>> SubscriptionDataAccessService(JpaTemplate jpaTemplate)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+
+ interface SubscriptionDao {
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionService <<Frame>> {
+ class SubscriptionService <<@Service>> {
+ <<create>> SubscriptionService(SubscriptionDao subscriptionDao)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionController <<Frame>> {
+ class SubscriptionController <<@Controller>>{
+ ' @Autowired
+ <<create>> SubscriptionController(SubscriptionService subscriptionService)
+ ' @GetMapping
+ ResponseEntity<List<String>> getSubscriptions(String username, String deviceID, String functionJSONP)
+ ' @PutMapping
+ ResponseEntity<String> uploadSubscriptions(String username, String deviceID, List<String> subscriptions)
+ ' @PostMapping
+ ResponseEntity<SubscriptionDelta> applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta)
+ ' @GetMapping
+ ResponseEntity<SubscriptionDelta> getSubscriptionDelta(String username, String deviceID, long since)
+ ResponseEntity<List<SubscriptionTitles>> getTitles(String username, String deviceID)
+ }
+
+ class SubscriptionTitles {
+ <<create>> SubscriptionTitles(Subscription subscription, List<EpisodeActionPost> episodeTitles)
+ Subscription getSubscription()
+ List<EpisodeActionPost> getEpisodesTitles()
+ }
+
+ class SubscriptionDelta {
+ <<create>> SubscriptionDelta(List<String> add, List<String> remove)
+ List<String> getRemove()
+ LocalDate getTimestamp()
+ List<List<String>> getUpdate_urls()
+ }
+ }
+
+}
+
+' Subscription <.. SubscriptionDataAccessService: DB
+' SubscriptionAction <.. SubscriptionDataAccessService: DB
+SubscriptionService --o SubscriptionController
+SubscriptionDao <.. SubscriptionService: <<use>>
+SubscriptionDao <|. SubscriptionDataAccessService: <<realize>>
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-util.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-util.puml
new file mode 100644
index 0000000..03dfc9a
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram-util.puml
@@ -0,0 +1,43 @@
+@startuml
+
+package util <<Frame>> {
+ class RSSParser {
+ <<create>> RSSParser(String subscriptionURL)
+ String getSubscriptionTitle()
+ List<Episode> getEpisodes()
+ Episode getEpisodeForURL(String episodeURL)
+ }
+ note bottom
+ Verwendet intern Spring um
+ HTTP-Anfragen zu erstellen.
+ end note
+
+ class CleanCronJob {
+ <<create>> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager)
+ void cleanInvalidUsers()
+ }
+ note bottom
+ Hintergrundservice, der in periodischen Abständen
+ Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden
+ bestätigt haben, wieder aus der Datenbank löscht.
+ (Auf die Assoziation zu JdbcUserDetailsManager wird
+ im Sinne der Übersichtlichkeit verzichtet.)
+ end note
+
+ class ResponseEntity<T> {
+ <<create>> ResponseEntity(T body, HttpStatusCode status)
+ T getBody()
+ HttpStatusCode getStatusCode()
+ }
+ note bottom
+ Aus org.springframework.http.
+ Erweitert die Klasse HttpEntity, welche
+ ein HTTP Anfrage- oder Antwort-Objekt
+ repräsentiert, durch einen HttpStatusCode.
+ Wird von den Controller-Methoden als
+ Rückgabewert verwendet.
+ end note
+}
+
+@enduml
+
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram.puml b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram.puml
new file mode 100644
index 0000000..f833aa2
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/classdiagram.puml
@@ -0,0 +1,68 @@
+@startuml
+' skinparam linetype ortho
+' skinparam groupInheritance 2
+allowmixing
+
+!include classdiagram-authentication.puml
+!include classdiagram-episode-actions.puml
+!include classdiagram-model.puml
+!include classdiagram-subscriptions.puml
+!include classdiagram-util.puml
+
+class SecurityConfigurationBasicAuth {
+ <<create>> SecurityConfigurationBasicAuth()
+ PasswordEncoder encoder()
+ UserDetailsManager userDetailsService()
+ SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion
+}
+note top
+ Erstellt einen Servlet Filter (springSecurityFilterChain)
+ der für die gesamte Sicherheit zuständig ist (Schutz der URLs,
+ Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.).
+end note
+
+class PSEApplication {
+ <<create>> PSEApplication()
+ void main(String[] args)
+}
+
+database Datenbank
+Datenbank <-[hidden]d- subscriptionsAPI
+Datenbank <-[hidden]d- episodeActionsAPI
+Datenbank <-[hidden]d- authenticationAPI
+() SQL as SQLSub
+() SQL as SQLAuth
+() SQL as SQLEpisode
+
+Datenbank -- SQLSub
+Datenbank -- SQLAuth
+Datenbank -- SQLEpisode
+
+Subscription --o SubscriptionTitles
+EpisodeActionPost -o SubscriptionTitles
+UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>>
+
+SubscriptionController ..o PSEApplication
+AuthenticationController ..o PSEApplication
+EpisodeActionController ..o PSEApplication
+SecurityConfigurationBasicAuth ..o PSEApplication
+
+PSEApplication --() HTTP
+
+SQLSub )-- SubscriptionDataAccessService: JPA
+' SQLAuth )-- AuthenticationDataAccessService: JPA
+SQLAuth )-- JdbcUserDetailsManager: JDBC
+SQLEpisode )-- EpisodeActionDataAccessService: JPA
+
+RSSParser <. SubscriptionDataAccessService: <<use>>
+RSSParser <. EpisodeActionDataAccessService: <<use>>
+' JdbcUserDetailsManager <-- CleanCronJob
+
+model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
+' Datenbank o.. Subscription: ORM
+' Datenbank o.. SubscriptionAction: ORM
+' Datenbank o.. Episode: ORM
+' Datenbank o.. EpisodeAction: ORM
+' Datenbank o.. User: ORM
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/componentdiagram.puml b/11-entwurfsheft-kolloquium/assets/diagrams/componentdiagram.puml
new file mode 100644
index 0000000..dea4a1d
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/componentdiagram.puml
@@ -0,0 +1,53 @@
+@startuml
+
+[App] as app
+[VueRouter] as router
+[NavbarComponent] as navbar
+[LoginPage] as login_page
+[SubscriptionsPage] as abo_page
+[EpisodesPage] as episodes_page
+[SettingsPage] as settings_page
+[ForgotPasswordPage] as forgot_page
+[ResetPasswordPage] as reset_page
+note top
+ Wird in der E-Mail zum Zurücksetzen des Passworts mit dem JWT-Token verlinkt.
+ Sendet das alte und neue Passwort und den JWT an die API.
+end note
+[RegistrationPage] as registration_page
+
+[SubscriptionComponent] as sub
+[EpisodeComponent] as episode
+[LastUpdateComponent] as last_update
+[PasswordValidatorComponent] as password
+
+app --> router
+
+app --> navbar
+router --> login_page
+router --> forgot_page
+router --> reset_page
+router --> registration_page
+router --> abo_page
+router --> episodes_page
+router --> settings_page
+
+navbar -[hidden] router
+
+episodes_page -[hidden] abo_page
+login_page -[hidden] forgot_page
+registration_page -[hidden] reset_page
+abo_page -[hidden] settings_page
+forgot_page -[hidden] episodes_page
+' forgot_page -[hidden] settings_page
+
+abo_page --> sub
+episodes_page --> episode
+
+sub --> last_update
+episode --> last_update
+
+settings_page --> password
+reset_page --> password
+registration_page --> password
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/db.puml b/11-entwurfsheft-kolloquium/assets/diagrams/db.puml
new file mode 100644
index 0000000..bdefaea
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/db.puml
@@ -0,0 +1,78 @@
+@startuml
+' Type Symbol
+' Zero or One |o--
+' Exactly One ||--
+' Zero or Many }o--
+' One or Many }|--
+
+skinparam linetype ortho
+
+entity User {
+ * int id <<unique>>
+ * <u>String email</u>
+ * String password
+ * boolean verified
+ * long created_at
+}
+
+entity SubscriptionAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * long timestamp
+ * int subscription_id
+ * boolean added
+}
+
+entity Subscription {
+ * int id <<unique>>
+ * <u>String url</u>
+ * long timestamp
+ * String title
+}
+
+entity Episode {
+ * int id <<unique>>
+ * <u>int guid <<unique>></u>
+ * <u>String url</u>
+ * String title
+ * int total
+ * int subscription_id
+}
+note right
+ Wenn der Client eine GUID aus dem Feed mitsendet, wird
+ diese statt der URL verwendet um die Episode zu finden.
+ So wird die Episode auch noch gefunden, nachdem sich
+ die URL geändert hat.
+end note
+note bottom of Episode
+ Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht,
+ dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription.
+ Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf
+ die aktuelle Zeit.
+ Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst
+ nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch
+ nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben.
+ Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden.
+end note
+
+entity EpisodeAction {
+ * int id <<unique>>
+ * <u>int user_id</u>
+ * int episode_id
+ * long timestamp
+ * int action
+ * int started
+ * int position
+}
+note right
+ Speichere für jede Episode
+ nur letzte Play-Action.
+endnote
+
+User ||--o{ EpisodeAction
+User ||--o{ SubscriptionAction
+SubscriptionAction }|--|| Subscription
+EpisodeAction }|--|| Episode
+Subscription ||-right-|{ Episode
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/deployment.puml b/11-entwurfsheft-kolloquium/assets/diagrams/deployment.puml
new file mode 100644
index 0000000..26918e2
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/deployment.puml
@@ -0,0 +1,59 @@
+@startuml
+
+node "<<device>> \nBackend Server" as backendServer{
+ database " <<database system>> \n MariaDB Server 10.6" as database {
+ rectangle rectangle1 [
+ <<schema>>
+ User
+ ]
+ rectangle rectangle2 [
+ <<schema>>
+ SubscriptionAction
+ ]
+ rectangle rectangle3 [
+ <<schema>>
+ EpisodeAction
+ ]
+ rectangle rectangle4 [
+ <<schema>>
+ Subscription
+ ]
+ rectangle rectangle5 [
+ <<schema>>
+ Episode
+ ]
+ }
+
+ node "<<framework>> \nJava Spring" as javaSpring{
+ node " <<device>> \n Tomcat Webserver"
+ }
+}
+
+node "<<device>> \nFrontend" as frontendServer {
+
+}
+
+node "<<device>> \nEndgerät" as terminal {
+ node "<<application>> \nBrowser" as browser
+ node "<<application>> \nPodcatcher" as podcatcher
+}
+
+backendServer "1" - "*" podcatcher
+
+node "<<device>> \nFrontend Server" as frontendServer{
+ node "<<framework>> \nVue.js" as vuejs {
+
+ }
+}
+
+podcatcher -[hidden] browser
+
+backendServer - "1" frontendServer
+
+database "1" -- "1" javaSpring
+
+browser "*" -- frontendServer
+
+
+
+@enduml
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml
new file mode 100644
index 0000000..603130c
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-forgotAndResetPW.puml
@@ -0,0 +1,41 @@
+@startuml
+
+skinparam ParticipantPadding 30
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/forgot.json"" \n//@RequestBody ForgotPasswordRequest forgotPasswordRequest// \n\n-> forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: forgotPassword(//forgotPasswordRequest//)
+activate AuthenticationService
+participant JavaMailSenderImpl << (C, #ADD1B2) >>
+AuthenticationService -> JavaMailSenderImpl: create link to reset password with JWT as URL parameter \n-> send(SimpleMailMessage simpleMessage) with link
+activate JavaMailSenderImpl
+<<- JavaMailSenderImpl: sends email with link containing a JWT to reset password
+JavaMailSenderImpl --> AuthenticationService
+deactivate JavaMailSenderImpl
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+||60||
+-> AuthenticationController: ""PUT /api/2/auth/{username}/resetpassword.json"" \n//@RequestParam String jwt// \n//@RequestBody ResetPasswordRequest resetPasswordRequest// \n\n-> login user (""username"") via JWT (//jwt//) \n-> resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationController
+AuthenticationController -> AuthenticationService: resetPassword(""username"", //resetPasswordRequest//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: String oldPassword = //resetPasswordRequest//.getOldPassword() \nString newPassword = //resetPasswordRequest//.getNewPassword() \n-> changePassword(newPassword, oldPassword)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: change password of logged in user
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml
new file mode 100644
index 0000000..47497d5
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Get All Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("device") String deviceID// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActions(""username"", //deviceID//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert,
+ da nicht zwischen Geräten unterschieden und für jede
+ Episode sowieso nur die letzte Play-Action gespeichert
+ wird. Dies gilt für alle GET-Anfragen der Episode Actions API.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActions(""username"")
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActions(""username"")
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> EpisodeActionDataAccessService: getEpisodeActionsSince(""username"", \nLocalDateTime.MIN.toEpochSecond(ZoneOffset.UTC))
+database Database
+activate EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get all EpisodeActions for all subscribed podcasts
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than LocalDateTime.MIN (none)
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionDataAccessService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
new file mode 100644
index 0000000..d8797d1
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getEpisodeActionsOfPodcastSince.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Get Episode Actions of Podcast Since**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""GET /api/2/episodes/{username}.json"" \n//@RequestParam("podcast") String podcastURL// \n//@RequestParam("device") String deviceID// \n//@RequestParam("since") long since// \n//@RequestParam("aggregated") boolean aggregated// \n\n-> getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //deviceID//, //since//, //aggregated//)
+note right
+ Die Parameter //deviceID// und //aggregated// werden ignoriert.
+ Siehe Notiz in Sequenzdiagramm **Get All Episode Actions**.
+end note
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: getEpisodeActionsOfPodcastSince(""username"", //podcastURL//, //since//)
+activate EpisodeActionDataAccessService
+database Database
+EpisodeActionDataAccessService -> Database: get all EpisodeActions the given podcast (//podcastURL//)
+activate Database
+Database --> EpisodeActionDataAccessService: List<EpisodeAction> selectedEpisodeActions \n-> then remove all older than //since//
+EpisodeActionDataAccessService -> Database: join EpisodeActions in selectedEpisodeActions with episodeURL of Episode
+Database --> EpisodeActionDataAccessService
+deactivate Database
+EpisodeActionDataAccessService --> EpisodeActionService: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: List<EpisodeActionPost> episodeActionPosts
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionGetResponse> response \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml
new file mode 100644
index 0000000..6e6895f
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-getSubscriptions.puml
@@ -0,0 +1,36 @@
+@startuml
+
+' title =**Get All Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""GET /subscriptions/{username}.json"" \n"" /subscriptions/{username}/{deviceid}.json"" \n//@RequestParam("jsonp") String functionJSONP// \n\n-> getSubscriptions(""username"", ""deviceid"", //functionJSONP//)
+activate SubscriptionController
+note right
+ Die Parameter ""deviceid"" und
+ //functionJSONP// werden ignoriert,
+ da nicht zwischen Geräten unterschieden
+ und JSONP nicht unterstützt wird.
+end note
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: getSubscriptions(""username"")
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: getSubscriptions(""username"")
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: getSubscriptionsSince(""username"", LocalDateTime.MIN)
+database Database
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: get all Podcasts from Subscriptions for ""username""
+activate Database
+Database --> SubscriptionDataAccessService: List<Podcast> subscribedPodcasts
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: List<String> podcastURLs
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: List<String> podcastURLs
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<List<String>> podcastURLs \n \n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-register.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-register.puml
new file mode 100644
index 0000000..b7b7aa1
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-register.puml
@@ -0,0 +1,26 @@
+@startuml
+
+' title =**Register**
+
+participant AuthenticationController << (C, #ADD1B2) @Controller >>
+-> AuthenticationController: ""POST /api/2/auth/register.json"" \n//@RequestBody UserDetails user// \n\n-> registerUser(//user//)
+activate AuthenticationController
+participant AuthenticationService << (C, #ADD1B2) @Service >>
+AuthenticationController -> AuthenticationService: registerUser(//user//)
+activate AuthenticationService
+participant JdbcUserDetailsManager << (C, #ADD1B2) @Repository >>
+AuthenticationService -> JdbcUserDetailsManager: createUser(//user//)
+activate JdbcUserDetailsManager
+database Database
+JdbcUserDetailsManager -> Database: create new User with given UserDetails (//user//)
+activate Database
+Database --> JdbcUserDetailsManager
+deactivate Database
+JdbcUserDetailsManager --> AuthenticationService: int indicating status
+deactivate JdbcUserDetailsManager
+AuthenticationService --> AuthenticationController: int indicating status
+deactivate AuthenticationService
+<-- AuthenticationController: ResponseEntity<Integer> indicating status \n\n-> ""HTTP status code""
+deactivate AuthenticationController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
new file mode 100644
index 0000000..d3dac57
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadEpisodeActions.puml
@@ -0,0 +1,38 @@
+@startuml
+
+' title =**Upload Episode Actions**
+
+participant EpisodeActionController << (C, #ADD1B2) @Controller >>
+-> EpisodeActionController: ""POST /api/2/episodes/{username}.json"" \n//@RequestBody EpisodeActionPostRequest episodeActionPostRequest// \n\n-> addEpisodeActions(""username"", //episodeActionPostRequest//)
+activate EpisodeActionController
+participant EpisodeActionService << (C, #ADD1B2) @Service >>
+EpisodeActionController -> EpisodeActionService: addEpisodeActions(""username"", \nepisodeActionPosts = //episodeActionPostRequest//.getEpisodeActionPosts())
+activate EpisodeActionService
+participant EpisodeActionDataAccessService << (C, #ADD1B2) @Repository >>
+EpisodeActionService -> EpisodeActionDataAccessService: addEpisodeActions(""username"", episodeActionPosts)
+database Database
+activate EpisodeActionDataAccessService
+loop for each EpisodeActionPost in episodeActionPosts -> episodeAction = episodeActionPost.getEpisodeAction()
+opt episodeAction.getAction().equals(Action.PLAY)
+EpisodeActionDataAccessService -> Database: set episodeID field of episodeAction for this ""username"" via podcastURL and episodeURL
+activate Database
+Database --> EpisodeActionDataAccessService
+EpisodeActionDataAccessService -> Database: get last EpisodeAction with this episodeID if present
+Database --> EpisodeActionDataAccessService: Optional<EpisodeAction> lastEpisodeAction
+opt lastEpisodeAction.isPresent()
+EpisodeActionDataAccessService -> Database: replace lastEpisodeAction with episodeAction
+else else
+EpisodeActionDataAccessService -> Database: add episodeAction to DB as new entry
+end
+Database --> EpisodeActionDataAccessService
+deactivate Database
+end
+end
+EpisodeActionDataAccessService --> EpisodeActionService: long latestTimestamp
+deactivate EpisodeActionDataAccessService
+EpisodeActionService --> EpisodeActionController: LocalDateTime timestamp = LocalDateTime.ofEpochSecond(latestTimestamp, 0, ZoneOffset.UTC)
+deactivate EpisodeActionService
+<-- EpisodeActionController: ResponseEntity<EpisodeActionPostResponse> \n(with empty list for updateURLs) \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate EpisodeActionController
+
+@enduml \ No newline at end of file
diff --git a/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml
new file mode 100644
index 0000000..1edc8cf
--- /dev/null
+++ b/11-entwurfsheft-kolloquium/assets/diagrams/sequencediagram-uploadSubscriptions.puml
@@ -0,0 +1,32 @@
+@startuml
+
+' title =**Upload Subscriptions**
+
+participant SubscriptionController << (C, #ADD1B2) @Controller >>
+-> SubscriptionController: ""PUT /subscriptions/{username}/{deviceid}.json"" \n//@RequestBody List<String> subscriptions// \n\n-> uploadSubscriptions(""username"", ""deviceid"", //subscriptions//)
+activate SubscriptionController
+participant SubscriptionService << (C, #ADD1B2) @Service >>
+SubscriptionController -> SubscriptionService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionService
+participant SubscriptionDataAccessService << (C, #ADD1B2) @Repository >>
+SubscriptionService -> SubscriptionDataAccessService: uploadSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+database Database
+SubscriptionDataAccessService -> Database: delete all subsciptions of ""username""
+activate Database
+Database --> SubscriptionDataAccessService
+SubscriptionDataAccessService -> SubscriptionDataAccessService: addSubscriptions(""username"", //subscriptions//)
+activate SubscriptionDataAccessService
+SubscriptionDataAccessService -> Database: upload all subscriptions (//subscriptions//) for ""username""
+Database --> SubscriptionDataAccessService
+deactivate Database
+SubscriptionDataAccessService --> SubscriptionDataAccessService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionDataAccessService --> SubscriptionService: int indicating status
+deactivate SubscriptionDataAccessService
+SubscriptionService --> SubscriptionController: int indicating status
+deactivate SubscriptionService
+<-- SubscriptionController: ResponseEntity<String> with empty String for success \n\n-> ""HTTP status code"" \n-> ""JSON""
+deactivate SubscriptionController
+
+@enduml \ No newline at end of file