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/assets/diagrams/classdiagram.puml |
Diffstat (limited to '20-implementierungsheft/assets/diagrams/classdiagram.puml')
-rw-r--r-- | 20-implementierungsheft/assets/diagrams/classdiagram.puml | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/20-implementierungsheft/assets/diagrams/classdiagram.puml b/20-implementierungsheft/assets/diagrams/classdiagram.puml new file mode 100644 index 0000000..4b1970a --- /dev/null +++ b/20-implementierungsheft/assets/diagrams/classdiagram.puml @@ -0,0 +1,463 @@ +@startuml +' skinparam linetype ortho +' skinparam groupInheritance 2 +allowmixing + +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() + } + } + +} + +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() + } + } +} + +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() + } + } +} + +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() + } +} + +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 +} + +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 + +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 + +Subscription <. SubscriptionAction: ID +' Subscription <.. SubscriptionDataAccessService: DB +' SubscriptionAction <.. SubscriptionDataAccessService: DB +SubscriptionService --o SubscriptionController +SubscriptionDao <.. SubscriptionService: <<use>> +Subscription --o SubscriptionTitles +EpisodeActionPost -o SubscriptionTitles +SubscriptionDao <|. SubscriptionDataAccessService: <<realize>> + +' User <.. AuthenticationDataAccessService: DB +' User <.. JdbcUserDetailsManager: DB +UserDetailsManager <.. AuthenticationService: <<use>> +' AuthenticationDao <.. AuthenticationService: <<use>> +AuthenticationService --o AuthenticationController +' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>> +UserDetailsManager <|. JdbcUserDetailsManager: <<realize>> +UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>> +UserDetails <|.. User: <<realize>> +User -> Authority +GrantedAuthority <|.. Authority: <<realize>> +JavaMailSenderImpl <. AuthenticationService: <<use>> + +Action <-- EpisodeAction +EpisodeActionPost -o EpisodeActionGetResponse +EpisodeActionPost -o EpisodeActionPostRequest +EpisodeAction .> Episode: ID +' EpisodeAction <.. EpisodeActionDataAccessService: DB +' Episode <.. EpisodeActionDataAccessService: DB +EpisodeActionDao <.. EpisodeActionService: <<use>> +EpisodeActionService --o EpisodeActionController +EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>> + +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 |