summaryrefslogtreecommitdiff
path: root/pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller
diff options
context:
space:
mode:
authorOrangerot <purple@orangerot.dev>2024-06-19 00:14:49 +0200
committerOrangerot <purple@orangerot.dev>2024-06-27 12:11:14 +0200
commit5b8851b6c268d0e93c158908fbfae9f8473db5ff (patch)
tree7010eb85d86fa2da06ea4ffbcdb01a685d502ae8 /pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller
Initial commitHEADmain
Diffstat (limited to 'pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller')
-rw-r--r--pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionController.java155
-rw-r--r--pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionDelta.java80
-rw-r--r--pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/SubscriptionTitles.java17
-rw-r--r--pse-server/src/main/java/org/psesquared/server/subscriptions/api/controller/package-info.java13
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;