From e45117b57ffda2f58b4f10dc91e147fdef4a7e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Thu, 24 Oct 2024 16:37:15 +0200 Subject: [PATCH] database WIP --- pom.xml | 13 +++++ .../ph87/tools/session/AbstractSession.java | 54 ++++++++++++------ .../session/AbstractSessionController.java | 18 ++---- .../tools/session/AbstractSessionDto.java | 8 +-- src/main/java/de/ph87/tools/user/User.java | 55 +++++++++++++------ .../de/ph87/tools/user/UserPrivateDto.java | 4 +- .../de/ph87/tools/user/UserRepository.java | 7 +++ .../java/de/ph87/tools/user/UserService.java | 26 +++------ 8 files changed, 116 insertions(+), 69 deletions(-) create mode 100644 src/main/java/de/ph87/tools/user/UserRepository.java diff --git a/pom.xml b/pom.xml index 6de0e12..3f21938 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,19 @@ spring-boot-starter-websocket + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + org.postgresql + postgresql + + org.projectlombok lombok diff --git a/src/main/java/de/ph87/tools/session/AbstractSession.java b/src/main/java/de/ph87/tools/session/AbstractSession.java index 1d981bd..9f61da9 100644 --- a/src/main/java/de/ph87/tools/session/AbstractSession.java +++ b/src/main/java/de/ph87/tools/session/AbstractSession.java @@ -2,10 +2,8 @@ package de.ph87.tools.session; import de.ph87.tools.user.User; import de.ph87.tools.web.IWebSocketMessage; -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; -import lombok.ToString; +import jakarta.persistence.*; +import lombok.*; import java.time.ZonedDateTime; import java.util.HashSet; @@ -13,36 +11,47 @@ import java.util.List; import java.util.Set; import java.util.UUID; +@Entity @Getter @ToString +@NoArgsConstructor public abstract class AbstractSession implements IWebSocketMessage { + @Id @NonNull - public final String uuid = UUID.randomUUID().toString(); + @Column(nullable = false) + private String uuid = UUID.randomUUID().toString(); @NonNull - public final User owner; + @ManyToOne(optional = false) + private User owner; @NonNull - public final ZonedDateTime created = ZonedDateTime.now(); + @Column(nullable = false) + private ZonedDateTime created = ZonedDateTime.now(); @NonNull + @ManyToMany @ToString.Exclude - private final Set users = new HashSet<>(); + private Set users = new HashSet<>(); @Setter @NonNull - public String title = "Spiel ohne Namen"; + @Column(nullable = false) + private String title = "Spiel ohne Namen"; @Setter @NonNull @ToString.Exclude + @Column(nullable = false) private String password = UUID.randomUUID().toString().substring(0, 4); @Setter + @Column(nullable = false) private boolean initial = true; @NonNull + @Column(nullable = false) private ZonedDateTime lastAccess = created; protected AbstractSession(@NonNull final User user) { @@ -50,16 +59,12 @@ public abstract class AbstractSession implements IWebSocketMessage { } public void join(@NonNull final User user) { - synchronized (uuid) { - users.add(user); - touch(); - } + users.add(user); + touch(); } public void leave(@NonNull final User user) { - synchronized (uuid) { - users.remove(user); - } + users.remove(user); } private void touch() { @@ -71,4 +76,21 @@ public abstract class AbstractSession implements IWebSocketMessage { return List.of("Number", uuid); } + public boolean isOwnedBy(@NonNull final User user) { + return owner.equals(user); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof final AbstractSession session)) { + return false; + } + return session.uuid.equals(this.uuid); + } + + @Override + public int hashCode() { + return uuid.hashCode(); + } + } diff --git a/src/main/java/de/ph87/tools/session/AbstractSessionController.java b/src/main/java/de/ph87/tools/session/AbstractSessionController.java index ad94565..05a1aed 100644 --- a/src/main/java/de/ph87/tools/session/AbstractSessionController.java +++ b/src/main/java/de/ph87/tools/session/AbstractSessionController.java @@ -40,9 +40,7 @@ public abstract class AbstractSessionController @Scheduled(timeUnit = TimeUnit.MINUTES, initialDelay = 5, fixedRate = 5) public void cleanUp() { final ZonedDateTime deadline = ZonedDateTime.now().minusDays(30); - synchronized (sessions) { - sessions.stream().filter(session -> session.getLastAccess().isBefore(deadline)).forEach(this::delete); - } + sessions.stream().filter(session -> session.getLastAccess().isBefore(deadline)).forEach(this::delete); } private void delete(@NonNull final SESSION session) { @@ -63,9 +61,7 @@ public abstract class AbstractSessionController final SESSION session = create(user); log.info("Session CREATED: {}", session); - synchronized (sessions) { - sessions.add(session); - } + sessions.add(session); return join(session, user); } @@ -110,7 +106,7 @@ public abstract class AbstractSessionController public AbstractSessionDto changeTitle(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid, @RequestBody final SessionChangeTitleInbound inbound) { final User user = userService.getByPrivateUuidOrThrow(userUuid); final SESSION session = getUserSession(user, inbound.uuid); - if (session.owner != user) { + if (session.isOwnedBy(user)) { throw new ResponseStatusException(HttpStatus.FORBIDDEN); } session.setTitle(inbound.title); @@ -122,7 +118,7 @@ public abstract class AbstractSessionController public AbstractSessionDto changePassword(@CookieValue(name = USER_UUID_COOKIE_NAME) @NonNull final String userUuid, @RequestBody final SessionChangePasswordInbound inbound) { final User user = userService.getByPrivateUuidOrThrow(userUuid); final SESSION session = getUserSession(user, inbound.uuid); - if (session.owner != user) { + if (session.isOwnedBy(user)) { throw new ResponseStatusException(HttpStatus.FORBIDDEN); } session.setPassword(inbound.password); @@ -147,14 +143,12 @@ public abstract class AbstractSessionController @NonNull private Optional findUserSession(@NonNull final User user, @NonNull final String sessionUuid) { - return user.getSessions().stream().filter(s -> s.uuid.equals(sessionUuid)).filter(sessionClazz::isInstance).map(sessionClazz::cast).findFirst(); + return user.getSessions().stream().filter(s -> s.getUuid().equals(sessionUuid)).filter(sessionClazz::isInstance).map(sessionClazz::cast).findFirst(); } @NonNull private SESSION getSessionByUuid(@NonNull final String uuid) { - synchronized (sessions) { - return sessions.stream().filter(u -> u.getUuid().equals(uuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); - } + return sessions.stream().filter(u -> u.getUuid().equals(uuid)).findFirst().orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); } @NonNull diff --git a/src/main/java/de/ph87/tools/session/AbstractSessionDto.java b/src/main/java/de/ph87/tools/session/AbstractSessionDto.java index 5881d4a..dd8344e 100644 --- a/src/main/java/de/ph87/tools/session/AbstractSessionDto.java +++ b/src/main/java/de/ph87/tools/session/AbstractSessionDto.java @@ -40,11 +40,11 @@ public abstract class AbstractSessionDto { protected AbstractSessionDto(@NonNull final AbstractSession session, @NonNull final String type) { this.type = type; - this.uuid = session.uuid; - this.title = session.title; - this.created = session.created; + this.uuid = session.getUuid(); + this.title = session.getTitle(); + this.created = session.getCreated(); this.password = session.getPassword(); - this.owner = new UserPublicDto(session.owner); + this.owner = new UserPublicDto(session.getOwner()); this.users = session.getUsers().stream().map(UserPublicDto::new).collect(Collectors.toSet()); this.initial = session.isInitial(); } diff --git a/src/main/java/de/ph87/tools/user/User.java b/src/main/java/de/ph87/tools/user/User.java index 9c10bd9..e40d804 100644 --- a/src/main/java/de/ph87/tools/user/User.java +++ b/src/main/java/de/ph87/tools/user/User.java @@ -1,12 +1,12 @@ package de.ph87.tools.user; -import com.fasterxml.jackson.annotation.JsonIgnore; import de.ph87.tools.session.AbstractSession; import de.ph87.tools.web.IWebSocketMessage; -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; -import lombok.ToString; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; +import lombok.*; import java.time.ZonedDateTime; import java.util.HashSet; @@ -14,43 +14,49 @@ import java.util.List; import java.util.Set; import java.util.UUID; +@Entity @Getter @ToString +@NoArgsConstructor public class User implements IWebSocketMessage { + @Id @NonNull - public final String privateUuid = UUID.randomUUID().toString(); + @Column(nullable = false) + private String privateUuid = UUID.randomUUID().toString(); @NonNull - public final String publicUuid = UUID.randomUUID().toString(); + @Column(nullable = false) + private String publicUuid = UUID.randomUUID().toString(); - public final ZonedDateTime created = ZonedDateTime.now(); + @NonNull + @Column(nullable = false) + private ZonedDateTime created = ZonedDateTime.now(); - @JsonIgnore + @ManyToMany @ToString.Exclude - private final Set sessions = new HashSet<>(); + private Set sessions = new HashSet<>(); + @NonNull + @Column(nullable = false) private ZonedDateTime lastAccess = created; @Setter @NonNull - public String name = "unnamed"; + @Column(nullable = false) + private String name = "Neuer Benutzer"; private void touch() { lastAccess = ZonedDateTime.now(); } public void join(@NonNull final AbstractSession session) { - synchronized (privateUuid) { - sessions.add(session); - touch(); - } + sessions.add(session); + touch(); } public void leave(@NonNull final AbstractSession session) { - synchronized (sessions) { - sessions.remove(session); - } + sessions.remove(session); } @Override @@ -58,4 +64,17 @@ public class User implements IWebSocketMessage { return List.of("User", privateUuid); } + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof final User user)) { + return false; + } + return user.privateUuid.equals(this.privateUuid); + } + + @Override + public int hashCode() { + return privateUuid.hashCode(); + } + } diff --git a/src/main/java/de/ph87/tools/user/UserPrivateDto.java b/src/main/java/de/ph87/tools/user/UserPrivateDto.java index 8a503df..bc47c4b 100644 --- a/src/main/java/de/ph87/tools/user/UserPrivateDto.java +++ b/src/main/java/de/ph87/tools/user/UserPrivateDto.java @@ -32,8 +32,8 @@ public class UserPrivateDto { public UserPrivateDto(@NonNull final User user) { this.publicUuid = user.getPublicUuid(); this.name = user.getName(); - this.privateUuid = user.privateUuid; - this.created = user.created; + this.privateUuid = user.getPrivateUuid(); + this.created = user.getCreated(); this.sessions = user.getSessions().stream().map(AbstractSessionDto::toDto).collect(Collectors.toSet()); } diff --git a/src/main/java/de/ph87/tools/user/UserRepository.java b/src/main/java/de/ph87/tools/user/UserRepository.java new file mode 100644 index 0000000..4b318b5 --- /dev/null +++ b/src/main/java/de/ph87/tools/user/UserRepository.java @@ -0,0 +1,7 @@ +package de.ph87.tools.user; + +import org.springframework.data.repository.ListCrudRepository; + +public interface UserRepository extends ListCrudRepository { + +} diff --git a/src/main/java/de/ph87/tools/user/UserService.java b/src/main/java/de/ph87/tools/user/UserService.java index 91a0afb..4bb406d 100644 --- a/src/main/java/de/ph87/tools/user/UserService.java +++ b/src/main/java/de/ph87/tools/user/UserService.java @@ -30,11 +30,9 @@ public class UserService { @NonNull public User getUserByUuidOrElseCreate(@Nullable final String uuid, @NonNull final HttpServletResponse response) { - synchronized (users) { - final User user = Optional.ofNullable(uuid).map(this::findByPrivateUuid).filter(Optional::isPresent).map(Optional::get).orElseGet(this::create); - writeUserUuidCookie(response, user); - return user; - } + final User user = Optional.ofNullable(uuid).map(this::findByPrivateUuid).filter(Optional::isPresent).map(Optional::get).orElseGet(this::create); + writeUserUuidCookie(response, user); + return user; } @Nullable @@ -48,26 +46,20 @@ public class UserService { } public void delete(@NonNull final String userUuid, final @NonNull HttpServletResponse response) { - synchronized (users) { - final User user = findByPrivateUuid(userUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); - users.remove(user); - log.info("User DELETED: {}", user); - } + final User user = findByPrivateUuid(userUuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); + users.remove(user); + log.info("User DELETED: {}", user); writeUserUuidCookie(response, null); } @NonNull public User getByPrivateUuidOrThrow(@NonNull final String uuid) { - synchronized (users) { - return findByPrivateUuid(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); - } + return findByPrivateUuid(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); } @NonNull public User getByPublicUuid(@NonNull final String uuid) { - synchronized (users) { - return findByPublicUuid(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); - } + return findByPublicUuid(uuid).orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST)); } @NonNull @@ -91,7 +83,7 @@ public class UserService { private static void writeUserUuidCookie(@NonNull final HttpServletResponse response, @Nullable final User user) { final Cookie cookie = new Cookie(USER_UUID_COOKIE_NAME, ""); if (user != null) { - cookie.setValue(user.privateUuid); + cookie.setValue(user.getPrivateUuid()); } cookie.setMaxAge(10 * 365 * 24 * 60 * 60); cookie.setPath("/");