database WIP
This commit is contained in:
parent
d1521417cf
commit
e45117b57f
13
pom.xml
13
pom.xml
@ -32,6 +32,19 @@
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
||||
@ -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<User> users = new HashSet<>();
|
||||
private Set<User> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -40,9 +40,7 @@ public abstract class AbstractSessionController<SESSION extends AbstractSession>
|
||||
@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<SESSION extends AbstractSession>
|
||||
|
||||
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<SESSION extends AbstractSession>
|
||||
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<SESSION extends AbstractSession>
|
||||
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<SESSION extends AbstractSession>
|
||||
|
||||
@NonNull
|
||||
private Optional<SESSION> 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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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<AbstractSession> sessions = new HashSet<>();
|
||||
private Set<AbstractSession> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
7
src/main/java/de/ph87/tools/user/UserRepository.java
Normal file
7
src/main/java/de/ph87/tools/user/UserRepository.java
Normal file
@ -0,0 +1,7 @@
|
||||
package de.ph87.tools.user;
|
||||
|
||||
import org.springframework.data.repository.ListCrudRepository;
|
||||
|
||||
public interface UserRepository extends ListCrudRepository<User, String> {
|
||||
|
||||
}
|
||||
@ -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("/");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user