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/model |
Diffstat (limited to 'pse-server/src/main/java/org/psesquared/server/model')
8 files changed, 553 insertions, 0 deletions
diff --git a/pse-server/src/main/java/org/psesquared/server/model/Action.java b/pse-server/src/main/java/org/psesquared/server/model/Action.java new file mode 100644 index 0000000..19b1c51 --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/model/Action.java @@ -0,0 +1,45 @@ +package org.psesquared.server.model; + +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * An enum with all different action types of an {@link EpisodeAction}. + */ +public enum Action { + + /** + * The download action type. + */ + DOWNLOAD, + + /** + * The play action type. + */ + PLAY, + + /** + * The delete action type. + */ + DELETE, + + /** + * The new action type. + */ + NEW, + + /** + * The flattr action type. + */ + FLATTR; + + /** + * Getter for the value of the "action" JSON property. + * + * @return The JSON value + */ + @JsonValue + public String getJsonProperty() { + return name().toLowerCase(); + } + +} diff --git a/pse-server/src/main/java/org/psesquared/server/model/Episode.java b/pse-server/src/main/java/org/psesquared/server/model/Episode.java new file mode 100644 index 0000000..7a409fc --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/model/Episode.java @@ -0,0 +1,74 @@ +package org.psesquared.server.model; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * An episode of a podcast. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "episodes") +public class Episode implements Serializable { + + /** + * The primary key for the table. + */ + @Id + @GeneratedValue(strategy=GenerationType.SEQUENCE) + @Column(name = "id", updatable = false) + private Long id; + + /** + * The GUID of an episode. + */ + @Column(name = "guid", unique = true) + private String guid; + + /** + * The URL where the episode is located at. + */ + @Column(name = "url", nullable = false) + private String url; + + /** + * The title of the episode. + */ + @Column(name = "title") + private String title; + + /** + * The total length of an episode. + */ + @Column(name = "total") + private int total; + + /** + * The podcast the episode is a part of. + */ + @ManyToOne(optional = false) + private Subscription subscription; + + /** + * The actions of an episode. + */ + @OneToMany(mappedBy = "episode", cascade = CascadeType.REMOVE) + private List<EpisodeAction> episodeActions; + +} diff --git a/pse-server/src/main/java/org/psesquared/server/model/EpisodeAction.java b/pse-server/src/main/java/org/psesquared/server/model/EpisodeAction.java new file mode 100644 index 0000000..a7e2375 --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/model/EpisodeAction.java @@ -0,0 +1,101 @@ +package org.psesquared.server.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.io.Serializable; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.psesquared.server.episode.actions.api.controller.EpisodeActionPost; + +/** + * An action a user took regarding an episode of a podcast. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "episode_actions") +public class EpisodeAction implements Serializable { + + /** + * The primary key for the table. + */ + @JsonIgnore + @Id + @GeneratedValue(strategy=GenerationType.SEQUENCE) + @Column(name = "id", updatable = false) + private Long id; + + /** + * The user who is responsible for the action. + */ + @JsonIgnore + @ManyToOne(optional = false) + private User user; + + /** + * The episode that is affected. + */ + @JsonIgnore + @ManyToOne(optional = false) + private Episode episode; + + /** + * The timestamp of when this action took place. + */ + @Column(name = "timestamp", + nullable = false) + private LocalDateTime timestamp; + + /** + * The type of action that happened. + */ + @JsonProperty(required = true) + @Column(name = "action", + nullable = false, + updatable = false) + private Action action; + + /** + * In case of play action: The starting time of the episode. + */ + @Column(name = "started", + updatable = false) + private int started; + + /** + * In case of play action: The time at which the episode was stopped. + */ + @Column(name = "position", + nullable = false, + updatable = false) + private int position; + + /** + * Generates a EpisodeActionPost from the given EpisodeAction for the + * EpisodeAction Controller. + * + * @return The generated EpisodeActionPost + */ + public EpisodeActionPost toEpisodeActionPost() { + String podcastUrl = this.getEpisode().getSubscription().getUrl(); + String episodeUrl = this.getEpisode().getUrl(); + String title = this.getEpisode().getTitle(); + String guid = this.getEpisode().getGuid(); + int total = this.getEpisode().getTotal(); + return + new EpisodeActionPost(podcastUrl, episodeUrl, title, guid, total, this); + } + +} diff --git a/pse-server/src/main/java/org/psesquared/server/model/Role.java b/pse-server/src/main/java/org/psesquared/server/model/Role.java new file mode 100644 index 0000000..37a316f --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/model/Role.java @@ -0,0 +1,28 @@ +package org.psesquared.server.model; + +/** + * Available user roles. + */ +public enum Role { + + /** + * Standard role. + */ + USER, + + /** + * Privileged role. + */ + ADMIN; + + /** + * The starting index. + */ + private static final int FIRST_INDEX = 0; + + @Override + public String toString() { + return name().charAt(FIRST_INDEX) + name().substring(1).toLowerCase(); + } + +} diff --git a/pse-server/src/main/java/org/psesquared/server/model/Subscription.java b/pse-server/src/main/java/org/psesquared/server/model/Subscription.java new file mode 100644 index 0000000..b130fca --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/model/Subscription.java @@ -0,0 +1,87 @@ +package org.psesquared.server.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedAttributeNode; +import jakarta.persistence.NamedEntityGraph; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +/** + * A podcast that was subscribed. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "subscriptions") +@NamedEntityGraph(name = "graph.Subscription.episodes", + attributeNodes = @NamedAttributeNode("episodes")) +public class Subscription implements Serializable { + + /** + * A primary key for the table. + */ + @JsonIgnore + @Id + @GeneratedValue(strategy=GenerationType.SEQUENCE) + @Column(name = "id", updatable = false) + private Long id; + + /** + * The URL for the RSS-Feed of the Podcast. + */ + @Column(name = "url", nullable = false) + private String url; + + /** + * The title of the Podcast. + */ + @Column(name = "title") + private String title; + + /** + * Timestamp of the last time the RSS-Feed was fetched. + */ + @Column(name = "timestamp") + private long timestamp; + + /** + * The list of SubscriptionActions of this podcast. + */ + @JsonIgnore + @OneToMany(mappedBy = "subscription", + cascade = CascadeType.REMOVE) + private List<SubscriptionAction> subscriptionActions; + + /** + * The episodes of a subscription. + */ + @JsonIgnore + @OneToMany(mappedBy = "subscription", cascade = CascadeType.REMOVE) + private final List<Episode> episodes = new ArrayList<>(); + + /** + * Adds an episode to the list of episodes. + * + * @param episode The to be added episode + */ + public void addEpisode(@NonNull final Episode episode) { + this.episodes.add(episode); + } + +} diff --git a/pse-server/src/main/java/org/psesquared/server/model/SubscriptionAction.java b/pse-server/src/main/java/org/psesquared/server/model/SubscriptionAction.java new file mode 100644 index 0000000..3d850eb --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/model/SubscriptionAction.java @@ -0,0 +1,62 @@ +package org.psesquared.server.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * An action a user took regarding a podcast. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "subscription_actions") +public class SubscriptionAction implements Serializable { + + /** + * The primary key for the table. + */ + @Id + @GeneratedValue(strategy=GenerationType.SEQUENCE) + @Column(name = "id", + updatable = false) + private int id; + + /** + * The user who took this action. + */ + @ManyToOne(optional = false) + private User user; + + /** + * The timestamp of when this action took place. + */ + @Column(name = "timestamp", + nullable = false) + private long timestamp; + + /** + * The podcast that was affected. + */ + @ManyToOne(optional = false) + private Subscription subscription; + + /** + * Whether the podcast was added or removed. + */ + @Column(name = "added", + nullable = false) + private boolean added; + +} diff --git a/pse-server/src/main/java/org/psesquared/server/model/User.java b/pse-server/src/main/java/org/psesquared/server/model/User.java new file mode 100644 index 0000000..7279aae --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/model/User.java @@ -0,0 +1,148 @@ +package org.psesquared.server.model; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.util.Collection; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +/** + * A user that synchronizes their podcasts via this server. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "users") +public class User implements UserDetails { + + /** + * The primary key for the table. + */ + @Id + @GeneratedValue(strategy=GenerationType.SEQUENCE) + @Column(name = "id", + updatable = false) + private Long id; + + /** + * The username of the user. + */ + @Column(name = "username", + unique = true, + nullable = false, + updatable = false) + private String username; + + /** + * The email address of the user. + */ + @Column(name = "email", + unique = true, + nullable = false) + private String email; + + /** + * The password of the user. + */ + @Column(name = "password", + nullable = false) + private String password; + + /** + * The verification status of the user. + */ + @Column(name = "enabled", + nullable = false) + private boolean enabled; + + /** + * Timestamp of when this user account was created. + */ + @Column(name = "created_at", + nullable = false, + updatable = false) + private long createdAt; + + /** + * The role of the user. + */ + @Column(name = "role", + nullable = false) + private Role role; + + /** + * The subscription actions the user made. + */ + @OneToMany(mappedBy = "user", + cascade = CascadeType.REMOVE) + private List<SubscriptionAction> subscriptionActions; + + /** + * The episode actions the user made. + */ + @OneToMany(mappedBy = "user", + cascade = CascadeType.REMOVE) + private List<EpisodeAction> episodeActions; + + /** + * Returns a collection with one {@link SimpleGrantedAuthority} + * with {@link #role}. + * + * @return The collection of granted authorities + */ + @Override + public Collection<? extends GrantedAuthority> getAuthorities() { + return List.of(new SimpleGrantedAuthority(role.toString())); + } + + /** + * Checks if this user account has not expired. + * + * @return {@code true} if the user account has not expired, + * <br> + * {@code false} otherwise + */ + @Override + public boolean isAccountNonExpired() { + return enabled; + } + + /** + * Checks if this user account is not locked. + * + * @return {@code true} if the user account is not locked, + * <br> + * {@code false} otherwise + */ + @Override + public boolean isAccountNonLocked() { + return enabled; + } + + /** + * Checks if this user account's credentials have not expired. + * + * @return {@code true} if the credentials have not expired, + * <br> + * {@code false} otherwise + */ + @Override + public boolean isCredentialsNonExpired() { + return enabled; + } + +} diff --git a/pse-server/src/main/java/org/psesquared/server/model/package-info.java b/pse-server/src/main/java/org/psesquared/server/model/package-info.java new file mode 100644 index 0000000..2bb9c13 --- /dev/null +++ b/pse-server/src/main/java/org/psesquared/server/model/package-info.java @@ -0,0 +1,8 @@ +/** + * This package features all classes that map to database entities via ORM + * as well as some classes that the former rely on. + * + * @author PSE-Squared Team + * @version 1.0 + */ +package org.psesquared.server.model; |