diff options
author | Orangerot <purple@orangerot.dev> | 2024-06-19 00:14:49 +0200 |
---|---|---|
committer | Orangerot <purple@orangerot.dev> | 2024-06-27 12:11:14 +0200 |
commit | 5b8851b6c268d0e93c158908fbfae9f8473db5ff (patch) | |
tree | 7010eb85d86fa2da06ea4ffbcdb01a685d502ae8 /pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller |
Diffstat (limited to 'pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller')
4 files changed, 265 insertions, 0 deletions
diff --git a/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionController.java b/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionController.java new file mode 100644 index 0000000..1ffe137 --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionController.java @@ -0,0 +1,155 @@ +package org.psesquared.server.subscriptions.api.controller; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.psesquared.server.subscriptions.api.service.SubscriptionService; +import org.psesquared.server.util.UpdateUrlsWrapper; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * This is a controller class for the Subscription API that handles the requests + * from the client concerning adding subscriptions, removing subscriptions and + * getting all current subscriptions. + * In the end an appropriate response is sent back to the user. + */ +@RestController +@RequiredArgsConstructor +public class SubscriptionController { + + /** + * The response for uploading subscriptions successfully. + */ + private static final String UPLOAD_SUCCESS = ""; + + /** + * The service class that this controller calls to further process requests. + */ + private final SubscriptionService subscriptionService; + + /** + * It takes a list of strings containing the URLs of all subscribed podcasts, + * and saves them to the database. + * + * @param username The username of the user + * @param deviceId The device ID of the device that is uploading the + * subscriptions (will be ignored in this implementation) + * @param subscriptions A list of strings, each string is the URL to a podcast + * RSS-Feed that was subscribed + * @return The response containing an empty String with + * <br> + * {@link HttpStatus#OK} on success, + * <br> + * {@link HttpStatus#NOT_FOUND} user not found + */ + @PutMapping(path = "/subscriptions/{username}/{deviceId}.json") + public ResponseEntity<String> uploadSubscriptions( + @PathVariable final String username, + @PathVariable final String deviceId, + @RequestBody final List<String> subscriptions) { + HttpStatus status + = subscriptionService.uploadSubscriptions(username, subscriptions); + return new ResponseEntity<>(UPLOAD_SUCCESS, status); + } + + /** + * This function returns a list of subscriptions for a given user. + * + * @param username The username of the user whose subscriptions you want + * to retrieve + * @param deviceId This is the unique identifier for the device of the + * user whose subscriptions are asked for + * (will be ignored in this implementation) + * @param functionJsonp This parameter is not supported in this implementation + * and is thus ignored + * @return A list of strings containing the RSS-Feed URLs of all subscribed + * podcasts + */ + @GetMapping(path = {"/subscriptions/{username}.json", + "/subscriptions/{username}/{deviceId}.json"}) + public ResponseEntity<List<String>> getSubscriptions( + @PathVariable final String username, + @PathVariable(required = false) final String deviceId, + @RequestParam(value = "jsonp", + required = false) final String functionJsonp) { + List<String> subscriptions = subscriptionService.getSubscriptions(username); + return ResponseEntity.ok(subscriptions); + } + + /** + * This function takes the information of added and removed podcasts in the + * form of a SubcriptionDelta as a JSON object. + * <br> + * After that, it applies the changes to the given user in the database. + * + * @param username The username of the user who is making changes to their + * subscriptions + * @param deviceId The device ID of the device that is requesting the update + * (will be ignored in this implementation) + * @param delta Contains all the changes that were made to the + * subscriptions of the user + * @return The response containing a placeholder for not + * supported function with + * <br> + * {@link HttpStatus#OK} on success, + * <br> + * {@link HttpStatus#NOT_FOUND} user or subscription not found + */ + @PostMapping(path = "/api/2/subscriptions/{username}/{deviceId}.json") + public ResponseEntity<UpdateUrlsWrapper> applySubscriptionDelta( + @PathVariable final String username, + @PathVariable final String deviceId, + @RequestBody final SubscriptionDelta delta) { + subscriptionService.applySubscriptionDelta(username, delta); + return ResponseEntity.ok(new UpdateUrlsWrapper()); + } + + /** + * It returns a list of all the changes to the subscriptions of a user since a + * given time. + * + * @param username The username of the user whose SubscriptionDeltas are being + * requested + * @param deviceId The device ID of the device that is requesting the delta + * (will be ignored in this implementation) + * @param since The timestamp of the last time the client checked for + * updates + * @return A response containing the SubscriptionDelta of all changes that + * were made in a JSON format + */ + @GetMapping(path = "/api/2/subscriptions/{username}/{deviceId}.json") + public ResponseEntity<SubscriptionDelta> getSubscriptionDelta( + @PathVariable final String username, + @PathVariable final String deviceId, + @RequestParam("since") final long since) { + SubscriptionDelta delta + = subscriptionService.getSubscriptionDelta(username, since); + return ResponseEntity.ok(delta); + } + + /** + * This function returns a list of podcasts a user is subscribed to. + * <br> + * This includes not only the podcast itself, but also the latest 20 Episodes + * of the podcast. + * + * @param username The username of the user whose podcasts are being requested + * @return A response containing a List of podcasts and their episodes the + * user is subscribed to + */ + @GetMapping(path = "/subscriptions/titles/{username}.json") + public ResponseEntity<List<SubscriptionTitles>> getTitles( + @PathVariable final String username) { + List<SubscriptionTitles> responseBody + = subscriptionService.getTitles(username); + return ResponseEntity.ok(responseBody); + } + +} diff --git a/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionDelta.java b/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionDelta.java new file mode 100644 index 0000000..7611b05 --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionDelta.java @@ -0,0 +1,80 @@ +package org.psesquared.server.subscriptions.api.controller; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.List; +import lombok.NonNull; + +/** + * SubscriptionDeltas contain all changes that were made to the subscriptions + * of a user (added / removed podcasts) at a certain time. + */ +public class SubscriptionDelta { + + /** + * The list of recently subscribed podcasts. + */ + @JsonProperty(required = true) + @NonNull + private final List<String> add; + + /** + * The list of recently unsubscribed podcasts. + */ + @JsonProperty(required = true) + @NonNull + private final List<String> remove; + + /** + * The timestamp of the delta. + */ + @JsonProperty(access = JsonProperty.Access.READ_ONLY) + private final long timestamp; + + /** + * Instantiates a new SubscriptionDelta with a current timestamp. + * + * @param addedPodcastUrls List of Strings containing the RSS-Feed URLs of + * all added podcasts + * @param removedPodcastUrls List of Strings containing the RSS-Feed URLs of + * all removed podcasts + */ + public SubscriptionDelta( + @org.springframework.lang.NonNull final List<String> addedPodcastUrls, + @org.springframework.lang.NonNull final List<String> removedPodcastUrls) { + this.add = addedPodcastUrls; + this.remove = removedPodcastUrls; + this.timestamp = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC); + } + + /** + * Returns the list of RSS-Feed URLs of all added podcasts. + * + * @return RSS-Feed URLs of all added podcasts + */ + @org.springframework.lang.NonNull + public List<String> getAdd() { + return add; + } + + /** + * Returns the list of RSS-Feed URLs of all removed podcasts. + * + * @return RSS-Feed URLs of all removed podcasts + */ + @org.springframework.lang.NonNull + public List<String> getRemove() { + return remove; + } + + /** + * Returns the timestamp of when this Subscription Delta was uploaded. + * + * @return The timestamp of when this Subscription Delta was uploaded + */ + public long getTimestamp() { + return timestamp; + } + +} diff --git a/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionTitles.java b/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionTitles.java new file mode 100644 index 0000000..682497b --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionTitles.java @@ -0,0 +1,17 @@ +package org.psesquared.server.subscriptions.api.controller; + +import com.fasterxml.jackson.annotation.JsonUnwrapped; +import java.util.List; +import org.psesquared.server.episode.actions.api.controller.EpisodeActionPost; +import org.psesquared.server.model.Subscription; + +/** + * Contains a podcast and its latest 20 Episodes. + * + * @param subscription The podcast + * @param episodes The episodes of the podcast + */ +public record SubscriptionTitles( + @JsonUnwrapped Subscription subscription, + List<EpisodeActionPost> episodes) { +} diff --git a/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/package-info.java b/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/package-info.java new file mode 100644 index 0000000..0238039 --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/package-info.java @@ -0,0 +1,13 @@ +/** + * This package represents the highest logical layer of the subscription API + * ({@link org.psesquared.server.subscriptions.api}) - the controller layer. + * <br> + * It contains the + * {@link + * org.psesquared.server.subscriptions.api.controller.SubscriptionController} + * along with some wrapper classes for JSON request and response bodies. + * + * @author PSE-Squared Team + * @version 1.0 + */ +package org.psesquared.server.subscriptions.api.controller; |