diff --git a/Multi-Chess.xml b/Multi-Chess.xml
new file mode 100644
index 0000000..60ceb42
--- /dev/null
+++ b/Multi-Chess.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 4fc1d1f..1c6072a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,10 +10,6 @@ repositories {
jcenter()
}
-dependencies {
- testCompile group: 'junit', name: 'junit', version: '4.12'
-}
-
subprojects {
apply plugin: 'java'
@@ -27,7 +23,15 @@ subprojects {
compileOnly 'org.projectlombok:lombok:1.18.16'
annotationProcessor 'org.projectlombok:lombok:1.18.16'
+ testImplementation('org.junit.jupiter:junit-jupiter:5.7.0')
+ testImplementation('org.mockito:mockito-core:3.7.0')
+ testImplementation('org.hamcrest:hamcrest-core:2.2')
+
testCompileOnly 'org.projectlombok:lombok:1.18.16'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.16'
}
+
+ test {
+ useJUnitPlatform()
+ }
}
diff --git a/fh.fd.ci.server/build.gradle b/fh.fd.ci.server/build.gradle
index ad6ace5..2bf768e 100644
--- a/fh.fd.ci.server/build.gradle
+++ b/fh.fd.ci.server/build.gradle
@@ -2,4 +2,13 @@ dependencies {
implementation project(':fh.fd.ci.shared')
compile 'com.sparkjava:spark-core:2.9.3'
+ compile 'dev.morphia.morphia:core:1.5.3'
+ compile 'com.fasterxml.jackson.core:jackson-databind:2.9.5'
+
+ task startServer(type: JavaExec){
+ main = "de.fd.fh.ServerApp"
+ description = "Start server"
+ classpath = sourceSets.main.runtimeClasspath
+ }
+
}
\ No newline at end of file
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/ServerApp.java b/fh.fd.ci.server/src/main/java/de/fd/fh/ServerApp.java
index 384d27c..d275c81 100644
--- a/fh.fd.ci.server/src/main/java/de/fd/fh/ServerApp.java
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/ServerApp.java
@@ -1,12 +1,57 @@
package de.fd.fh;
+import de.fd.fh.server.access.AccessContextEventListener;
+import de.fd.fh.server.access.AccessRepository;
+import de.fd.fh.server.access.AccessService;
+import de.fd.fh.server.access.web.AccessController;
+import de.fd.fh.server.user.UserContextEventListener;
+import de.fd.fh.server.user.web.UserController;
+import de.fd.fh.server.user.UserRepository;
+import de.fd.fh.server.user.UserService;
+
+
+import java.util.HashSet;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.Set;
+
import static spark.Spark.*;
public class ServerApp
{
+ private static AccessRepository accessRepository;
+ private static UserRepository userRepository;
+
+ private static final Set listeners = new HashSet<>();
public static void main(String[] args)
{
+ initRepositories();
+
+ initListeners();
+
+ new AccessController((AccessService) addListeners(new AccessService(accessRepository)));
+ new UserController((UserService) addListeners(new UserService(userRepository)));
+
get("/hello", (req, res) -> "Hello World");
+
+ }
+
+ private static Object addListeners(Observable service)
+ {
+ listeners.forEach(service::addObserver);
+
+ return service;
+ }
+
+ private static void initListeners()
+ {
+ listeners.add(new AccessContextEventListener(accessRepository));
+ listeners.add(new UserContextEventListener(userRepository));
+ }
+
+ private static void initRepositories() {
+ accessRepository = new AccessRepository();
+ userRepository = new UserRepository();
}
}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/Access.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/Access.java
new file mode 100644
index 0000000..d3ab03b
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/Access.java
@@ -0,0 +1,46 @@
+package de.fd.fh.server.access;
+
+import de.fd.fh.server.user.UserId;
+import dev.morphia.annotations.Embedded;
+import dev.morphia.annotations.Entity;
+import dev.morphia.annotations.Id;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Entity("login")
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+public class Access
+{
+ @Id
+ private String _id;
+
+ private String name;
+
+ private String password;
+
+ @Embedded
+ private UserId userId;
+
+ @Embedded
+ private AccessToken token;
+
+ private Role role;
+
+ void removeToken()
+ {
+ this.token = null;
+ }
+
+ void setToken(final AccessToken token)
+ {
+ this.token = token;
+ }
+
+ void updatePassword(final String newPassword)
+ {
+ this.password = newPassword;
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessContextEventListener.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessContextEventListener.java
new file mode 100644
index 0000000..4920e07
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessContextEventListener.java
@@ -0,0 +1,28 @@
+package de.fd.fh.server.access;
+
+import de.fd.fh.server.user.events.ChangePasswordEvent;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Observable;
+import java.util.Observer;
+
+@RequiredArgsConstructor
+public class AccessContextEventListener implements Observer
+{
+ private final AccessRepository accessRepository;
+
+ @Override
+ public void update(Observable observable, Object o)
+ {
+ if(o instanceof ChangePasswordEvent)
+ {
+ final ChangePasswordEvent event = (ChangePasswordEvent) o;
+
+ final Access access = accessRepository.findByUserId(event.getUserId());
+
+ access.updatePassword(event.getNewPassword());
+
+ accessRepository.save(access);
+ }
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessRepository.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessRepository.java
new file mode 100644
index 0000000..7149cf6
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessRepository.java
@@ -0,0 +1,58 @@
+package de.fd.fh.server.access;
+
+import com.mongodb.MongoClient;
+import com.mongodb.WriteResult;
+import de.fd.fh.server.user.UserId;
+import dev.morphia.Datastore;
+import dev.morphia.Key;
+import dev.morphia.Morphia;
+
+public class AccessRepository
+{
+ private final Datastore datastore;
+
+ public AccessRepository()
+ {
+ System.out.println("AccessRepo");
+ final Morphia morphia = new Morphia();
+
+ morphia.mapPackage("de.fd.fh.server.access");
+
+ this.datastore = morphia.createDatastore(new MongoClient(), "smartwarfare");
+ datastore.ensureIndexes();
+ }
+
+ AccessRepository(Datastore datastore)
+ {
+ this.datastore = datastore;
+ }
+
+ public Key save(final Access access)
+ {
+ return datastore.save(access);
+ }
+
+ Access findByUserName(final String name)
+ {
+ return datastore.createQuery(Access.class)
+ .field("name").equal(name).first();
+ }
+
+ Access findByToken(final String token)
+ {
+ return datastore.createQuery(Access.class)
+ .field("token.token").equal(token).first();
+ }
+
+ Access findByUserId(final UserId userId)
+ {
+ return datastore.createQuery(Access.class)
+ .field("userId.identifier").equal(userId.getIdentifier()).first();
+ }
+
+ WriteResult deleteLoginByUserId(final UserId userId)
+ {
+ return datastore.delete(datastore.createQuery(Access.class)
+ .field("userId.identifier").equal(userId.getIdentifier()).first());
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessService.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessService.java
new file mode 100644
index 0000000..752d321
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessService.java
@@ -0,0 +1,152 @@
+package de.fd.fh.server.access;
+
+import de.fd.fh.server.access.events.AccountCreatedEvent;
+import de.fd.fh.server.access.events.AccountDeletedEvent;
+import de.fd.fh.server.user.UserId;
+import de.fd.fh.shared.network.messages.LoginRequest;
+import de.fd.fh.shared.network.messages.RegistrateRequest;
+import lombok.RequiredArgsConstructor;
+import org.bson.types.ObjectId;
+
+import java.util.Base64;
+import java.util.Observable;
+
+import static spark.Spark.halt;
+
+@RequiredArgsConstructor
+public class AccessService extends Observable
+{
+ private final AccessRepository accessRepository;
+
+ public AccessToken before(final String path, final String token) {
+ System.out.println("Pfad: " + path);
+ if (!(path.equals("/accounts/login")
+ || path.equals("/accounts/registrate")
+ ))
+ {
+ final AccessToken accessToken = authenticate(token);
+
+ if (accessToken == null)
+ {
+ halt(401);
+ }
+ return accessToken;
+ }
+ return null;
+ }
+
+ private AccessToken authenticate(final String bearerToken)
+ {
+ return accessRepository.findByToken(bearerToken.substring("Bearer ".length())).getToken();
+ }
+
+ public boolean createPlayer(RegistrateRequest message)
+ {
+ System.out.println("createPlayer: " + message);
+
+ if (userNameDoesNotExist(message.getUserName()))
+ {
+ System.out.println("Name does exist.");
+ return false;
+ }
+
+ final Access access = new Access(
+ new ObjectId().toHexString(),
+ message.getUserName(),
+ message.getPassword(),
+ UserId.random(),
+ null,
+ Role.USER
+ );
+
+ accessRepository.save(access);
+
+ setChanged();
+ notifyObservers(new AccountCreatedEvent(access.getName(),
+ access.getUserId()));
+
+ System.out.println("DBLogin: " + access);
+
+ return true;
+ }
+
+ private boolean userNameDoesNotExist(final String name)
+ {
+ final Access user = accessRepository.findByUserName(name);
+ return user != null;
+ }
+
+ public boolean logout(final String header)
+ {
+ try
+ {
+ System.out.println("logout " + header);
+
+ final Access access = accessRepository.findByToken(header.substring("Bearer ".length()));
+
+ access.removeToken();
+
+ accessRepository.save(access);
+
+ return true;
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+
+ return false;
+ }
+ }
+
+ public LoginRequest authorization(final String header)
+ {
+ System.out.println("authorization");
+ final String auth = header.substring("Basic ".length());
+
+ try
+ {
+ byte[] message = Base64.getDecoder().decode(auth);
+
+ String messageStr = new String(message);
+ String[] user_password = messageStr.split(":");
+
+ final Access access = accessRepository.findByUserName(user_password[0]);
+
+ System.out.println(access.getName());
+ if (user_password[1].equals(access.getPassword()))
+ {
+ access.setToken(AccessToken.of(access));
+ accessRepository.save(access);
+
+ final LoginRequest loginRequest = new LoginRequest();
+ loginRequest.setUserId(access.getUserId().getIdentifier());
+ loginRequest.setToken(access.getToken().getToken());
+ loginRequest.setName(access.getName());
+
+ return loginRequest;
+ }
+
+ return null;
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public boolean deleteAccount(final UserId userId, final AccessToken token)
+ {
+ if (!token.getUserId().getIdentifier()
+ .equals(userId.getIdentifier()))
+ {
+ return false;
+ }
+ if (accessRepository.deleteLoginByUserId(userId).wasAcknowledged())
+ {
+ setChanged();
+ notifyObservers(new AccountDeletedEvent(userId));
+
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessToken.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessToken.java
new file mode 100644
index 0000000..e65bdab
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/AccessToken.java
@@ -0,0 +1,62 @@
+package de.fd.fh.server.access;
+
+import de.fd.fh.server.user.UserId;
+import dev.morphia.annotations.Embedded;
+import dev.morphia.annotations.PrePersist;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+import java.util.Random;
+
+@Embedded
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+public class AccessToken
+{
+ private String token;
+
+ private LocalDateTime createdDate;
+
+ private Role role;
+
+ @Embedded
+ private UserId userId;
+
+ static AccessToken of(final Access access)
+ {
+ return new AccessToken(
+ generateToken(),
+ LocalDateTime.now(),
+ access.getRole(),
+ access.getUserId()
+ );
+ }
+
+ @PrePersist
+ void prePersist()
+ {
+ this.createdDate = LocalDateTime.now();
+ }
+
+ private static String generateToken()
+ {
+ final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ final String lower = upper.toLowerCase();
+ final String numbers = "0123456789";
+ final String alphabet = upper + lower + numbers;
+
+ System.out.println("generate Security Token.");
+
+ Random random = new Random();
+ StringBuilder generatedString = new StringBuilder();
+ for (int i = 0; i < 64; i++) {
+ generatedString.append(alphabet.charAt(random.nextInt(alphabet.length())));
+ }
+
+ System.out.println("Token: " + generatedString);
+ return generatedString.toString();
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/Role.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/Role.java
new file mode 100644
index 0000000..66db360
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/Role.java
@@ -0,0 +1,6 @@
+package de.fd.fh.server.access;
+
+public enum Role
+{
+ ADMIN, USER
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountCreatedEvent.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountCreatedEvent.java
new file mode 100644
index 0000000..c5e1530
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountCreatedEvent.java
@@ -0,0 +1,13 @@
+package de.fd.fh.server.access.events;
+
+import de.fd.fh.server.user.UserId;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class AccountCreatedEvent
+{
+ private final String name;
+ private final UserId userId;
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountDeletedEvent.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountDeletedEvent.java
new file mode 100644
index 0000000..7667bcb
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/events/AccountDeletedEvent.java
@@ -0,0 +1,12 @@
+package de.fd.fh.server.access.events;
+
+import de.fd.fh.server.user.UserId;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class AccountDeletedEvent
+{
+ private final UserId userId;
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/web/AccessController.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/web/AccessController.java
new file mode 100644
index 0000000..3e32964
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/access/web/AccessController.java
@@ -0,0 +1,104 @@
+package de.fd.fh.server.access.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.fd.fh.server.access.AccessService;
+import de.fd.fh.server.access.AccessToken;
+import de.fd.fh.server.user.UserId;
+import de.fd.fh.shared.Utils;
+import de.fd.fh.shared.network.messages.LoginRequest;
+import de.fd.fh.shared.network.messages.RegistrateRequest;
+
+import static spark.Spark.*;
+
+public class AccessController
+{
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ public AccessController(final AccessService service)
+ {
+ before("/*",
+ (req, res) ->
+ {
+ final String path = req.pathInfo();
+ final String token = req.headers(Utils.AUTHENTICATION_HEADER);
+
+ final AccessToken accessToken = service.before(path, token);
+
+ req.session().attribute("userId",
+ accessToken);
+ });
+
+ post("/accounts/registrate",
+ (request, response) ->
+ {
+ final RegistrateRequest message =
+ objectMapper.readValue(request.body(), RegistrateRequest.class);
+
+ if (service.createPlayer(message))
+ {
+ response.status(201);
+ }
+ else
+ {
+ response.status(400);
+ }
+ return response;
+ }
+ );
+
+ post("/accounts/login",
+ (request, response) ->
+ {
+ final String header = request.headers(Utils.AUTHENTICATION_HEADER);
+
+ final LoginRequest login = service.authorization(header);
+
+ if (login == null)
+ {
+ response.status(401);
+ }
+ else
+ {
+ response.status(200);
+ response.type("application/json");
+ response.body(objectMapper.writeValueAsString(login));
+ }
+ return response;
+ });
+
+ post("/accounts/logout",
+ (request, response) ->
+ {
+ final String token = request.headers(Utils.AUTHENTICATION_HEADER);
+
+ if (service.logout(token))
+ {
+ response.status(200);
+ }
+ else
+ {
+ response.status(400);
+ }
+
+ return response;
+ });
+
+ delete("/accounts/:player_id",
+ (request, response) ->
+ {
+ final UserId userId = UserId.of(request.params(":player_id"));
+ final AccessToken token = request.session().attribute("userId");
+
+ if (service.deleteAccount(userId, token))
+ {
+ response.status(200);
+ }
+ else
+ {
+ response.status(400);
+ }
+
+ return response;
+ });
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/User.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/User.java
new file mode 100644
index 0000000..ef18257
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/User.java
@@ -0,0 +1,26 @@
+package de.fd.fh.server.user;
+
+import lombok.*;
+
+@AllArgsConstructor
+@Getter
+public class User {
+
+ private final UserId id;
+
+ private String name;
+
+ public static User of(String name)
+ {
+ return new User(null, name);
+ }
+
+ public void rename(String name)
+ {
+ if (name == null)
+ {
+ return;
+ }
+ this.name = name;
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserContextEventListener.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserContextEventListener.java
new file mode 100644
index 0000000..c9fe1a5
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserContextEventListener.java
@@ -0,0 +1,43 @@
+package de.fd.fh.server.user;
+
+import de.fd.fh.server.access.events.AccountCreatedEvent;
+import de.fd.fh.server.access.events.AccountDeletedEvent;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Observable;
+import java.util.Observer;
+
+@RequiredArgsConstructor
+public class UserContextEventListener implements Observer
+{
+ private final UserRepository userRepository;
+
+ @Override
+ public void update(
+ final Observable observable,
+ final Object event)
+ {
+ System.out.println("UserContextEventListener " + event);
+ if (event instanceof AccountCreatedEvent) {
+ handleAccountCreatedEvent((AccountCreatedEvent) event);
+ }
+ if (event instanceof AccountDeletedEvent) {
+ handleAccountDeletedEvent((AccountDeletedEvent) event);
+ }
+ }
+
+ private void handleAccountDeletedEvent(final AccountDeletedEvent event)
+ {
+ userRepository.deleteUserById(event.getUserId());
+ }
+
+ private void handleAccountCreatedEvent(final AccountCreatedEvent event)
+ {
+ System.out.println("handleAccountCreatedEvent " + event);
+ final User user = new User(event.getUserId(), event.getName());
+ System.out.println("User: " + user);
+
+ userRepository.save(user);
+ System.out.println("UserId: " + user.getId());
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserId.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserId.java
new file mode 100644
index 0000000..d978069
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserId.java
@@ -0,0 +1,25 @@
+package de.fd.fh.server.user;
+
+import dev.morphia.annotations.Embedded;
+import lombok.*;
+import org.bson.types.ObjectId;
+
+@Getter
+@Embedded
+@NoArgsConstructor
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+@EqualsAndHashCode(of = {"identifier"})
+public class UserId
+{
+ private String identifier;
+
+ public static UserId of(final String identifier)
+ {
+ return new UserId(identifier);
+ }
+
+ public static UserId random()
+ {
+ return new UserId(new ObjectId().toHexString());
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserRepository.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserRepository.java
new file mode 100644
index 0000000..dcb1316
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserRepository.java
@@ -0,0 +1,52 @@
+package de.fd.fh.server.user;
+
+import com.mongodb.MongoClient;
+import com.mongodb.WriteResult;
+import dev.morphia.Datastore;
+import dev.morphia.Key;
+import dev.morphia.Morphia;
+
+public class UserRepository {
+
+ private final Datastore datastore;
+
+ public UserRepository()
+ {
+ System.out.println("UserRepo");
+ final Morphia morphia = new Morphia();
+
+ morphia.mapPackage("de.fd.fh.server.user");
+
+ this.datastore = morphia.createDatastore(new MongoClient(), "smartwarfare");
+ datastore.ensureIndexes();
+ }
+
+ UserRepository(Datastore datastore)
+ {
+ this.datastore = datastore;
+ }
+
+ public Key save(final User user)
+ {
+ return datastore.save(user);
+ }
+
+ public User findUserById(final UserId userId)
+ {
+ return datastore.createQuery(User.class)
+ .field("_id.identifier").equal(userId.getIdentifier())
+ .first();
+ }
+
+ public User findUserByName(final String name)
+ {
+ return datastore.createQuery(User.class)
+ .field("name").equal(name)
+ .first();
+ }
+
+ WriteResult deleteUserById(final UserId userId)
+ {
+ return datastore.delete(findUserById(userId));
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserService.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserService.java
new file mode 100644
index 0000000..268e695
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/UserService.java
@@ -0,0 +1,48 @@
+package de.fd.fh.server.user;
+
+import de.fd.fh.server.user.events.ChangePasswordEvent;
+import de.fd.fh.server.user.web.ChangeUserRequest;
+import de.fd.fh.server.user.web.UserRequest;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Observable;
+
+@RequiredArgsConstructor
+public class UserService extends Observable
+{
+ private final UserRepository userRepository;
+
+ public User changePlayer(final UserId userId, final ChangeUserRequest message)
+ {
+ System.out.println("changePlayer: " + message);
+
+ User user = userRepository.findUserById(userId);
+
+ if (message.getPassword() != null)
+ {
+ setChanged();
+ notifyObservers(new ChangePasswordEvent(userId, message.getPassword()));
+ }
+
+ userRepository.save(user);
+
+ return userRepository.findUserById(userId);
+ }
+
+ public User getPlayer(final UserId id)
+ {
+ return userRepository.findUserById(id);
+ }
+
+ public UserRequest getSmallPlayer(final UserId userId)
+ {
+ final User user = userRepository.findUserById(userId);
+
+ if(user == null)
+ {
+ return null;
+ }
+
+ return new UserRequest(user.getId().getIdentifier(), user.getName());
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/events/ChangePasswordEvent.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/events/ChangePasswordEvent.java
new file mode 100644
index 0000000..bc15e48
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/events/ChangePasswordEvent.java
@@ -0,0 +1,18 @@
+package de.fd.fh.server.user.events;
+
+import de.fd.fh.server.user.UserId;
+import lombok.Getter;
+
+@Getter
+public class ChangePasswordEvent
+{
+ private final String newPassword;
+
+ private final UserId userId;
+
+ public ChangePasswordEvent(final UserId userId, final String password)
+ {
+ this.newPassword = password;
+ this.userId = userId;
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/ChangeUserRequest.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/ChangeUserRequest.java
new file mode 100644
index 0000000..82fbe76
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/ChangeUserRequest.java
@@ -0,0 +1,13 @@
+package de.fd.fh.server.user.web;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class ChangeUserRequest
+{
+ private final String name;
+
+ private final String password;
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/UserController.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/UserController.java
new file mode 100644
index 0000000..67a932d
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/UserController.java
@@ -0,0 +1,89 @@
+package de.fd.fh.server.user.web;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.fd.fh.server.access.AccessToken;
+import de.fd.fh.server.user.User;
+import de.fd.fh.server.user.UserId;
+import de.fd.fh.server.user.UserService;
+
+import static spark.Spark.get;
+import static spark.Spark.post;
+
+public class UserController
+{
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ public UserController(final UserService service)
+ {
+ post("/users",
+ ((request, response) ->
+ {
+ final UserId userId =
+ ((AccessToken) request.session()
+ .attribute("userId"))
+ .getUserId();
+
+ final ChangeUserRequest message = objectMapper.readValue(request.body(),
+ ChangeUserRequest.class);
+
+ final User user = service.changePlayer(
+ userId,
+ message);
+
+ if (user == null)
+ {
+ response.status(400);
+ }
+ else
+ {
+ response.status(200);
+ response.type("application/json");
+
+ return objectMapper.writeValueAsString(user);
+ }
+
+ return response;
+ }
+ ));
+
+ get("/users",
+ (request, response) ->
+ {
+ final UserId userId =
+ ((AccessToken) request.session()
+ .attribute("userId"))
+ .getUserId();
+
+ final User user = service.getPlayer(userId);
+
+ if (user == null)
+ {
+ response.status(400);
+ }
+ else
+ {
+ response.status(200);
+ response.type("application/json");
+
+ return objectMapper.writeValueAsString(user);
+ }
+
+ return response;
+ }
+ );
+
+ get("/users/:user_id",
+ (request, response) ->
+ {
+ final UserId userId = UserId.of(request.params(":user_id"));
+ final UserRequest user = service.getSmallPlayer(userId);
+
+ if (user == null)
+ {
+ response.status(404);
+ }
+ response.body(objectMapper.writeValueAsString(user));
+ return response;
+ });
+ }
+}
diff --git a/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/UserRequest.java b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/UserRequest.java
new file mode 100644
index 0000000..981861c
--- /dev/null
+++ b/fh.fd.ci.server/src/main/java/de/fd/fh/server/user/web/UserRequest.java
@@ -0,0 +1,13 @@
+package de.fd.fh.server.user.web;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class UserRequest
+{
+ private final String id;
+
+ private final String name;
+}
diff --git a/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessContextEventListenerTest.java b/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessContextEventListenerTest.java
new file mode 100644
index 0000000..e970141
--- /dev/null
+++ b/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessContextEventListenerTest.java
@@ -0,0 +1,36 @@
+package de.fd.fh.server.access;
+
+import de.fd.fh.server.user.UserId;
+import de.fd.fh.server.user.UserRepository;
+import de.fd.fh.server.user.UserService;
+import de.fd.fh.server.user.events.ChangePasswordEvent;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.then;
+import static org.mockito.Mockito.*;
+
+class AccessContextEventListenerTest
+{
+ @Test
+ void given_changePasswordEvent_when_passwordChanged_should_changePassword()
+ {
+ final ChangePasswordEvent event = new ChangePasswordEvent(UserId.of("12345"), "newPwd");
+
+ final AccessRepository repository = mock(AccessRepository.class);
+ when(repository.findByUserId(any(UserId.class)))
+ .thenReturn(new Access());
+
+ final ArgumentCaptor captor = ArgumentCaptor.forClass(Access.class);
+
+ new AccessContextEventListener(repository).update(null, event);
+ verify(repository).save(captor.capture());
+
+ assertEquals("newPwd", captor.getValue().getPassword(), "Have to be the new password");
+ then(repository).should().findByUserId(any(UserId.class));
+ then(repository).should().save(any(Access.class));
+ then(repository).shouldHaveNoMoreInteractions();
+ }
+}
\ No newline at end of file
diff --git a/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessRepositoryTest.java b/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessRepositoryTest.java
new file mode 100644
index 0000000..488d332
--- /dev/null
+++ b/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessRepositoryTest.java
@@ -0,0 +1,42 @@
+package de.fd.fh.server.access;
+
+import de.fd.fh.server.user.UserId;
+import dev.morphia.Datastore;
+import dev.morphia.Key;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.then;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class AccessRepositoryTest
+{
+ @Mock
+ private Datastore datastore;
+
+ @BeforeEach
+ public void before()
+ {
+ datastore = mock(Datastore.class);
+ }
+
+ @Test
+ void given_newUser_when_saveUser_should_storeUserInDatabase()
+ {
+ when(datastore.save(any(Access.class)))
+ .thenReturn(new Key<>(Access.class, "collection", "id"));
+
+ final Access access = new Access("testId", "testName", "testPwd", UserId.of("userId"),
+ null, Role.USER);
+
+ final Key result = new AccessRepository(datastore).save(access);
+
+ assertThat("Key is null", result, notNullValue());
+ then(datastore).should().save(any(Access.class));
+ }
+}
\ No newline at end of file
diff --git a/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessServiceTest.java b/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessServiceTest.java
new file mode 100644
index 0000000..073a84a
--- /dev/null
+++ b/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessServiceTest.java
@@ -0,0 +1,245 @@
+package de.fd.fh.server.access;
+
+import com.mongodb.WriteResult;
+import de.fd.fh.server.user.UserId;
+import de.fd.fh.shared.network.messages.LoginRequest;
+import de.fd.fh.shared.network.messages.RegistrateRequest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import spark.HaltException;
+
+import java.time.LocalDateTime;
+import java.util.Base64;
+import java.util.Observable;
+import java.util.Observer;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.then;
+import static org.mockito.Mockito.*;
+
+class AccessServiceTest implements Observer
+{
+ private Object event;
+
+ @BeforeEach
+ void before()
+ {
+ this.event = null;
+ }
+
+ @Test
+ void given_authenticatedUser_when_serverAuthenticateUser_should_authenticateUser()
+ {
+ final Access access = new Access(
+ "testId",
+ "testName",
+ "testPwd",
+ UserId.of("12345"),
+ new AccessToken(
+ "testToken",
+ LocalDateTime.now(),
+ Role.USER,
+ UserId.of("12345")
+ ),
+ Role.USER);
+
+ final AccessRepository repository = mock(AccessRepository.class);
+ when(repository.findByToken(any()))
+ .thenReturn(access);
+ final String path = "/test/path";
+ final String token = "testToken";
+
+ final AccessToken result = new AccessService(repository).before(path, token);
+
+ assertThat("User is not authenticated", result, notNullValue());
+ then(repository).should().findByToken(any());
+ then(repository).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ void given_notAuthenticatedUser_when_serverAuthenticateUser_should_denyUser()
+ {
+ final Access access = new Access(
+ "testId",
+ "testName",
+ "testPwd",
+ UserId.of("12345"),
+ null,
+ Role.USER);
+
+ final AccessRepository repository = mock(AccessRepository.class);
+ when(repository.findByToken(any()))
+ .thenReturn(access);
+ final String path = "/test/path";
+ final String token = "testToken";
+
+ assertThrows(HaltException.class, () ->new AccessService(repository).before(path, token));
+
+ then(repository).should().findByToken(any());
+ then(repository).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ void given_newUser_when_createUser_should_storeNewUser()
+ {
+ final RegistrateRequest request =
+ RegistrateRequest.of("testUser", "testPwd");
+
+ final AccessRepository repository = mock(AccessRepository.class);
+ when(repository.findByUserName(any()))
+ .thenReturn(null);
+ ArgumentCaptor accessCaptor = ArgumentCaptor.forClass(Access.class);
+
+ final AccessService service = new AccessService(repository);
+ service.addObserver(this);
+
+ final boolean result = service.createPlayer(request);
+
+ assertTrue(result);
+ assertThat("No event thrown", this.event, notNullValue());
+
+ verify(repository).save(accessCaptor.capture());
+ final Access createdAccess = accessCaptor.getValue();
+
+ assertNotNull(createdAccess, "No Access created");
+ assertNotNull(createdAccess.get_id(), "No Id created");
+ assertNotNull(createdAccess.getUserId(), "No UserId created");
+ assertEquals("testUser", createdAccess.getName(), "Wrong Username");
+ assertEquals("testPwd", createdAccess.getPassword(), "Wrong Password");
+ assertEquals(Role.USER.name(), createdAccess.getRole().name(), "Should be USER");
+ assertNull(createdAccess.getToken(), "User should not be logged in");
+
+ then(repository).should().findByUserName(any());
+ then(repository).should().save(any(Access.class));
+ then(repository).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ void given_loggedInUser_when_logout_should_logoutUser()
+ {
+ final Access access = new Access(
+ "testId",
+ "testName",
+ "testPwd",
+ UserId.of("12345"),
+ null,
+ Role.USER
+ );
+ final AccessToken token = AccessToken.of(access);
+ access.setToken(token);
+
+ final AccessRepository repository = mock(AccessRepository.class);
+ when(repository.findByToken(any()))
+ .thenReturn(access);
+ ArgumentCaptor accessCaptor = ArgumentCaptor.forClass(Access.class);
+
+ final AccessService service = new AccessService(repository);
+
+ final boolean result = service.logout("testToken");
+
+ assertTrue(result);
+
+ verify(repository).save(accessCaptor.capture());
+ final Access createdAccess = accessCaptor.getValue();
+
+ assertNotNull(createdAccess, "No Access created");
+ assertNotNull(createdAccess.get_id(), "No Id created");
+ assertNotNull(createdAccess.getUserId(), "No UserId created");
+ assertEquals("testName", createdAccess.getName(), "Wrong Username");
+ assertEquals("testPwd", createdAccess.getPassword(), "Wrong Password");
+ assertEquals(Role.USER.name(), createdAccess.getRole().name(), "Should be USER");
+ assertNull(createdAccess.getToken(), "User should logged out");
+
+ then(repository).should().findByToken(any());
+ then(repository).should().save(any(Access.class));
+ then(repository).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ void given_storedUser_when_loginUser_should_returnLoginRequest()
+ {
+ final byte[] message = Base64.getEncoder().encode("testName:testPassword".getBytes());
+ final String header = "Basic " + new String(message);
+ final Access access = new Access(
+ "testId",
+ "testName",
+ "testPassword",
+ UserId.of("12345"),
+ null,
+ Role.USER
+ );
+ final AccessRepository repository = mock(AccessRepository.class);
+ when(repository.findByUserName(any()))
+ .thenReturn(access);
+
+ final LoginRequest result = new AccessService(repository).authorization(header);
+
+ assertNotNull(result);
+ assertEquals(result.getName(), "testName", "Wrong UserName");
+ assertEquals(result.getUserId(), "12345", "Wrong Password");
+ assertNotNull(result.getToken(), "Not logged in");
+ }
+
+ @Test
+ void given_storedUserWithWrongPassword_when_loginUser_should_returnAccessDeny()
+ {
+ final byte[] message = Base64.getEncoder().encode("testName:testPassword".getBytes());
+ final String header = "Basic " + new String(message);
+ final AccessRepository repository = mock(AccessRepository.class);
+
+ final LoginRequest result = new AccessService(repository).authorization(header);
+
+ assertNull(result, "Return LoginRequest but wrong permissions");
+ }
+
+ @Test
+ void given_storedUser_when_deleteUser_should_deleteUser()
+ {
+ final UserId userId = UserId.of("12345");
+ final AccessToken token = new AccessToken(null, null, null, UserId.of("12345"));
+ final AccessRepository repository = mock(AccessRepository.class);
+ when(repository.deleteLoginByUserId(any(UserId.class)))
+ .thenReturn(new WriteResult(1, false, null));
+
+ final AccessService service = new AccessService(repository);
+ service.addObserver(this);
+
+ final boolean result = service.deleteAccount(userId, token);
+
+ assertTrue(result);
+ assertNotNull(event);
+
+ then(repository).should().deleteLoginByUserId(any(UserId.class));
+ then(repository).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ void given_storedUser_when_deleteUserWithWrongPermission_should_doNothing()
+ {
+ final UserId userId = UserId.of("12345");
+ final AccessToken token = new AccessToken(null, null, null, UserId.of("98765"));
+ final AccessRepository repository = mock(AccessRepository.class);
+ when(repository.deleteLoginByUserId(any(UserId.class)))
+ .thenReturn(new WriteResult(1, false, null));
+
+ final AccessService service = new AccessService(repository);
+ service.addObserver(this);
+
+ final boolean result = service.deleteAccount(userId, token);
+
+ assertFalse(result);
+ assertNull(event);
+
+ then(repository).shouldHaveNoInteractions();
+ }
+
+ @Override
+ public void update(Observable o, Object arg)
+ {
+ this.event = arg;
+ }
+}
\ No newline at end of file
diff --git a/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessTokenTest.java b/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessTokenTest.java
new file mode 100644
index 0000000..1872e62
--- /dev/null
+++ b/fh.fd.ci.server/src/test/java/de/fd/fh/server/access/AccessTokenTest.java
@@ -0,0 +1,31 @@
+package de.fd.fh.server.access;
+
+import de.fd.fh.server.user.UserId;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.jupiter.api.Assertions.*;
+
+class AccessTokenTest
+{
+ @Test
+ void given_accessData_when_createAccessToken_should_createGeneratedToken()
+ {
+ final Access access = new Access(
+ "testId",
+ "testName",
+ "testPwd",
+ UserId.of("12345"),
+ null,
+ Role.USER);
+
+ final AccessToken result = AccessToken.of(access);
+
+ assertNotNull(result.getCreatedDate());
+ assertNotNull(result.getToken());
+ assertThat(result.getToken().length(), equalTo(64));
+ assertEquals(result.getRole(), Role.USER);
+ assertEquals(result.getUserId(), UserId.of("12345"));
+ }
+}
\ No newline at end of file
diff --git a/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserContextEventListenerTest.java b/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserContextEventListenerTest.java
new file mode 100644
index 0000000..294c9d7
--- /dev/null
+++ b/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserContextEventListenerTest.java
@@ -0,0 +1,51 @@
+package de.fd.fh.server.user;
+
+import de.fd.fh.server.access.events.AccountCreatedEvent;
+import de.fd.fh.server.access.events.AccountDeletedEvent;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.then;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+class UserContextEventListenerTest
+{
+ @Test
+ void given_accountCreatedEvent_when_accountWasCreated_should_createUser()
+ {
+ final AccountCreatedEvent event = new AccountCreatedEvent("testName", UserId.of("12345"));
+ final UserRepository repository = mock(UserRepository.class);
+
+ final ArgumentCaptor captor = ArgumentCaptor.forClass(User.class);
+
+ new UserContextEventListener(repository).update(null, event);
+ verify(repository).save(captor.capture());
+
+ assertNotNull(captor.getValue());
+ assertEquals("testName", captor.getValue().getName(), "Should have the correct name");
+ assertEquals("12345", captor.getValue().getId().getIdentifier(), "Should have the correct userId");
+ then(repository).should().save(any());
+ then(repository).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ void given_accountDeletedEvent_when_accountWasDeleted_should_deleteUser()
+ {
+ final AccountDeletedEvent event = new AccountDeletedEvent(UserId.of("12345"));
+ final UserRepository repository = mock(UserRepository.class);
+
+ final ArgumentCaptor captor = ArgumentCaptor.forClass(UserId.class);
+
+ new UserContextEventListener(repository).update(null, event);
+ verify(repository).deleteUserById(captor.capture());
+
+ assertNotNull(captor.getValue());
+ assertEquals("12345", captor.getValue().getIdentifier(), "No correct userId");
+ then(repository).should().deleteUserById(any(UserId.class));
+ then(repository).shouldHaveNoMoreInteractions();
+ }
+}
\ No newline at end of file
diff --git a/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserRepositoryTest.java b/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserRepositoryTest.java
new file mode 100644
index 0000000..a551286
--- /dev/null
+++ b/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserRepositoryTest.java
@@ -0,0 +1,40 @@
+package de.fd.fh.server.user;
+
+import dev.morphia.Datastore;
+import dev.morphia.Key;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.then;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class UserRepositoryTest
+{
+ @Mock
+ private Datastore datastore;
+
+ @BeforeEach
+ public void before()
+ {
+ datastore = mock(Datastore.class);
+ }
+
+ @Test
+ void given_newUser_when_saveUser_should_storeUserInDatabase()
+ {
+ when(datastore.save(any(User.class)))
+ .thenReturn(new Key<>(User.class, "collection", "id"));
+
+ final User access = new User(UserId.of("userId"), "testName");
+
+ final Key result = new UserRepository(datastore).save(access);
+
+ assertThat("Key is null", result, notNullValue());
+ then(datastore).should().save(any(User.class));
+ }
+}
\ No newline at end of file
diff --git a/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserServiceTest.java b/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserServiceTest.java
new file mode 100644
index 0000000..1c3bcbf
--- /dev/null
+++ b/fh.fd.ci.server/src/test/java/de/fd/fh/server/user/UserServiceTest.java
@@ -0,0 +1,84 @@
+package de.fd.fh.server.user;
+
+import de.fd.fh.server.user.web.ChangeUserRequest;
+import de.fd.fh.server.user.web.UserRequest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+class UserServiceTest implements Observer
+{
+ private Object event;
+
+ @BeforeEach
+ void before()
+ {
+ event = null;
+ }
+
+ @Test
+ void given_storedUser_when_changePassword_should_changePassword()
+ {
+ final User user =
+ User.of("testName");
+ final ChangeUserRequest request =
+ new ChangeUserRequest("testName", "newPassword");
+ final UserRepository repository = mock(UserRepository.class);
+ when(repository.findUserById(any(UserId.class)))
+ .thenReturn(user);
+
+ final UserService service = new UserService(repository);
+ service.addObserver(this);
+ final ArgumentCaptor captor = ArgumentCaptor.forClass(User.class);
+
+ service.changePlayer(UserId.of("12345"), request);
+ verify(repository).save(captor.capture());
+
+ assertNotNull(captor.getValue(), "Should be saved");
+ assertNotNull(event);
+ }
+
+ @Test
+ void given_storedUser_when_getPlayer_should_returnPlayer()
+ {
+ final User user =
+ User.of("testName");
+ final UserRepository repository = mock(UserRepository.class);
+ when(repository.findUserById(any(UserId.class)))
+ .thenReturn(user);
+
+ final User result = new UserService(repository).getPlayer(UserId.of("12345"));
+
+ assertNotNull(result);
+ }
+
+ @Test
+ void given_storedUser_when_getSmallPlayer_should_returnSmallPlayer()
+ {
+ final User user =
+ new User(UserId.of("12345"), "testName");
+ final UserRepository repository = mock(UserRepository.class);
+ when(repository.findUserById(any(UserId.class)))
+ .thenReturn(user);
+
+ final UserRequest result = new UserService(repository).getSmallPlayer(UserId.of("12345"));
+
+ assertNotNull(result);
+ assertEquals("12345", result.getId(), "Wrong UserId");
+ assertEquals("testName", result.getName(), "Wrong Name");
+
+ }
+
+ @Override
+ public void update(Observable o, Object arg)
+ {
+ event = arg;
+ }
+}
\ No newline at end of file
diff --git a/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/Utils.java b/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/Utils.java
new file mode 100644
index 0000000..32c326d
--- /dev/null
+++ b/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/Utils.java
@@ -0,0 +1,6 @@
+package de.fd.fh.shared;
+
+public class Utils
+{
+ public static final String AUTHENTICATION_HEADER = "Authorization";
+}
diff --git a/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/network/messages/LoginRequest.java b/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/network/messages/LoginRequest.java
new file mode 100644
index 0000000..4e1c38c
--- /dev/null
+++ b/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/network/messages/LoginRequest.java
@@ -0,0 +1,11 @@
+package de.fd.fh.shared.network.messages;
+
+import lombok.Data;
+
+@Data
+public class LoginRequest
+{
+ private String name;
+ private String userId;
+ private String token;
+}
diff --git a/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/network/messages/RegistrateRequest.java b/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/network/messages/RegistrateRequest.java
new file mode 100644
index 0000000..b3c08d4
--- /dev/null
+++ b/fh.fd.ci.shared/src/main/java/de/fd/fh/shared/network/messages/RegistrateRequest.java
@@ -0,0 +1,12 @@
+package de.fd.fh.shared.network.messages;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor(staticName = "of")
+public class RegistrateRequest
+{
+ private String userName;
+ private String password;
+}