roles;
- private UUID id;
- private String title;
- private String description;
- private Long userMaximum;
- private GroupType type;
- private Visibility visibility;
- private UUID parent;
-
- public Group() {
- members = new ArrayList<>();
- roles = new HashMap<>();
- }
-
-}
diff --git a/src/main/java/mops/gruppen2/domain/GroupType.java b/src/main/java/mops/gruppen2/domain/GroupType.java
deleted file mode 100644
index ea45105..0000000
--- a/src/main/java/mops/gruppen2/domain/GroupType.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package mops.gruppen2.domain;
-
-public enum GroupType {
- SIMPLE,
- LECTURE
-}
diff --git a/src/main/java/mops/gruppen2/domain/Role.java b/src/main/java/mops/gruppen2/domain/Role.java
deleted file mode 100644
index 2b58e75..0000000
--- a/src/main/java/mops/gruppen2/domain/Role.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package mops.gruppen2.domain;
-
-public enum Role {
- ADMIN,
- MEMBER
-}
diff --git a/src/main/java/mops/gruppen2/domain/User.java b/src/main/java/mops/gruppen2/domain/User.java
deleted file mode 100644
index 16806b2..0000000
--- a/src/main/java/mops/gruppen2/domain/User.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package mops.gruppen2.domain;
-
-import lombok.AllArgsConstructor;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-
-@Getter
-@AllArgsConstructor
-@NoArgsConstructor
-@EqualsAndHashCode(exclude = {"givenname", "familyname", "email"})
-public class User {
-
- private String id;
- private String givenname;
- private String familyname;
- private String email;
-
- public User(Account account) {
- id = account.getName();
- givenname = account.getGivenname();
- familyname = account.getFamilyname();
- email = account.getEmail();
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/Visibility.java b/src/main/java/mops/gruppen2/domain/Visibility.java
deleted file mode 100644
index 5f41a61..0000000
--- a/src/main/java/mops/gruppen2/domain/Visibility.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package mops.gruppen2.domain;
-
-public enum Visibility {
- PUBLIC,
- PRIVATE
-}
diff --git a/src/main/java/mops/gruppen2/domain/dto/InviteLinkDTO.java b/src/main/java/mops/gruppen2/domain/dto/InviteLinkDTO.java
deleted file mode 100644
index b325f6b..0000000
--- a/src/main/java/mops/gruppen2/domain/dto/InviteLinkDTO.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package mops.gruppen2.domain.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.relational.core.mapping.Table;
-
-@Table("invite")
-@Getter
-@AllArgsConstructor
-public class InviteLinkDTO {
-
- @Id
- Long invite_id;
- String group_id;
- String invite_link;
-}
diff --git a/src/main/java/mops/gruppen2/domain/event/AddMemberEvent.java b/src/main/java/mops/gruppen2/domain/event/AddMemberEvent.java
new file mode 100644
index 0000000..0394a0c
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/AddMemberEvent.java
@@ -0,0 +1,57 @@
+package mops.gruppen2.domain.event;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.GroupFullException;
+import mops.gruppen2.domain.exception.IdMismatchException;
+import mops.gruppen2.domain.exception.UserExistsException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import java.util.UUID;
+
+/**
+ * Fügt einen einzelnen Nutzer einer Gruppe hinzu.
+ */
+@Log4j2
+@Value
+@AllArgsConstructor
+public class AddMemberEvent extends Event {
+
+ @JsonProperty("user")
+ User user;
+
+ public AddMemberEvent(UUID groupId, String exec, String target, User user) throws IdMismatchException {
+ super(groupId, exec, target);
+ this.user = user;
+
+ if (!target.equals(user.getId())) {
+ throw new IdMismatchException("Der User passt nicht zur angegebenen userid.");
+ }
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {
+ cache.usersPut(target, group);
+ }
+
+ @Override
+ protected void applyEvent(Group group) throws UserExistsException, GroupFullException {
+ group.addMember(target, user);
+
+ log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
+ }
+
+ @Override
+ public String format() {
+ return "Benutzer hinzugefügt: " + target + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.ADDMEMBER.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/AddUserEvent.java b/src/main/java/mops/gruppen2/domain/event/AddUserEvent.java
deleted file mode 100644
index b2f65be..0000000
--- a/src/main/java/mops/gruppen2/domain/event/AddUserEvent.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.Role;
-import mops.gruppen2.domain.User;
-import mops.gruppen2.domain.exception.EventException;
-import mops.gruppen2.domain.exception.GroupFullException;
-import mops.gruppen2.domain.exception.UserAlreadyExistsException;
-
-import java.util.UUID;
-
-/**
- * Fügt einen einzelnen Nutzer einer Gruppe hinzu.
- */
-@Getter
-@NoArgsConstructor // For Jackson
-public class AddUserEvent extends Event {
-
- private String givenname;
- private String familyname;
- private String email;
-
- public AddUserEvent(UUID groupId, String userId, String givenname, String familyname, String email) {
- super(groupId, userId);
- this.givenname = givenname;
- this.familyname = familyname;
- this.email = email;
- }
-
- @Override
- protected void applyEvent(Group group) throws EventException {
- User user = new User(userId, givenname, familyname, email);
-
- if (group.getMembers().contains(user)) {
- throw new UserAlreadyExistsException(getClass().toString());
- }
-
- if (group.getMembers().size() >= group.getUserMaximum()) {
- throw new GroupFullException(getClass().toString());
- }
-
- group.getMembers().add(user);
- group.getRoles().put(userId, Role.MEMBER);
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/event/CreateGroupEvent.java b/src/main/java/mops/gruppen2/domain/event/CreateGroupEvent.java
index e75c6e6..8e55353 100644
--- a/src/main/java/mops/gruppen2/domain/event/CreateGroupEvent.java
+++ b/src/main/java/mops/gruppen2/domain/event/CreateGroupEvent.java
@@ -1,36 +1,56 @@
package mops.gruppen2.domain.event;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.GroupType;
-import mops.gruppen2.domain.Visibility;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.infrastructure.GroupCache;
+import java.time.LocalDateTime;
import java.util.UUID;
-@Getter
-@NoArgsConstructor // For Jackson
+@Log4j2
+@Value
+@AllArgsConstructor// Value generiert den allArgsConstrucot nur, wenn keiner explizit angegeben ist
public class CreateGroupEvent extends Event {
- private Visibility groupVisibility;
- private UUID groupParent;
- private GroupType groupType;
- private Long groupUserMaximum;
+ @JsonProperty("date")
+ LocalDateTime date;
- public CreateGroupEvent(UUID groupId, String userId, UUID parent, GroupType type, Visibility visibility, Long userMaximum) {
- super(groupId, userId);
- groupParent = parent;
- groupType = type;
- groupVisibility = visibility;
- groupUserMaximum = userMaximum;
+ public CreateGroupEvent(UUID groupId, String exec, LocalDateTime date) {
+ super(groupId, exec, null);
+ this.date = date;
}
@Override
- protected void applyEvent(Group group) {
- group.setId(groupId);
- group.setParent(groupParent);
- group.setType(groupType);
- group.setVisibility(groupVisibility);
- group.setUserMaximum(groupUserMaximum);
+ protected void updateCache(GroupCache cache, Group group) {
+ cache.groupsPut(groupid, group);
+ cache.linksPut(group.getLink(), group);
+ }
+
+ @Override
+ protected void applyEvent(Group group) throws BadArgumentException {
+ group.setId(groupid);
+ group.setCreator(exec);
+ group.setCreationDate(date);
+
+ log.trace("\t\t\t\t\tNeue Gruppe: {}", group.toString());
+ }
+
+ @Override
+ public String format() {
+ return "Gruppe erstellt.";
+ }
+
+ @Override
+ public String type() {
+ return EventType.CREATEGROUP.toString();
+ }
+
+ @Override
+ public String toString() {
+ return "(" + version + "," + groupid + "," + date + ")";
}
}
diff --git a/src/main/java/mops/gruppen2/domain/event/DeleteGroupEvent.java b/src/main/java/mops/gruppen2/domain/event/DeleteGroupEvent.java
deleted file mode 100644
index adc54f5..0000000
--- a/src/main/java/mops/gruppen2/domain/event/DeleteGroupEvent.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
-
-import java.util.UUID;
-
-@Getter
-@NoArgsConstructor // For Jackson
-public class DeleteGroupEvent extends Event {
-
- public DeleteGroupEvent(UUID groupId, String userId) {
- super(groupId, userId);
- }
-
- @Override
- protected void applyEvent(Group group) {
- group.getRoles().clear();
- group.getMembers().clear();
- group.setTitle(null);
- group.setDescription(null);
- group.setVisibility(null);
- group.setType(null);
- group.setParent(null);
- group.setUserMaximum(0L);
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/event/DeleteUserEvent.java b/src/main/java/mops/gruppen2/domain/event/DeleteUserEvent.java
deleted file mode 100644
index c12e1b2..0000000
--- a/src/main/java/mops/gruppen2/domain/event/DeleteUserEvent.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.User;
-import mops.gruppen2.domain.exception.EventException;
-import mops.gruppen2.domain.exception.UserNotFoundException;
-
-import java.util.UUID;
-
-/**
- * Entfernt ein einzelnes Mitglied einer Gruppe.
- */
-@Getter
-@NoArgsConstructor // For Jackson
-public class DeleteUserEvent extends Event {
-
- public DeleteUserEvent(UUID groupId, String userId) {
- super(groupId, userId);
- }
-
- @Override
- protected void applyEvent(Group group) throws EventException {
- for (User user : group.getMembers()) {
- if (user.getId().equals(this.userId)) {
- group.getMembers().remove(user);
- group.getRoles().remove(user.getId());
- return;
- }
- }
- throw new UserNotFoundException(this.getClass().toString());
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/event/DestroyGroupEvent.java b/src/main/java/mops/gruppen2/domain/event/DestroyGroupEvent.java
new file mode 100644
index 0000000..d244f3f
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/DestroyGroupEvent.java
@@ -0,0 +1,42 @@
+package mops.gruppen2.domain.event;
+
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import java.util.UUID;
+
+@Log4j2
+@Value
+@AllArgsConstructor
+public class DestroyGroupEvent extends Event {
+
+ public DestroyGroupEvent(UUID groupId, String exec) {
+ super(groupId, exec, null);
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {
+ cache.groupsRemove(groupid, group);
+ }
+
+ @Override
+ protected void applyEvent(Group group) throws NoAccessException {
+ group.destroy(exec);
+
+ log.trace("\t\t\t\t\tGelöschte Gruppe: {}", group.toString());
+ }
+
+ @Override
+ public String format() {
+ return "Gruppe gelöscht.";
+ }
+
+ @Override
+ public String type() {
+ return EventType.DESTROYGROUP.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/Event.java b/src/main/java/mops/gruppen2/domain/event/Event.java
index bf1d8f5..0da2a41 100644
--- a/src/main/java/mops/gruppen2/domain/event/Event.java
+++ b/src/main/java/mops/gruppen2/domain/event/Event.java
@@ -1,51 +1,119 @@
package mops.gruppen2.domain.event;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.BadArgumentException;
import mops.gruppen2.domain.exception.EventException;
-import mops.gruppen2.domain.exception.GroupIdMismatchException;
+import mops.gruppen2.domain.exception.IdMismatchException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.infrastructure.GroupCache;
+import java.time.LocalDateTime;
import java.util.UUID;
+import static com.fasterxml.jackson.annotation.JsonSubTypes.Type;
+import static com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
-@JsonTypeInfo(
- use = JsonTypeInfo.Id.NAME,
- property = "type"
-)
-@JsonSubTypes({
- @JsonSubTypes.Type(value = AddUserEvent.class, name = "AddUserEvent"),
- @JsonSubTypes.Type(value = CreateGroupEvent.class, name = "CreateGroupEvent"),
- @JsonSubTypes.Type(value = DeleteUserEvent.class, name = "DeleteUserEvent"),
- @JsonSubTypes.Type(value = UpdateGroupDescriptionEvent.class, name = "UpdateGroupDescriptionEvent"),
- @JsonSubTypes.Type(value = UpdateGroupTitleEvent.class, name = "UpdateGroupTitleEvent"),
- @JsonSubTypes.Type(value = UpdateRoleEvent.class, name = "UpdateRoleEvent"),
- @JsonSubTypes.Type(value = DeleteGroupEvent.class, name = "DeleteGroupEvent"),
- @JsonSubTypes.Type(value = UpdateUserMaxEvent.class, name = "UpdateUserMaxEvent")
- })
+@Log4j2
+@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "class")
+@JsonSubTypes({@Type(value = AddMemberEvent.class, name = "ADDMEMBER"),
+ @Type(value = CreateGroupEvent.class, name = "CREATEGROUP"),
+ @Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"),
+ @Type(value = KickMemberEvent.class, name = "KICKMEMBER"),
+ @Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"),
+ @Type(value = SetInviteLinkEvent.class, name = "SETLINK"),
+ @Type(value = SetLimitEvent.class, name = "SETLIMIT"),
+ @Type(value = SetParentEvent.class, name = "SETPARENT"),
+ @Type(value = SetTitleEvent.class, name = "SETTITLE"),
+ @Type(value = SetTypeEvent.class, name = "SETTYPE"),
+ @Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")})
@Getter
-@NoArgsConstructor
-@AllArgsConstructor
+@NoArgsConstructor // Lombok needs a default constructor in the base class
public abstract class Event {
- protected UUID groupId;
- protected String userId;
+ @JsonProperty("groupid")
+ protected UUID groupid;
- public void apply(Group group) throws EventException {
- checkGroupIdMatch(group.getId());
- applyEvent(group);
+ @JsonProperty("version")
+ protected long version; // Group-Version
+
+ @JsonProperty("exec")
+ protected String exec;
+
+ @JsonProperty("target")
+ protected String target;
+
+ @JsonProperty("date")
+ protected LocalDateTime date;
+
+ //TODO: Eigentlich sollte die Gruppe aus dem Cache genommen werden, nicht übergeben
+ public Event(UUID groupid, String exec, String target) {
+ this.groupid = groupid;
+ this.exec = exec;
+ this.target = target;
}
- private void checkGroupIdMatch(UUID groupId) {
- if (groupId == null || this.groupId.equals(groupId)) {
+ public void init(long version) {
+ if (this.version != 0) {
+ throw new BadArgumentException("Event wurde schon initialisiert. (" + type() + ")");
+ }
+ date = LocalDateTime.now();
+
+ log.trace("Event wurde initialisiert. (" + type() + "," + version + ")");
+
+ this.version = version;
+ }
+
+ public void apply(Group group, GroupCache cache) throws EventException {
+ log.trace("Event wird angewendet:\t{}", this);
+
+ if (version == 0) {
+ throw new BadArgumentException("Event wurde nicht initialisiert.");
+ }
+
+ checkGroupIdMatch(group.getId());
+ group.updateVersion(version);
+ applyEvent(group);
+ updateCache(cache, group); // Update erst nachdem apply keine exception geworfen hat
+ }
+
+ public void apply(Group group) throws EventException {
+ log.trace("Event wird angewendet:\t{}", this);
+
+ if (version == 0) {
+ throw new BadArgumentException("Event wurde nicht initialisiert.");
+ }
+
+ checkGroupIdMatch(group.getId());
+ group.updateVersion(version);
+ applyEvent(group);
+
+ }
+
+ private void checkGroupIdMatch(UUID groupid) throws IdMismatchException {
+ // CreateGroupEvents müssen die Id erst initialisieren
+ if (this instanceof CreateGroupEvent) {
return;
}
- throw new GroupIdMismatchException(getClass().toString());
+ if (!this.groupid.equals(groupid)) {
+ throw new IdMismatchException("Das Event gehört zu einer anderen Gruppe");
+ }
}
+ protected abstract void updateCache(GroupCache cache, Group group);
+
protected abstract void applyEvent(Group group) throws EventException;
+
+ @JsonIgnore
+ public abstract String format();
+
+ @JsonIgnore
+ public abstract String type();
}
diff --git a/src/main/java/mops/gruppen2/domain/event/EventType.java b/src/main/java/mops/gruppen2/domain/event/EventType.java
new file mode 100644
index 0000000..a444326
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/EventType.java
@@ -0,0 +1,15 @@
+package mops.gruppen2.domain.event;
+
+public enum EventType {
+ ADDMEMBER,
+ CREATEGROUP,
+ DESTROYGROUP,
+ KICKMEMBER,
+ SETDESCRIPTION,
+ SETLINK,
+ SETLIMIT,
+ SETPARENT,
+ SETTITLE,
+ SETTYPE,
+ UPDATEROLE
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/KickMemberEvent.java b/src/main/java/mops/gruppen2/domain/event/KickMemberEvent.java
new file mode 100644
index 0000000..8d9a080
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/KickMemberEvent.java
@@ -0,0 +1,46 @@
+package mops.gruppen2.domain.event;
+
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.LastAdminException;
+import mops.gruppen2.domain.exception.UserNotFoundException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import java.util.UUID;
+
+/**
+ * Entfernt ein einzelnes Mitglied einer Gruppe.
+ */
+@Log4j2
+@Value
+@AllArgsConstructor
+public class KickMemberEvent extends Event {
+
+ public KickMemberEvent(UUID groupId, String exec, String target) {
+ super(groupId, exec, target);
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {
+ cache.usersRemove(target, group);
+ }
+
+ @Override
+ protected void applyEvent(Group group) throws UserNotFoundException, LastAdminException {
+ group.kickMember(target);
+
+ log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
+ }
+
+ @Override
+ public String format() {
+ return "Mitglied entfernt: " + target + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.KICKMEMBER.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/SetDescriptionEvent.java b/src/main/java/mops/gruppen2/domain/event/SetDescriptionEvent.java
new file mode 100644
index 0000000..5ad51dd
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/SetDescriptionEvent.java
@@ -0,0 +1,50 @@
+package mops.gruppen2.domain.event;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.wrapper.Description;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import javax.validation.Valid;
+import java.util.UUID;
+
+/**
+ * Ändert nur die Gruppenbeschreibung.
+ */
+@Log4j2
+@Value
+@AllArgsConstructor
+public class SetDescriptionEvent extends Event {
+
+ @JsonProperty("desc")
+ Description description;
+
+ public SetDescriptionEvent(UUID groupId, String exec, @Valid Description description) {
+ super(groupId, exec, null);
+ this.description = description;
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {}
+
+ @Override
+ protected void applyEvent(Group group) throws NoAccessException {
+ group.setDescription(exec, description);
+
+ log.trace("\t\t\t\t\tNeue Beschreibung: {}", group.getDescription());
+ }
+
+ @Override
+ public String format() {
+ return "Beschreibung gesetzt: " + description + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.SETDESCRIPTION.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/SetInviteLinkEvent.java b/src/main/java/mops/gruppen2/domain/event/SetInviteLinkEvent.java
new file mode 100644
index 0000000..30c19e7
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/SetInviteLinkEvent.java
@@ -0,0 +1,50 @@
+package mops.gruppen2.domain.event;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.wrapper.Link;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import javax.validation.Valid;
+import java.util.UUID;
+
+@Log4j2
+@Value
+@AllArgsConstructor
+public class SetInviteLinkEvent extends Event {
+
+ @JsonProperty("link")
+ Link link;
+
+ public SetInviteLinkEvent(UUID groupId, String exec, @Valid Link link) {
+ super(groupId, exec, null);
+ this.link = link;
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {
+ cache.linksRemove(group.getLink());
+ cache.linksPut(link.getValue(), group);
+ }
+
+ @Override
+ protected void applyEvent(Group group) throws NoAccessException {
+ group.setLink(exec, link);
+
+ log.trace("\t\t\t\t\tNeuer Link: {}", group.getLink());
+ }
+
+ @Override
+ public String format() {
+ return "Einladungslink gesetzt: " + link + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.SETLINK.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/SetLimitEvent.java b/src/main/java/mops/gruppen2/domain/event/SetLimitEvent.java
new file mode 100644
index 0000000..e69576b
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/SetLimitEvent.java
@@ -0,0 +1,48 @@
+package mops.gruppen2.domain.event;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import javax.validation.Valid;
+import java.util.UUID;
+
+@Log4j2
+@Value
+@AllArgsConstructor
+public class SetLimitEvent extends Event {
+
+ @JsonProperty("limit")
+ Limit limit;
+
+ public SetLimitEvent(UUID groupId, String exec, @Valid Limit limit) {
+ super(groupId, exec, null);
+ this.limit = limit;
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {}
+
+ @Override
+ protected void applyEvent(Group group) throws BadArgumentException, NoAccessException {
+ group.setLimit(exec, limit);
+
+ log.trace("\t\t\t\t\tNeues UserLimit: {}", group.getLimit());
+ }
+
+ @Override
+ public String format() {
+ return "Benutzerlimit gesetzt: " + limit + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.SETLIMIT.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/SetParentEvent.java b/src/main/java/mops/gruppen2/domain/event/SetParentEvent.java
new file mode 100644
index 0000000..be1dda9
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/SetParentEvent.java
@@ -0,0 +1,48 @@
+package mops.gruppen2.domain.event;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.wrapper.Parent;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import javax.validation.Valid;
+import java.util.UUID;
+
+@Log4j2
+@Value
+@AllArgsConstructor
+public class SetParentEvent extends Event {
+
+ @JsonProperty("parent")
+ Parent parent;
+
+ public SetParentEvent(UUID groupId, String exec, @Valid Parent parent) {
+ super(groupId, exec, null);
+ this.parent = parent;
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {}
+
+ @Override
+ protected void applyEvent(Group group) throws NoAccessException, BadArgumentException {
+ group.setParent(exec, parent);
+
+ log.trace("\t\t\t\t\tNeues Parent: {}", group.getParent());
+ }
+
+ @Override
+ public String format() {
+ return "Veranstaltungszugehörigkeit gesetzt: " + parent.getValue() + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.SETPARENT.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/SetTitleEvent.java b/src/main/java/mops/gruppen2/domain/event/SetTitleEvent.java
new file mode 100644
index 0000000..bdfa3d1
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/SetTitleEvent.java
@@ -0,0 +1,51 @@
+package mops.gruppen2.domain.event;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.wrapper.Title;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import javax.validation.Valid;
+import java.util.UUID;
+
+/**
+ * Ändert nur den Gruppentitel.
+ */
+@Log4j2
+@Value
+@AllArgsConstructor
+public class SetTitleEvent extends Event {
+
+ @JsonProperty("title")
+ Title title;
+
+ public SetTitleEvent(UUID groupId, String exec, @Valid Title title) {
+ super(groupId, exec, null);
+ this.title = title;
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {}
+
+ @Override
+ protected void applyEvent(Group group) throws NoAccessException {
+ group.setTitle(exec, title);
+
+ log.trace("\t\t\t\t\tNeuer Titel: {}", group.getTitle());
+ }
+
+ @Override
+ public String format() {
+ return "Titel gesetzt: " + title + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.SETTITLE.toString();
+ }
+
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/SetTypeEvent.java b/src/main/java/mops/gruppen2/domain/event/SetTypeEvent.java
new file mode 100644
index 0000000..85be321
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/event/SetTypeEvent.java
@@ -0,0 +1,57 @@
+package mops.gruppen2.domain.event;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.experimental.NonFinal;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.EventException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import javax.validation.Valid;
+import java.util.UUID;
+
+@Log4j2
+@Value
+@AllArgsConstructor
+public class SetTypeEvent extends Event {
+
+ @JsonProperty("type")
+ Type type;
+
+ //TODO: blöder hack, das soll eigentlich anders gehen
+ // Problem ist, dass die Gruppe vor dem Cache verändert wird, also kann der cache den alten Typ
+ // nicht mehr aus der Gruppe holen
+ @NonFinal
+ Type oldType;
+
+ public SetTypeEvent(UUID groupId, String exec, @Valid Type type) {
+ super(groupId, exec, null);
+
+ this.type = type;
+ }
+
+ @Override
+ protected void updateCache(GroupCache cache, Group group) {
+ cache.typesRemove(oldType, group);
+ cache.typesPut(type, group);
+ }
+
+ @Override
+ protected void applyEvent(Group group) throws EventException {
+ oldType = group.getType();
+ group.setType(exec, type);
+ }
+
+ @Override
+ public String format() {
+ return "Gruppentype gesetzt: " + type + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.SETTYPE.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/event/UpdateGroupDescriptionEvent.java b/src/main/java/mops/gruppen2/domain/event/UpdateGroupDescriptionEvent.java
deleted file mode 100644
index bbd9f6d..0000000
--- a/src/main/java/mops/gruppen2/domain/event/UpdateGroupDescriptionEvent.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.BadParameterException;
-
-import java.util.UUID;
-
-/**
- * Ändert nur die Gruppenbeschreibung.
- */
-@Getter
-@NoArgsConstructor // For Jackson
-public class UpdateGroupDescriptionEvent extends Event {
-
- private String newGroupDescription;
-
- public UpdateGroupDescriptionEvent(UUID groupId, String userId, String newGroupDescription) {
- super(groupId, userId);
- this.newGroupDescription = newGroupDescription.trim();
- }
-
- @Override
- protected void applyEvent(Group group) {
- if (newGroupDescription.isEmpty()) {
- throw new BadParameterException("Die Beschreibung ist leer.");
- }
-
- group.setDescription(newGroupDescription);
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/event/UpdateGroupTitleEvent.java b/src/main/java/mops/gruppen2/domain/event/UpdateGroupTitleEvent.java
deleted file mode 100644
index 689e55f..0000000
--- a/src/main/java/mops/gruppen2/domain/event/UpdateGroupTitleEvent.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.BadParameterException;
-
-import java.util.UUID;
-
-/**
- * Ändert nur den Gruppentitel.
- */
-@Getter
-@NoArgsConstructor // For Jackson
-public class UpdateGroupTitleEvent extends Event {
-
- private String newGroupTitle;
-
- public UpdateGroupTitleEvent(UUID groupId, String userId, String newGroupTitle) {
- super(groupId, userId);
- this.newGroupTitle = newGroupTitle.trim();
- }
-
- @Override
- protected void applyEvent(Group group) {
- if (newGroupTitle.isEmpty()) {
- throw new BadParameterException("Der Titel ist leer.");
- }
-
- group.setTitle(newGroupTitle);
- }
-
-}
diff --git a/src/main/java/mops/gruppen2/domain/event/UpdateRoleEvent.java b/src/main/java/mops/gruppen2/domain/event/UpdateRoleEvent.java
index e7703e3..e5f16fb 100644
--- a/src/main/java/mops/gruppen2/domain/event/UpdateRoleEvent.java
+++ b/src/main/java/mops/gruppen2/domain/event/UpdateRoleEvent.java
@@ -1,35 +1,51 @@
package mops.gruppen2.domain.event;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.Role;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.LastAdminException;
import mops.gruppen2.domain.exception.UserNotFoundException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Role;
+import mops.gruppen2.infrastructure.GroupCache;
import java.util.UUID;
/**
* Aktualisiert die Gruppenrolle eines Teilnehmers.
*/
-@Getter
-@NoArgsConstructor // For Jackson
+@Log4j2
+@Value
+@AllArgsConstructor
public class UpdateRoleEvent extends Event {
- private Role newRole;
+ @JsonProperty("role")
+ Role role;
- public UpdateRoleEvent(UUID groupId, String userId, Role newRole) {
- super(groupId, userId);
- this.newRole = newRole;
+ public UpdateRoleEvent(UUID groupId, String exec, String target, Role role) {
+ super(groupId, exec, target);
+ this.role = role;
}
@Override
- protected void applyEvent(Group group) throws UserNotFoundException {
- if (group.getRoles().containsKey(userId)) {
- group.getRoles().put(userId, newRole);
- return;
- }
+ protected void updateCache(GroupCache cache, Group group) {}
- throw new UserNotFoundException(getClass().toString());
+ @Override
+ protected void applyEvent(Group group) throws UserNotFoundException, LastAdminException {
+ group.memberPutRole(target, role);
+
+ log.trace("\t\t\t\t\tNeue Admin: {}", group.getAdmins());
+ }
+
+ @Override
+ public String format() {
+ return "Mitgliedsrolle gesetzt: " + target + ": " + role + ".";
+ }
+
+ @Override
+ public String type() {
+ return EventType.UPDATEROLE.toString();
}
}
diff --git a/src/main/java/mops/gruppen2/domain/event/UpdateUserMaxEvent.java b/src/main/java/mops/gruppen2/domain/event/UpdateUserMaxEvent.java
deleted file mode 100644
index f9df452..0000000
--- a/src/main/java/mops/gruppen2/domain/event/UpdateUserMaxEvent.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.BadParameterException;
-import mops.gruppen2.domain.exception.EventException;
-
-import java.util.UUID;
-
-@Getter
-@NoArgsConstructor
-public class UpdateUserMaxEvent extends Event {
-
- private Long userMaximum;
-
- public UpdateUserMaxEvent(UUID groupId, String userId, Long userMaximum) {
- super(groupId, userId);
- this.userMaximum = userMaximum;
- }
-
- @Override
- protected void applyEvent(Group group) throws EventException {
- if (userMaximum <= 0 || userMaximum < group.getMembers().size()) {
- throw new BadParameterException("Usermaximum zu klein.");
- }
-
- group.setUserMaximum(userMaximum);
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/exception/BadArgumentException.java b/src/main/java/mops/gruppen2/domain/exception/BadArgumentException.java
new file mode 100644
index 0000000..425a6d1
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/exception/BadArgumentException.java
@@ -0,0 +1,12 @@
+package mops.gruppen2.domain.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class BadArgumentException extends EventException {
+
+ private static final long serialVersionUID = -6757742013238625595L;
+
+ public BadArgumentException(String info) {
+ super(HttpStatus.BAD_REQUEST, "Fehlerhafter Parameter.", info);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/exception/BadParameterException.java b/src/main/java/mops/gruppen2/domain/exception/BadParameterException.java
deleted file mode 100644
index a6b8d6e..0000000
--- a/src/main/java/mops/gruppen2/domain/exception/BadParameterException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package mops.gruppen2.domain.exception;
-
-import org.springframework.http.HttpStatus;
-
-public class BadParameterException extends EventException {
-
- public BadParameterException(String info) {
- super(HttpStatus.BAD_REQUEST, "Fehlerhafter Parameter angegeben!", info);
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/exception/BadPayloadException.java b/src/main/java/mops/gruppen2/domain/exception/BadPayloadException.java
new file mode 100644
index 0000000..4281ac2
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/exception/BadPayloadException.java
@@ -0,0 +1,13 @@
+package mops.gruppen2.domain.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class BadPayloadException extends EventException {
+
+ private static final long serialVersionUID = -3978242017847155629L;
+
+ public BadPayloadException(String info) {
+ super(HttpStatus.INTERNAL_SERVER_ERROR, "Payload konnte nicht übersetzt werden.", info);
+ }
+}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/EventException.java b/src/main/java/mops/gruppen2/domain/exception/EventException.java
index 38d56d9..4d59dd2 100644
--- a/src/main/java/mops/gruppen2/domain/exception/EventException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/EventException.java
@@ -5,8 +5,10 @@ import org.springframework.web.server.ResponseStatusException;
public class EventException extends ResponseStatusException {
+ private static final long serialVersionUID = 6784052016028094340L;
+
public EventException(HttpStatus status, String msg, String info) {
- super(status, msg + " (" + info + ")");
+ super(status, info.isBlank() ? "" : msg + " (" + info + ")");
}
}
diff --git a/src/main/java/mops/gruppen2/domain/exception/GroupFullException.java b/src/main/java/mops/gruppen2/domain/exception/GroupFullException.java
index 014f0d7..5f2d4c6 100644
--- a/src/main/java/mops/gruppen2/domain/exception/GroupFullException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/GroupFullException.java
@@ -4,8 +4,10 @@ import org.springframework.http.HttpStatus;
public class GroupFullException extends EventException {
+ private static final long serialVersionUID = -4011141160467668713L;
+
public GroupFullException(String info) {
- super(HttpStatus.INTERNAL_SERVER_ERROR, "Die Gruppe hat die maximale Midgliederanzahl bereits erreicht!", info);
+ super(HttpStatus.INTERNAL_SERVER_ERROR, "Gruppe hat maximale Teilnehmeranzahl bereits erreicht.", info);
}
}
diff --git a/src/main/java/mops/gruppen2/domain/exception/GroupIdMismatchException.java b/src/main/java/mops/gruppen2/domain/exception/GroupIdMismatchException.java
deleted file mode 100644
index 67d0905..0000000
--- a/src/main/java/mops/gruppen2/domain/exception/GroupIdMismatchException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package mops.gruppen2.domain.exception;
-
-import org.springframework.http.HttpStatus;
-
-public class GroupIdMismatchException extends EventException {
-
- public GroupIdMismatchException(String info) {
- super(HttpStatus.INTERNAL_SERVER_ERROR, "Falsche Gruppe für Event.", info);
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/exception/GroupNotFoundException.java b/src/main/java/mops/gruppen2/domain/exception/GroupNotFoundException.java
index 82a2dc7..5a10585 100644
--- a/src/main/java/mops/gruppen2/domain/exception/GroupNotFoundException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/GroupNotFoundException.java
@@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
public class GroupNotFoundException extends EventException {
+ private static final long serialVersionUID = -4738218416842951106L;
+
public GroupNotFoundException(String info) {
- super(HttpStatus.NOT_FOUND, "Gruppe wurde nicht gefunden.", info);
+ super(HttpStatus.NOT_FOUND, "Gruppe existiert nicht oder wurde gelöscht.", info);
}
}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/IdMismatchException.java b/src/main/java/mops/gruppen2/domain/exception/IdMismatchException.java
new file mode 100644
index 0000000..1200f8b
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/exception/IdMismatchException.java
@@ -0,0 +1,13 @@
+package mops.gruppen2.domain.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class IdMismatchException extends EventException {
+
+ private static final long serialVersionUID = 7944077617758922089L;
+
+ public IdMismatchException(String info) {
+ super(HttpStatus.INTERNAL_SERVER_ERROR, "Ids stimmen nicht überein.", info);
+ }
+}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/InvalidInviteException.java b/src/main/java/mops/gruppen2/domain/exception/InvalidInviteException.java
index 6202155..2f9b19e 100644
--- a/src/main/java/mops/gruppen2/domain/exception/InvalidInviteException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/InvalidInviteException.java
@@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
public class InvalidInviteException extends EventException {
+ private static final long serialVersionUID = 2643001101459427944L;
+
public InvalidInviteException(String info) {
- super(HttpStatus.NOT_FOUND, "Der Einladungslink ist ungültig.", info);
+ super(HttpStatus.NOT_FOUND, "Einladungslink ist ungültig oder Gruppe wurde gelöscht.", info);
}
}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/LastAdminException.java b/src/main/java/mops/gruppen2/domain/exception/LastAdminException.java
new file mode 100644
index 0000000..a6af0ea
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/exception/LastAdminException.java
@@ -0,0 +1,12 @@
+package mops.gruppen2.domain.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class LastAdminException extends EventException {
+
+ private static final long serialVersionUID = 9059481382346544288L;
+
+ public LastAdminException(String info) {
+ super(HttpStatus.INTERNAL_SERVER_ERROR, "Gruppe braucht mindestens einen Admin.", info);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/exception/NoAccessException.java b/src/main/java/mops/gruppen2/domain/exception/NoAccessException.java
index 38ec56a..27c569b 100644
--- a/src/main/java/mops/gruppen2/domain/exception/NoAccessException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/NoAccessException.java
@@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
public class NoAccessException extends EventException {
+ private static final long serialVersionUID = 1696988497122834654L;
+
public NoAccessException(String info) {
- super(HttpStatus.FORBIDDEN, "Hier hast du leider keinen Zugriff!", info);
+ super(HttpStatus.FORBIDDEN, "Kein Zugriff.", info);
}
}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/NoAdminAfterActionException.java b/src/main/java/mops/gruppen2/domain/exception/NoAdminAfterActionException.java
deleted file mode 100644
index f0b170b..0000000
--- a/src/main/java/mops/gruppen2/domain/exception/NoAdminAfterActionException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package mops.gruppen2.domain.exception;
-
-import org.springframework.http.HttpStatus;
-
-public class NoAdminAfterActionException extends EventException {
-
- public NoAdminAfterActionException(String info) {
- super(HttpStatus.INTERNAL_SERVER_ERROR, "Nach dieser Aktion hätte die Gruppe keinen Admin mehr", info);
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/exception/NoInviteExistException.java b/src/main/java/mops/gruppen2/domain/exception/NoInviteExistException.java
index 9a61523..d56b8ab 100644
--- a/src/main/java/mops/gruppen2/domain/exception/NoInviteExistException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/NoInviteExistException.java
@@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
public class NoInviteExistException extends EventException {
+ private static final long serialVersionUID = -8092076461455840693L;
+
public NoInviteExistException(String info) {
super(HttpStatus.NOT_FOUND, "Für diese Gruppe existiert kein Link.", info);
}
}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/PageNotFoundException.java b/src/main/java/mops/gruppen2/domain/exception/PageNotFoundException.java
index 8a44f16..0871621 100644
--- a/src/main/java/mops/gruppen2/domain/exception/PageNotFoundException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/PageNotFoundException.java
@@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
public class PageNotFoundException extends EventException {
+ private static final long serialVersionUID = 2374509005158710104L;
+
public PageNotFoundException(String info) {
- super(HttpStatus.NOT_FOUND, "Die Seite wurde nicht gefunden!", info);
+ super(HttpStatus.NOT_FOUND, "Seite wurde nicht gefunden.", info);
}
}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/UserAlreadyExistsException.java b/src/main/java/mops/gruppen2/domain/exception/UserAlreadyExistsException.java
deleted file mode 100644
index ba8b676..0000000
--- a/src/main/java/mops/gruppen2/domain/exception/UserAlreadyExistsException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package mops.gruppen2.domain.exception;
-
-import org.springframework.http.HttpStatus;
-
-public class UserAlreadyExistsException extends EventException {
-
- public UserAlreadyExistsException(String info) {
- super(HttpStatus.INTERNAL_SERVER_ERROR, "Der User existiert bereits.", info);
- }
-}
diff --git a/src/main/java/mops/gruppen2/domain/exception/UserExistsException.java b/src/main/java/mops/gruppen2/domain/exception/UserExistsException.java
new file mode 100644
index 0000000..43f5d59
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/exception/UserExistsException.java
@@ -0,0 +1,13 @@
+package mops.gruppen2.domain.exception;
+
+import org.springframework.http.HttpStatus;
+
+public class UserExistsException extends EventException {
+
+ private static final long serialVersionUID = -8150634358760194625L;
+
+ public UserExistsException(String info) {
+ super(HttpStatus.INTERNAL_SERVER_ERROR, "User existiert bereits.", info);
+ }
+}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/UserNotFoundException.java b/src/main/java/mops/gruppen2/domain/exception/UserNotFoundException.java
index 29209bd..e1273df 100644
--- a/src/main/java/mops/gruppen2/domain/exception/UserNotFoundException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/UserNotFoundException.java
@@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
public class UserNotFoundException extends EventException {
+ private static final long serialVersionUID = 8347442921199785291L;
+
public UserNotFoundException(String info) {
- super(HttpStatus.NOT_FOUND, "Der User wurde nicht gefunden.", info);
+ super(HttpStatus.NOT_FOUND, "User existiert nicht.", info);
}
}
+
diff --git a/src/main/java/mops/gruppen2/domain/exception/WrongFileException.java b/src/main/java/mops/gruppen2/domain/exception/WrongFileException.java
index 665c9da..45fcaa7 100644
--- a/src/main/java/mops/gruppen2/domain/exception/WrongFileException.java
+++ b/src/main/java/mops/gruppen2/domain/exception/WrongFileException.java
@@ -4,7 +4,10 @@ import org.springframework.http.HttpStatus;
public class WrongFileException extends EventException {
+ private static final long serialVersionUID = -166192514348555116L;
+
public WrongFileException(String info) {
- super(HttpStatus.BAD_REQUEST, "Die entsprechende Datei ist keine valide CSV-Datei!", info);
+ super(HttpStatus.BAD_REQUEST, "Datei ist keine valide CSV-Datei.", info);
}
}
+
diff --git a/src/main/java/mops/gruppen2/domain/model/group/Group.java b/src/main/java/mops/gruppen2/domain/model/group/Group.java
new file mode 100644
index 0000000..61feb00
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/Group.java
@@ -0,0 +1,357 @@
+package mops.gruppen2.domain.model.group;
+
+import lombok.AccessLevel;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.exception.GroupFullException;
+import mops.gruppen2.domain.exception.IdMismatchException;
+import mops.gruppen2.domain.exception.LastAdminException;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.exception.UserExistsException;
+import mops.gruppen2.domain.exception.UserNotFoundException;
+import mops.gruppen2.domain.model.group.wrapper.Body;
+import mops.gruppen2.domain.model.group.wrapper.Description;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.domain.model.group.wrapper.Link;
+import mops.gruppen2.domain.model.group.wrapper.Parent;
+import mops.gruppen2.domain.model.group.wrapper.Title;
+import mops.gruppen2.domain.service.helper.CommonHelper;
+import mops.gruppen2.domain.service.helper.SortHelper;
+import mops.gruppen2.domain.service.helper.ValidationHelper;
+
+import javax.validation.Valid;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * Repräsentiert den aggregierten Zustand einer Gruppe.
+ *
+ *
+ * Muss beim Start gesetzt werden: groupid, meta
+ */
+@Log4j2
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+public class Group {
+
+ // Metainformationen
+ @EqualsAndHashCode.Include
+ private UUID groupid;
+
+ @Getter
+ private Type type = Type.PRIVATE;
+
+ private Parent parent = Parent.EMPTY();
+
+ private Limit limit = Limit.DEFAULT(); // Add initial user
+
+ private Link link = Link.RANDOM();
+
+ private GroupMeta meta = GroupMeta.EMPTY();
+
+ //TODO: UI set + use for options
+ private final GroupOptions options = GroupOptions.DEFAULT();
+
+ // Inhalt
+ private Title title = Title.EMPTY();
+
+ private Description description = Description.EMPTY();
+
+ //TODO: Asciidoc description
+ private Body body;
+
+ // Integrationen
+
+ // Teilnehmer
+ private final Map memberships = new HashMap<>();
+
+
+ // ####################################### Members ###########################################
+
+
+ public List getMembers() {
+ return SortHelper.sortByMemberRole(new ArrayList<>(memberships.values())).stream()
+ .map(Membership::getUser)
+ .collect(Collectors.toList());
+ }
+
+ public List getRegulars() {
+ return memberships.values().stream()
+ .map(Membership::getUser)
+ .filter(member -> isRegular(member.getId()))
+ .collect(Collectors.toList());
+ }
+
+ public List getAdmins() {
+ return memberships.values().stream()
+ .map(Membership::getUser)
+ .filter(member -> isAdmin(member.getId()))
+ .collect(Collectors.toList());
+ }
+
+ public Role getRole(String userid) {
+ return memberships.get(userid).getRole();
+ }
+
+ public void addMember(String target, User user) throws UserExistsException, GroupFullException {
+ ValidationHelper.throwIfMember(this, target);
+ ValidationHelper.throwIfGroupFull(this);
+
+ memberships.put(target, new Membership(user, Role.REGULAR));
+ }
+
+ public void kickMember(String target) throws UserNotFoundException, LastAdminException {
+ ValidationHelper.throwIfNoMember(this, target);
+ ValidationHelper.throwIfLastAdmin(this, target);
+
+ memberships.remove(target);
+ }
+
+ public boolean memberHasRole(String target, Role role) {
+ ValidationHelper.throwIfNoMember(this, target);
+
+ return memberships.get(target).getRole() == role;
+ }
+
+ public void memberPutRole(String target, Role role) throws UserNotFoundException, LastAdminException {
+ ValidationHelper.throwIfNoMember(this, target);
+ if (role == Role.REGULAR) {
+ ValidationHelper.throwIfLastAdmin(this, target);
+ }
+
+ memberships.put(target, memberships.get(target).setRole(role));
+ }
+
+ public boolean isMember(String target) {
+ return memberships.containsKey(target);
+ }
+
+ public boolean isAdmin(String target) throws UserNotFoundException {
+ ValidationHelper.throwIfNoMember(this, target);
+
+ return memberships.get(target).getRole() == Role.ADMIN;
+ }
+
+ public boolean isRegular(String target) throws UserNotFoundException {
+ ValidationHelper.throwIfNoMember(this, target);
+
+ return memberships.get(target).getRole() == Role.REGULAR;
+ }
+
+
+ // ######################################### Getters #########################################
+
+
+ public UUID getId() {
+ return groupid;
+ }
+
+ public UUID getParent() {
+ return parent.getValue();
+ }
+
+ public long getLimit() {
+ return limit.getValue();
+ }
+
+ public String getTitle() {
+ return title.toString();
+ }
+
+ public String getDescription() {
+ return description.getValue();
+ }
+
+ public String getLink() {
+ return link.getValue();
+ }
+
+ public String creator() {
+ return meta.getCreator();
+ }
+
+ public long version() {
+ return meta.getVersion();
+ }
+
+ public LocalDateTime creationDate() {
+ return meta.getCreationDate();
+ }
+
+ public int size() {
+ return memberships.size();
+ }
+
+ public boolean isFull() {
+ return size() >= limit.getValue();
+ }
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ public boolean exists() {
+ return groupid != null && !CommonHelper.uuidIsEmpty(groupid);
+ }
+
+ public boolean isPublic() {
+ return type == Type.PUBLIC;
+ }
+
+ public boolean isPrivate() {
+ return type == Type.PRIVATE;
+ }
+
+ public boolean isLecture() {
+ return type == Type.LECTURE;
+ }
+
+ public boolean hasParent() {
+ return !parent.isEmpty();
+ }
+
+ public boolean hasMaterial() {
+ return options.isHasMaterialIntegration();
+ }
+
+ public boolean hasForums() {
+ return options.isHasForumsIntegration();
+ }
+
+ public boolean hasCalendar() {
+ return options.isHasTermineIntegration();
+ }
+
+ public boolean hasModules() {
+ return options.isHasModulesIntegration();
+ }
+
+ public boolean hasPortfolios() {
+ return options.isHasPortfolioIntegration();
+ }
+
+
+ // ######################################## Setters ##########################################
+
+
+ public void setId(UUID groupid) throws BadArgumentException {
+ if (this.groupid != null) {
+ throw new BadArgumentException("GruppenId bereits gesetzt.");
+ }
+
+ this.groupid = groupid;
+ }
+
+ public void setType(String exec, Type type) throws NoAccessException {
+ ValidationHelper.throwIfNoAdmin(this, exec);
+
+ this.type = type;
+ }
+
+ public void setTitle(String exec, @Valid Title title) throws NoAccessException {
+ ValidationHelper.throwIfNoAdmin(this, exec);
+
+ this.title = title;
+ }
+
+ public void setDescription(String exec, @Valid Description description) throws NoAccessException {
+ ValidationHelper.throwIfNoAdmin(this, exec);
+
+ this.description = description;
+ }
+
+ public void setLimit(String exec, @Valid Limit limit) throws NoAccessException, BadArgumentException {
+ ValidationHelper.throwIfNoAdmin(this, exec);
+
+ if (size() > limit.getValue()) {
+ throw new BadArgumentException("Das Userlimit ist zu klein für die Gruppe.");
+ }
+
+ this.limit = limit;
+ }
+
+ public void setParent(String exec, @Valid Parent parent) throws NoAccessException, BadArgumentException {
+ ValidationHelper.throwIfNoAdmin(this, exec);
+ if (parent.getValue().equals(groupid)) {
+ throw new BadArgumentException("Die Gruppe kann nicht zu sich selbst gehören!");
+ }
+
+ this.parent = parent;
+ }
+
+ public void setLink(String exec, @Valid Link link) throws NoAccessException {
+ ValidationHelper.throwIfNoAdmin(this, exec);
+ if (link.getValue().equals(groupid.toString())) {
+ throw new BadArgumentException("Link kann nicht der GruppenID entsprechen.");
+ }
+
+ this.link = link;
+ }
+
+ public void updateVersion(long version) throws IdMismatchException {
+ meta = meta.setVersion(version);
+ }
+
+ public void setCreator(String target) throws BadArgumentException {
+ meta = meta.setCreator(target);
+ }
+
+ public void setCreationDate(LocalDateTime date) throws BadArgumentException {
+ meta = meta.setCreationDate(date);
+ }
+
+
+ // ######################################### Util ############################################
+
+
+ public void destroy(String userid) throws NoAccessException {
+ if (!isEmpty()) {
+ ValidationHelper.throwIfNoAdmin(this, userid);
+ }
+
+ groupid = null;
+ // Wenn man alles null setzt hat der cache mehr arbeit, weil dieser erst nach der löschung
+ // geupdated wird und sich link und mitgliedschaften selber heraussuchen muss
+ /*type = null;
+ parent = null;
+ limit = null;
+ link = null;
+ meta = null;
+ options = null;
+ title = null;
+ description = null;
+ body = null;
+ memberships = null;*/
+ }
+
+ public String format() {
+ return title + " - " + description;
+ }
+
+ @Override
+ public String toString() {
+ return "group("
+ + (groupid == null ? "groupid: null" : groupid.toString())
+ + ", "
+ + (parent == null ? "parent: null" : parent.toString())
+ + ", "
+ + (meta == null ? "meta: null" : meta.toString())
+ + ")";
+ }
+
+ public static Group EMPTY() {
+ return new Group();
+ }
+
+ public long getVersion() {
+ return meta.getVersion();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/GroupMeta.java b/src/main/java/mops/gruppen2/domain/model/group/GroupMeta.java
new file mode 100644
index 0000000..44a7a07
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/GroupMeta.java
@@ -0,0 +1,50 @@
+package mops.gruppen2.domain.model.group;
+
+import lombok.ToString;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.exception.IdMismatchException;
+
+import java.time.LocalDateTime;
+
+@Log4j2
+@Value
+@ToString
+class GroupMeta {
+
+ long version;
+ String creator;
+ LocalDateTime creationDate;
+
+ GroupMeta setVersion(long version) throws IdMismatchException {
+ if (this.version >= version) {
+ throw new IdMismatchException("Die Gruppe ist bereits auf einem neueren Stand.");
+ }
+ if (this.version + 1 != version) {
+ throw new IdMismatchException("Es fehlen vorherige Events.");
+ }
+
+ return new GroupMeta(version, creator, creationDate);
+ }
+
+ GroupMeta setCreator(String userid) throws BadArgumentException {
+ if (creator != null) {
+ throw new BadArgumentException("Gruppe hat schon einen Ersteller.");
+ }
+
+ return new GroupMeta(version, userid, creationDate);
+ }
+
+ GroupMeta setCreationDate(LocalDateTime date) throws BadArgumentException {
+ if (creationDate != null) {
+ throw new BadArgumentException("Gruppe hat schon ein Erstellungsdatum.");
+ }
+
+ return new GroupMeta(version, creator, date);
+ }
+
+ static GroupMeta EMPTY() {
+ return new GroupMeta(0, null, null);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/GroupOptions.java b/src/main/java/mops/gruppen2/domain/model/group/GroupOptions.java
new file mode 100644
index 0000000..f0cd1f6
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/GroupOptions.java
@@ -0,0 +1,40 @@
+package mops.gruppen2.domain.model.group;
+
+import lombok.Value;
+
+//TODO: doooooodododo
+@Value
+class GroupOptions {
+
+ // Gruppe
+ boolean showClearname;
+ boolean hasBody;
+ boolean isLeavable;
+ boolean hasLink;
+
+ String customLogo;
+ String customBackground;
+ String customTitle;
+
+ // Integrations
+ boolean hasMaterialIntegration;
+ boolean hasTermineIntegration;
+ boolean hasPortfolioIntegration;
+ boolean hasForumsIntegration;
+ boolean hasModulesIntegration;
+
+ static GroupOptions DEFAULT() {
+ return new GroupOptions(true,
+ false,
+ true,
+ false,
+ null,
+ null,
+ null,
+ true,
+ true,
+ true,
+ true,
+ true);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/Membership.java b/src/main/java/mops/gruppen2/domain/model/group/Membership.java
new file mode 100644
index 0000000..7a730ce
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/Membership.java
@@ -0,0 +1,23 @@
+package mops.gruppen2.domain.model.group;
+
+import lombok.EqualsAndHashCode;
+import lombok.Value;
+
+@Value
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+public class Membership {
+
+ User user;
+ Role role;
+
+ // LocalDateTime age;
+
+ @Override
+ public String toString() {
+ return user.format() + ": " + role;
+ }
+
+ public Membership setRole(Role role) {
+ return new Membership(user, role);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/Role.java b/src/main/java/mops/gruppen2/domain/model/group/Role.java
new file mode 100644
index 0000000..0b7c4d5
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/Role.java
@@ -0,0 +1,10 @@
+package mops.gruppen2.domain.model.group;
+
+public enum Role {
+ ADMIN,
+ REGULAR;
+
+ public Role toggle() {
+ return this == ADMIN ? REGULAR : ADMIN;
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/Type.java b/src/main/java/mops/gruppen2/domain/model/group/Type.java
new file mode 100644
index 0000000..eae882e
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/Type.java
@@ -0,0 +1,7 @@
+package mops.gruppen2.domain.model.group;
+
+public enum Type {
+ PUBLIC,
+ PRIVATE,
+ LECTURE
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/User.java b/src/main/java/mops/gruppen2/domain/model/group/User.java
new file mode 100644
index 0000000..7f781ca
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/User.java
@@ -0,0 +1,64 @@
+package mops.gruppen2.domain.model.group;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Value;
+import lombok.extern.log4j.Log4j2;
+import org.keycloak.KeycloakPrincipal;
+import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
+
+@Log4j2
+@Value
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
+@AllArgsConstructor
+public class User {
+
+ @EqualsAndHashCode.Include
+ @Getter(AccessLevel.NONE)
+ @JsonProperty("id")
+ String userid;
+
+ @JsonProperty("givenname")
+ String givenname;
+
+ @JsonProperty("familyname")
+ String familyname;
+
+ @JsonProperty("email")
+ String email;
+
+ public User(KeycloakAuthenticationToken token) {
+ KeycloakPrincipal principal = (KeycloakPrincipal) token.getPrincipal();
+ userid = principal.getName();
+ givenname = principal.getKeycloakSecurityContext().getIdToken().getGivenName();
+ familyname = principal.getKeycloakSecurityContext().getIdToken().getFamilyName();
+ email = principal.getKeycloakSecurityContext().getIdToken().getEmail();
+ }
+
+ /**
+ * User identifizieren sich über die Id, mehr wird also manchmal nicht benötigt.
+ *
+ * @param userid Die User Id
+ */
+ public User(String userid) {
+ this.userid = userid;
+ givenname = "";
+ familyname = "";
+ email = "";
+ }
+
+ public String getId() {
+ return userid;
+ }
+
+ public String format() {
+ return givenname + " " + familyname;
+ }
+
+ public boolean isMember(Group group) {
+ return group.getMembers().contains(this);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/wrapper/Body.java b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Body.java
new file mode 100644
index 0000000..791b527
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Body.java
@@ -0,0 +1,8 @@
+package mops.gruppen2.domain.model.group.wrapper;
+
+import lombok.Value;
+
+//TODO: do it
+@Value
+public class Body {
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/wrapper/Description.java b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Description.java
new file mode 100644
index 0000000..5be889e
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Description.java
@@ -0,0 +1,27 @@
+package mops.gruppen2.domain.model.group.wrapper;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Value;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+@Value
+public class Description {
+
+ @NotNull
+ @Size(min = 4, max = 512)
+ @JsonProperty("value")
+ String value;
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @JsonIgnore
+ public static Description EMPTY() {
+ return new Description("EMPTY");
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/wrapper/Limit.java b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Limit.java
new file mode 100644
index 0000000..b06d69e
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Limit.java
@@ -0,0 +1,27 @@
+package mops.gruppen2.domain.model.group.wrapper;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Value;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Value
+public class Limit {
+
+ @NotNull
+ @Min(1)
+ @Max(999_999)
+ @JsonProperty("value")
+ long value;
+
+ public static Limit DEFAULT() {
+ return new Limit(1);
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/wrapper/Link.java b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Link.java
new file mode 100644
index 0000000..963dd94
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Link.java
@@ -0,0 +1,27 @@
+package mops.gruppen2.domain.model.group.wrapper;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Value;
+
+import javax.validation.constraints.NotNull;
+import java.util.UUID;
+
+@Value
+public class Link {
+
+ @NotNull
+ @JsonProperty("value")
+ UUID value;
+
+ public Link(String value) {
+ this.value = UUID.fromString(value);
+ }
+
+ public static Link RANDOM() {
+ return new Link(UUID.randomUUID().toString());
+ }
+
+ public String getValue() {
+ return value.toString();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/wrapper/Parent.java b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Parent.java
new file mode 100644
index 0000000..e19cc6e
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Parent.java
@@ -0,0 +1,36 @@
+package mops.gruppen2.domain.model.group.wrapper;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.ToString;
+import lombok.Value;
+import mops.gruppen2.domain.service.helper.CommonHelper;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.beans.ConstructorProperties;
+import java.util.UUID;
+
+@Value
+@ToString
+public class Parent {
+
+ @NotNull
+ @JsonProperty("id")
+ UUID value;
+
+ @ConstructorProperties("id")
+ public Parent(@NotBlank @Size(min = 36, max = 36) String parentid) {
+ value = UUID.fromString(parentid);
+ }
+
+ public static Parent EMPTY() {
+ return new Parent("00000000-0000-0000-0000-000000000000");
+ }
+
+ @JsonIgnore
+ public boolean isEmpty() {
+ return CommonHelper.uuidIsEmpty(value);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/model/group/wrapper/Title.java b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Title.java
new file mode 100644
index 0000000..651dabc
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/model/group/wrapper/Title.java
@@ -0,0 +1,27 @@
+package mops.gruppen2.domain.model.group.wrapper;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Value;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+@Value
+public class Title {
+
+ @NotNull
+ @Size(min = 4, max = 128)
+ @JsonProperty("value")
+ String value;
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @JsonIgnore
+ public static Title EMPTY() {
+ return new Title("EMPTY");
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/EventStoreService.java b/src/main/java/mops/gruppen2/domain/service/EventStoreService.java
new file mode 100644
index 0000000..31ea0b8
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/EventStoreService.java
@@ -0,0 +1,130 @@
+package mops.gruppen2.domain.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.event.Event;
+import mops.gruppen2.domain.exception.BadPayloadException;
+import mops.gruppen2.domain.service.helper.CommonHelper;
+import mops.gruppen2.domain.service.helper.FileHelper;
+import mops.gruppen2.persistance.EventRepository;
+import mops.gruppen2.persistance.dto.EventDTO;
+import org.springframework.stereotype.Service;
+
+import java.sql.Timestamp;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Log4j2
+@RequiredArgsConstructor
+@Service
+public class EventStoreService {
+
+ private final EventRepository eventStore;
+
+
+ //########################################### SAVE ###########################################
+
+
+ /**
+ * Erzeugt ein DTO aus einem Event und speicher es.
+ *
+ * @param event Event, welches gespeichert wird
+ */
+ public void saveEvent(Event event) {
+ eventStore.save(getDTOFromEvent(event));
+ }
+
+ public void saveAll(Event... events) {
+ for (Event event : events) {
+ eventStore.save(getDTOFromEvent(event));
+ }
+ }
+
+
+ //########################################### DTOs ###########################################
+
+
+ /**
+ * Erzeugt aus einem Event Objekt ein EventDTO Objekt.
+ *
+ * @param event Event, welches in DTO übersetzt wird
+ *
+ * @return EventDTO (Neues DTO)
+ */
+ private static EventDTO getDTOFromEvent(Event event) {
+ try {
+ String payload = FileHelper.serializeEventJson(event);
+ return new EventDTO(null,
+ event.getGroupid().toString(),
+ event.getVersion(),
+ event.getExec(),
+ event.getTarget(),
+ Timestamp.valueOf(event.getDate()),
+ payload);
+ } catch (JsonProcessingException e) {
+ log.error("Event ({}) konnte nicht serialisiert werden!", event, e);
+ throw new BadPayloadException(EventStoreService.class.toString());
+ }
+ }
+
+ /**
+ * Erzeugt aus einer Liste von eventDTOs eine Liste von Events.
+ *
+ * @param eventDTOS Liste von DTOs
+ *
+ * @return Liste von Events
+ */
+ private static List getEventsFromDTOs(List eventDTOS) {
+ return eventDTOS.stream()
+ .map(EventStoreService::getEventFromDTO)
+ .collect(Collectors.toList());
+ }
+
+ private static Event getEventFromDTO(EventDTO dto) {
+ try {
+ return FileHelper.deserializeEventJson(dto.getEvent_payload());
+ } catch (JsonProcessingException e) {
+ log.error("Payload {} konnte nicht deserialisiert werden!", dto.getEvent_payload(), e);
+ throw new BadPayloadException(EventStoreService.class.toString());
+ }
+ }
+
+
+ // #################################### SIMPLE QUERIES #######################################
+
+
+ public List findAllEvents() {
+ return getEventsFromDTOs(eventStore.findAllEvents());
+ }
+
+ public List findGroupEvents(UUID groupId) {
+ return getEventsFromDTOs(eventStore.findGroupEvents(groupId.toString()));
+ }
+
+ public List findGroupEvents(List ids) {
+ return ids.stream()
+ .map(id -> eventStore.findGroupEvents(id.toString()))
+ .map(EventStoreService::getEventsFromDTOs)
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
+ }
+
+ public List findGroupPayloads(UUID groupId) {
+ return eventStore.findGroupPayloads(groupId.toString());
+ }
+
+ public List findGroupDTOs(UUID groupid) {
+ return eventStore.findGroupEvents(groupid.toString());
+ }
+
+ public List findChangedGroups(long eventid) {
+ return CommonHelper.stringsToUUID(eventStore.findChangedGroupIds(eventid));
+ }
+
+ public long findMaxEventId() {
+ return eventStore.findMaxEventId();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/GroupService.java b/src/main/java/mops/gruppen2/domain/service/GroupService.java
new file mode 100644
index 0000000..9569a67
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/GroupService.java
@@ -0,0 +1,280 @@
+package mops.gruppen2.domain.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.event.AddMemberEvent;
+import mops.gruppen2.domain.event.CreateGroupEvent;
+import mops.gruppen2.domain.event.DestroyGroupEvent;
+import mops.gruppen2.domain.event.Event;
+import mops.gruppen2.domain.event.KickMemberEvent;
+import mops.gruppen2.domain.event.SetDescriptionEvent;
+import mops.gruppen2.domain.event.SetInviteLinkEvent;
+import mops.gruppen2.domain.event.SetLimitEvent;
+import mops.gruppen2.domain.event.SetParentEvent;
+import mops.gruppen2.domain.event.SetTitleEvent;
+import mops.gruppen2.domain.event.SetTypeEvent;
+import mops.gruppen2.domain.event.UpdateRoleEvent;
+import mops.gruppen2.domain.exception.EventException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Role;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.domain.model.group.wrapper.Description;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.domain.model.group.wrapper.Link;
+import mops.gruppen2.domain.model.group.wrapper.Parent;
+import mops.gruppen2.domain.model.group.wrapper.Title;
+import mops.gruppen2.domain.service.helper.ValidationHelper;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.springframework.stereotype.Service;
+
+import javax.validation.Valid;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * Behandelt Aufgaben, welche sich auf eine Gruppe beziehen.
+ * Es werden übergebene Gruppen bearbeitet und dementsprechend Events erzeugt und gespeichert.
+ */
+@Log4j2
+@RequiredArgsConstructor
+@Service
+public class GroupService {
+
+ private final GroupCache groupCache;
+ private final EventStoreService eventStoreService;
+
+ // ################################# GRUPPE ERSTELLEN ########################################
+
+
+ public Group createGroup(String exec) {
+ return createGroup(UUID.randomUUID(), exec, LocalDateTime.now());
+ }
+
+ public void initGroupMembers(Group group,
+ String exec,
+ String target,
+ User user,
+ Limit limit) {
+
+ addMember(group, exec, target, user);
+ updateRole(group, exec, target, Role.ADMIN);
+ setLimit(group, exec, limit);
+ }
+
+ public void initGroupMeta(Group group,
+ String exec,
+ Type type,
+ Parent parent) {
+
+ setType(group, exec, type);
+ setParent(group, exec, parent);
+ }
+
+ public void initGroupText(Group group,
+ String exec,
+ Title title,
+ Description description) {
+
+ setTitle(group, exec, title);
+ setDescription(group, exec, description);
+ }
+
+
+ // ################################### GRUPPEN ÄNDERN ########################################
+
+
+ /**
+ * Fügt eine Liste von Usern zu einer Gruppe hinzu.
+ * Duplikate werden übersprungen, die erzeugten Events werden gespeichert.
+ * Dabei wird das Teilnehmermaximum eventuell angehoben.
+ * Prüft, ob der User Admin ist.
+ *
+ * @param newUsers Userliste
+ * @param group Gruppe
+ * @param exec Ausführender User
+ */
+ public void addUsersToGroup(Group group, String exec, List newUsers) {
+ List users = newUsers.stream().distinct().collect(Collectors.toUnmodifiableList());
+
+ setLimit(group, exec, getAdjustedUserLimit(users, group));
+
+ users.forEach(newUser -> addUserSilent(group, exec, newUser.getId(), newUser));
+ }
+
+ /**
+ * Ermittelt ein passendes Teilnehmermaximum.
+ * Reicht das alte Maximum, wird dieses zurückgegeben.
+ * Ansonsten wird ein erhöhtes Maximum zurückgegeben.
+ *
+ * @param newUsers Neue Teilnehmer
+ * @param group Bestehende Gruppe, welche verändert wird
+ *
+ * @return Das neue Teilnehmermaximum
+ */
+ private static Limit getAdjustedUserLimit(List newUsers, Group group) {
+ return new Limit(Math.max((long) group.size() + newUsers.size(), group.getLimit()));
+ }
+
+ /**
+ * Wechselt die Rolle eines Teilnehmers von Admin zu Member oder andersherum.
+ * Überprüft, ob der User Mitglied ist und ob er der letzte Admin ist.
+ *
+ * @param target Teilnehmer, welcher geändert wird
+ * @param group Gruppe, in welcher sih der Teilnehmer befindet
+ *
+ * @throws EventException Falls der User nicht gefunden wird
+ */
+ public void toggleMemberRole(Group group, String exec, String target) {
+ ValidationHelper.throwIfNoMember(group, target);
+
+ updateRole(group, exec, target, group.getRole(target).toggle());
+ }
+
+
+ // ################################# SINGLE EVENTS ###########################################
+ // Spezifische Events werden erzeugt, validiert, auf die Gruppe angewandt und gespeichert
+
+
+ /**
+ * Erzeugt eine Gruppe, speichert diese und gibt diese zurück.
+ */
+ private Group createGroup(UUID groupid, String exec, LocalDateTime date) {
+ Event event = new CreateGroupEvent(groupid,
+ exec,
+ date);
+ Group group = Group.EMPTY();
+ applyAndSave(group, event);
+
+ return group;
+ }
+
+ /**
+ * Dasselbe wie addUser(), aber exceptions werden abgefangen und nicht geworfen.
+ */
+ private void addUserSilent(Group group, String exec, String target, User user) {
+ try {
+ addMember(group, exec, target, user);
+ } catch (Exception e) {
+ log.debug("Doppelter User {} wurde nicht zu Gruppe {} hinzugefügt!", user, group);
+ }
+ }
+
+ /**
+ * Erzeugt, speichert ein AddUserEvent und wendet es auf eine Gruppe an.
+ * Prüft, ob der Nutzer schon Mitglied ist und ob Gruppe voll ist.
+ */
+ public void addMember(Group group, String exec, String target, User user) {
+ applyAndSave(group, new AddMemberEvent(group.getId(), exec, target, user));
+ }
+
+ /**
+ * Erzeugt, speichert ein DeleteUserEvent und wendet es auf eine Gruppe an.
+ * Prüft, ob der Nutzer Mitglied ist und ob er der letzte Admin ist.
+ */
+ public void kickMember(Group group, String exec, String target) {
+ applyAndSave(group, new KickMemberEvent(group.getId(), exec, target));
+
+ if (group.isEmpty()) {
+ deleteGroup(group, exec);
+ }
+ }
+
+ /**
+ * Erzeugt, speichert ein DeleteGroupEvent und wendet es auf eine Gruppe an.
+ * Prüft, ob der Nutzer Admin ist.
+ */
+ public void deleteGroup(Group group, String exec) {
+ if (!group.exists()) {
+ return;
+ }
+
+ applyAndSave(group, new DestroyGroupEvent(group.getId(), exec));
+ }
+
+ /**
+ * Erzeugt, speichert ein UpdateTitleEvent und wendet es auf eine Gruppe an.
+ * Prüft, ob der Nutzer Admin ist und ob der Titel valide ist.
+ * Bei keiner Änderung wird nichts erzeugt.
+ */
+ public void setTitle(Group group, String exec, @Valid Title title) {
+ if (group.getTitle().equals(title.getValue())) {
+ return;
+ }
+
+ applyAndSave(group, new SetTitleEvent(group.getId(), exec, title));
+ }
+
+ /**
+ * Erzeugt, speichert ein UpdateDescriptiopnEvent und wendet es auf eine Gruppe an.
+ * Prüft, ob der Nutzer Admin ist und ob die Beschreibung valide ist.
+ * Bei keiner Änderung wird nichts erzeugt.
+ */
+ public void setDescription(Group group, String exec, @Valid Description description) {
+ if (group.getDescription().equals(description.getValue())) {
+ return;
+ }
+
+ applyAndSave(group, new SetDescriptionEvent(group.getId(), exec, description));
+ }
+
+ /**
+ * Erzeugt, speichert ein UpdateRoleEvent und wendet es auf eine Gruppe an.
+ * Prüft, ob der Nutzer Mitglied ist.
+ * Bei keiner Änderung wird nichts erzeugt.
+ */
+ private void updateRole(Group group, String exec, String target, Role role) {
+ if (group.memberHasRole(target, role)) {
+ return;
+ }
+
+ applyAndSave(group, new UpdateRoleEvent(group.getId(), exec, target, role));
+ }
+
+ /**
+ * Erzeugt, speichert ein UpdateUserLimitEvent und wendet es auf eine Gruppe an.
+ * Prüft, ob der Nutzer Admin ist und ob das Limit valide ist.
+ * Bei keiner Änderung wird nichts erzeugt.
+ */
+ public void setLimit(Group group, String exec, @Valid Limit userLimit) {
+ if (userLimit.getValue() == group.getLimit()) {
+ return;
+ }
+
+ applyAndSave(group, new SetLimitEvent(group.getId(), exec, userLimit));
+ }
+
+ public void setParent(Group group, String exec, Parent parent) {
+ if (parent.getValue() == group.getParent()) {
+ return;
+ }
+
+ applyAndSave(group, new SetParentEvent(group.getId(), exec, parent));
+ }
+
+ //TODO: UI Link regenerieren button
+ public void setLink(Group group, String exec, @Valid Link link) {
+ if (group.getLink().equals(link.getValue())) {
+ return;
+ }
+
+ applyAndSave(group, new SetInviteLinkEvent(group.getId(), exec, link));
+ }
+
+ private void setType(Group group, String exec, Type type) {
+ if (group.getType() == type) {
+ return;
+ }
+
+ applyAndSave(group, new SetTypeEvent(group.getId(), exec, type));
+ }
+
+ private void applyAndSave(Group group, Event event) throws EventException {
+ event.init(group.version() + 1);
+ event.apply(group, groupCache);
+
+ eventStoreService.saveEvent(event);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/SearchService.java b/src/main/java/mops/gruppen2/domain/service/SearchService.java
new file mode 100644
index 0000000..06b65f3
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/SearchService.java
@@ -0,0 +1,68 @@
+package mops.gruppen2.domain.service;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.EventException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@RequiredArgsConstructor
+@Log4j2
+public class SearchService {
+
+ private final GroupCache groupCache;
+
+ /**
+ * Filtert alle öffentliche Gruppen nach dem Suchbegriff und gibt diese als sortierte Liste zurück.
+ * Groß- und Kleinschreibung wird nicht beachtet.
+ * Der Suchbegriff wird im Gruppentitel und in der Beschreibung gesucht.
+ *
+ * @param search Der Suchstring
+ *
+ * @return Liste von projizierten Gruppen
+ *
+ * @throws EventException Projektionsfehler
+ */
+ public List searchString(String search, String principal) {
+ List groups = new ArrayList<>();
+ groups.addAll(groupCache.publics());
+ groups.addAll(groupCache.lectures());
+ groups = removeUserGroups(groups, principal);
+
+ if (search.isEmpty()) {
+ return groups;
+ }
+
+ log.debug("Es wurde gesucht nach: {}", search);
+ return groups.stream()
+ .filter(group -> group.format().toLowerCase().contains(search.toLowerCase()))
+ .collect(Collectors.toList());
+ }
+
+ public List searchType(Type type, String principal) {
+ log.debug("Es wurde gesucht nach: {}", type);
+
+ if (type == Type.LECTURE) {
+ return removeUserGroups(groupCache.lectures(), principal);
+ }
+ if (type == Type.PUBLIC) {
+ return removeUserGroups(groupCache.publics(), principal);
+ }
+
+ return Collections.emptyList();
+ }
+
+ private static List removeUserGroups(List groups, String principal) {
+ return groups.stream()
+ .filter(group -> !group.isMember(principal))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/helper/APIHelper.java b/src/main/java/mops/gruppen2/domain/service/helper/APIHelper.java
new file mode 100644
index 0000000..7f1d283
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/helper/APIHelper.java
@@ -0,0 +1,26 @@
+package mops.gruppen2.domain.service.helper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.infrastructure.api.GroupRequestWrapper;
+import mops.gruppen2.infrastructure.api.GroupWrapper;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Log4j2
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class APIHelper {
+
+ public static GroupRequestWrapper wrap(long status, List groupList) {
+ return new GroupRequestWrapper(status, wrap(groupList));
+ }
+
+ public static List wrap(List groups) {
+ return groups.stream()
+ .map(GroupWrapper::new)
+ .collect(Collectors.toUnmodifiableList());
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/helper/CommonHelper.java b/src/main/java/mops/gruppen2/domain/service/helper/CommonHelper.java
new file mode 100644
index 0000000..25a8575
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/helper/CommonHelper.java
@@ -0,0 +1,24 @@
+package mops.gruppen2.domain.service.helper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Log4j2
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class CommonHelper {
+
+ public static boolean uuidIsEmpty(UUID uuid) {
+ return "00000000-0000-0000-0000-000000000000".equals(uuid.toString());
+ }
+
+ public static List stringsToUUID(List changedGroupIds) {
+ return changedGroupIds.stream()
+ .map(UUID::fromString)
+ .collect(Collectors.toUnmodifiableList());
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/helper/FileHelper.java b/src/main/java/mops/gruppen2/domain/service/helper/FileHelper.java
new file mode 100644
index 0000000..78857a6
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/helper/FileHelper.java
@@ -0,0 +1,148 @@
+package mops.gruppen2.domain.service.helper;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.event.Event;
+import mops.gruppen2.domain.exception.EventException;
+import mops.gruppen2.domain.exception.GroupNotFoundException;
+import mops.gruppen2.domain.exception.WrongFileException;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.persistance.dto.EventDTO;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Log4j2
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class FileHelper {
+
+ // ######################################## CSV #############################################
+
+
+ public static List readCsvFile(MultipartFile file) throws EventException {
+ if (file == null || file.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ try {
+ List userList = readCsv(file.getInputStream());
+ return userList.stream()
+ .distinct()
+ .collect(Collectors.toList()); //filter duplicates from list
+ } catch (IOException e) {
+ log.error("File konnte nicht gelesen werden!", e);
+ throw new WrongFileException(file.getOriginalFilename());
+ }
+ }
+
+ private static List readCsv(InputStream stream) throws IOException {
+ CsvMapper mapper = new CsvMapper();
+
+ CsvSchema schema = mapper.schemaFor(User.class).withHeader().withColumnReordering(true);
+ ObjectReader reader = mapper.readerFor(User.class).with(schema);
+
+ return reader.readValues(stream).readAll();
+ }
+
+ public static String writeCsvUserList(List members) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("id,givenname,familyname,email\n");
+
+ members.forEach(user -> builder.append(user.getId())
+ .append(",")
+ .append(user.getGivenname())
+ .append(",")
+ .append(user.getFamilyname())
+ .append(",")
+ .append(user.getEmail())
+ .append("\n"));
+
+ return builder.toString();
+ }
+
+
+ // ########################################## JSON ###########################################
+
+
+ /**
+ * Übersetzt eine Java-Event-Repräsentation zu einem JSON-Event-Payload.
+ *
+ * @param event Java-Event-Repräsentation
+ *
+ * @return JSON-Event-Payload als String
+ *
+ * @throws JsonProcessingException Bei JSON Fehler
+ */
+
+ public static String serializeEventJson(Event event) throws JsonProcessingException {
+ ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
+ String payload = mapper.writeValueAsString(event);
+ log.trace(payload);
+ return payload;
+ }
+
+ /**
+ * Übersetzt eine JSON-Event-Payload zu einer Java-Event-Repräsentation.
+ *
+ * @param json JSON-Event-Payload als String
+ *
+ * @return Java-Event-Repräsentation
+ *
+ * @throws JsonProcessingException Bei JSON Fehler
+ */
+ public static Event deserializeEventJson(String json) throws JsonProcessingException {
+ ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
+ Event event = mapper.readValue(json, Event.class);
+ log.trace(event);
+ return event;
+ }
+
+
+ // ############################################### TXT #######################################
+
+
+ public static String payloadsToPlain(List payloads) {
+ return payloads.stream()
+ .map(payload -> payload + "\n")
+ .reduce((String payloadA, String payloadB) -> payloadA + payloadB)
+ .orElseThrow(() -> new GroupNotFoundException("Keine Payloads gefunden."));
+ }
+
+ public static String eventDTOsToSql(List dtos) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("INSERT INTO event(group_id, group_version, exec_id, target_id, event_date, event_payload)\nVALUES\n");
+
+ dtos.forEach(dto -> builder.append("('")
+ .append(dto.getGroup_id())
+ .append("','")
+ .append(dto.getGroup_version())
+ .append("','")
+ .append(dto.getExec_id())
+ .append("','")
+ .append(dto.getTarget_id())
+ .append("','")
+ .append(dto.getEvent_date())
+ .append("','")
+ .append(dto.getEvent_payload())
+ .append("'),\n"));
+
+ builder.replace(builder.length() - 2, builder.length(), ";");
+
+ return builder.toString();
+ }
+
+
+ // ############################################### SQL #######################################
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/helper/ProjectionHelper.java b/src/main/java/mops/gruppen2/domain/service/helper/ProjectionHelper.java
new file mode 100644
index 0000000..2e686e9
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/helper/ProjectionHelper.java
@@ -0,0 +1,67 @@
+package mops.gruppen2.domain.service.helper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.event.Event;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Liefert verschiedene Projektionen auf Gruppen.
+ * Benötigt ausschließlich den EventStoreService.
+ */
+@Log4j2
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ProjectionHelper {
+
+ public static List project(List events) {
+ Map groups = new HashMap<>();
+
+ if (events.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ log.trace(groups);
+ log.trace(events);
+
+ events.forEach(event -> event.apply(getOrCreateGroup(groups, event.getGroupid())));
+
+ return new ArrayList<>(groups.values());
+ }
+
+ public static void project(Map groups, List events, GroupCache cache) {
+ if (events.isEmpty()) {
+ return;
+ }
+
+ log.trace(groups);
+ log.trace(events);
+
+ events.forEach(event -> event.apply(getOrCreateGroup(groups, event.getGroupid()), cache));
+ }
+
+ /**
+ * Gibt die Gruppe mit der richtigen Id aus der übergebenen Map wieder, existiert diese nicht
+ * wird die Gruppe erstellt und der Map hizugefügt.
+ *
+ * @param groups Map aus GruppenIds und Gruppen
+ * @param groupId Die Id der Gruppe, die zurückgegeben werden soll
+ *
+ * @return Die gesuchte Gruppe
+ */
+ private static Group getOrCreateGroup(Map groups, UUID groupId) {
+ if (!groups.containsKey(groupId)) {
+ groups.put(groupId, Group.EMPTY());
+ }
+
+ return groups.get(groupId);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/helper/SortHelper.java b/src/main/java/mops/gruppen2/domain/service/helper/SortHelper.java
new file mode 100644
index 0000000..2f7583f
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/helper/SortHelper.java
@@ -0,0 +1,27 @@
+package mops.gruppen2.domain.service.helper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import mops.gruppen2.domain.model.group.Membership;
+import mops.gruppen2.domain.model.group.Role;
+
+import java.util.List;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class SortHelper {
+
+ public static List sortByMemberRole(List memberships) {
+ memberships.sort((Membership m1, Membership m2) -> {
+ if (m1.getRole() == Role.ADMIN) {
+ return -1;
+ }
+ if (m2.getRole() == Role.ADMIN) {
+ return 1;
+ }
+
+ return 0;
+ });
+
+ return memberships;
+ }
+}
diff --git a/src/main/java/mops/gruppen2/domain/service/helper/ValidationHelper.java b/src/main/java/mops/gruppen2/domain/service/helper/ValidationHelper.java
new file mode 100644
index 0000000..c82fff4
--- /dev/null
+++ b/src/main/java/mops/gruppen2/domain/service/helper/ValidationHelper.java
@@ -0,0 +1,84 @@
+package mops.gruppen2.domain.service.helper;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.exception.GroupFullException;
+import mops.gruppen2.domain.exception.LastAdminException;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.exception.UserExistsException;
+import mops.gruppen2.domain.exception.UserNotFoundException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
+
+@Log4j2
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ValidationHelper {
+
+ public static boolean checkIfLastMember(Group group, String userid) {
+ return group.isMember(userid) && group.size() == 1;
+ }
+
+ /**
+ * Überprüft, ob ein User in einer Gruppe Admin ist.
+ */
+ public static boolean checkIfAdmin(Group group, String userid) {
+ if (group.isMember(userid)) {
+ return group.isAdmin(userid);
+ }
+ return false;
+ }
+
+ public static boolean checkIfLastAdmin(Group group, String userid) {
+ return checkIfAdmin(group, userid) && group.getAdmins().size() == 1;
+ }
+
+
+ // ######################################## THROW ############################################
+
+
+ public static void throwIfMember(Group group, String userid) throws UserExistsException {
+ if (group.isMember(userid)) {
+ log.error("Benutzer {} ist schon in Gruppe {}", userid, group);
+ throw new UserExistsException(userid);
+ }
+ }
+
+ public static void throwIfNoMember(Group group, String userid) throws UserNotFoundException {
+ if (!group.isMember(userid)) {
+ log.error("Benutzer {} ist nicht in Gruppe {}!", userid, group);
+ throw new UserNotFoundException(userid);
+ }
+ }
+
+ public static void throwIfNoAdmin(Group group, String userid) throws NoAccessException {
+ if (!checkIfAdmin(group, userid)) {
+ log.error("User {} ist kein Admin in Gruppe {}!", userid, group);
+ throw new NoAccessException(group.getId().toString());
+ }
+ }
+
+ /**
+ * Schmeißt keine Exception, wenn der User der letzte User ist.
+ */
+ public static void throwIfLastAdmin(Group group, String userid) throws LastAdminException {
+ if (!checkIfLastMember(group, userid) && checkIfLastAdmin(group, userid)) {
+ throw new LastAdminException("Du bist letzter Admin!");
+ }
+ }
+
+ public static void throwIfGroupFull(Group group) throws GroupFullException {
+ if (group.isFull()) {
+ log.error("Die Gruppe {} ist voll!", group);
+ throw new GroupFullException(group.getId().toString());
+ }
+ }
+
+ public static void validateCreateForm(KeycloakAuthenticationToken token, Type type) {
+ if (!token.getAccount().getRoles().contains("orga") && type == Type.LECTURE) {
+ throw new BadArgumentException("Nur Orga kann Veranstaltungen erstellen.");
+ }
+ }
+}
diff --git a/src/main/java/mops/gruppen2/infrastructure/ApplicationInit.java b/src/main/java/mops/gruppen2/infrastructure/ApplicationInit.java
new file mode 100644
index 0000000..4c91b4e
--- /dev/null
+++ b/src/main/java/mops/gruppen2/infrastructure/ApplicationInit.java
@@ -0,0 +1,18 @@
+package mops.gruppen2.infrastructure;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+@RequiredArgsConstructor
+@Component
+public class ApplicationInit {
+
+ private final GroupCache groupCache;
+
+ @EventListener(ApplicationReadyEvent.class)
+ public void init() {
+ groupCache.init();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/infrastructure/GroupCache.java b/src/main/java/mops/gruppen2/infrastructure/GroupCache.java
new file mode 100644
index 0000000..9dc33de
--- /dev/null
+++ b/src/main/java/mops/gruppen2/infrastructure/GroupCache.java
@@ -0,0 +1,208 @@
+package mops.gruppen2.infrastructure;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.domain.exception.GroupNotFoundException;
+import mops.gruppen2.domain.exception.IdMismatchException;
+import mops.gruppen2.domain.exception.UserNotFoundException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.domain.service.helper.ProjectionHelper;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * Cached alle existierenden Gruppen und einige Beziehungen.
+ * Gruppen können nach Typ angefragt werden, nach ID, nach Link oder nach User.
+ * Der Cache wird von den Events aktualisiert.
+ * Beim Aufruf der init() Methode werden alle bisherigen Events projiziert und die Gruppen gespeichert.
+ * Die Komplette Anwendung verwendet eine Instanz des Caches.
+ */
+@Log4j2
+@RequiredArgsConstructor
+@Component
+@Scope("singleton")
+public class GroupCache {
+
+ private final EventStoreService eventStoreService;
+
+ private final Map groups = new HashMap<>();
+ private final Map links = new HashMap<>();
+ private final Map> users = new HashMap<>(); // Wird vielleicht zu groß?
+ private final Map> types = new EnumMap<>(Type.class);
+
+
+ // ######################################## CACHE ###########################################
+
+
+ void init() {
+ ProjectionHelper.project(groups, eventStoreService.findAllEvents(), this);
+ }
+
+
+ // ########################################### GETTERS #######################################
+
+
+ public Group group(UUID groupid) {
+ if (!groups.containsKey(groupid)) {
+ throw new GroupNotFoundException("Gruppe ist nicht im Cache.");
+ }
+
+ return groups.get(groupid);
+ }
+
+ public Group group(String link) {
+ if (!links.containsKey(link)) {
+ throw new GroupNotFoundException("Link ist nicht im Cache.");
+ }
+
+ return links.get(link);
+ }
+
+ public List groups() {
+ if (groups.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ return List.copyOf(groups.values());
+ }
+
+ public List userGroups(String userid) {
+ if (!users.containsKey(userid)) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(users.get(userid));
+ }
+
+ public List userLectures(String userid) {
+ return userGroups(userid).stream()
+ .filter(Group::isLecture)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ public List userPublics(String userid) {
+ return userGroups(userid).stream()
+ .filter(Group::isPublic)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ public List userPrivates(String userid) {
+ return userGroups(userid).stream()
+ .filter(Group::isPrivate)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ public List publics() {
+ if (!types.containsKey(Type.PUBLIC)) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(types.get(Type.PUBLIC));
+ }
+
+ public List privates() {
+ if (!types.containsKey(Type.PRIVATE)) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(types.get(Type.PRIVATE));
+ }
+
+ public List lectures() {
+ if (!types.containsKey(Type.LECTURE)) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(types.get(Type.LECTURE));
+ }
+
+
+ // ######################################## SETTERS ##########################################
+
+
+ public void usersPut(String userid, Group group) {
+ if (!group.isMember(userid)) {
+ throw new UserNotFoundException("User ist kein Mitglied, Gruppe nicht gecached.");
+ }
+ if (!users.containsKey(userid)) {
+ users.put(userid, new ArrayList<>());
+ log.debug("Ein User wurde dem Cache hinzugefügt.");
+ }
+
+ users.get(userid).add(group);
+ }
+
+ public void usersRemove(String target, Group group) {
+ if (!users.containsKey(target)) {
+ return;
+ }
+
+ users.get(target).remove(group);
+ }
+
+ public void groupsPut(UUID groupid, Group group) {
+ if (group.getId() != groupid) {
+ throw new IdMismatchException("ID passt nicht zu Gruppe, Gruppe nicht gecached.");
+ }
+
+ groups.put(groupid, group);
+ }
+
+ public void groupsRemove(UUID groupid, Group group) {
+ if (!groups.containsKey(groupid)) {
+ return;
+ }
+
+ groups.remove(groupid);
+ links.remove(group.getLink());
+ group.getMembers().forEach(user -> users.get(user.getId()).removeIf(usergroup -> !usergroup.exists()));
+ types.get(group.getType()).removeIf(typegroup -> !typegroup.exists());
+ }
+
+ public void linksPut(String link, Group group) {
+ if (!link.equals(group.getLink())) {
+ throw new IdMismatchException("Link passt nicht zu Gruppe, Gruppe nicht gecached.");
+ }
+
+ links.put(link, group);
+ }
+
+ public void linksRemove(String link) {
+ if (!links.containsKey(link)) {
+ return;
+ }
+
+ links.remove(link);
+ }
+
+ public void typesPut(Type type, Group group) {
+ if (!types.containsKey(type)) {
+ types.put(type, new ArrayList<>());
+ log.debug("Ein Typ wurde dem Cache hinzugefügt.");
+ }
+ if (group.getType() != type) {
+ throw new IdMismatchException("Typ passt nicht zu Gruppe, Gruppe nicht gecached.");
+ }
+
+ types.get(type).add(group);
+ }
+
+ public void typesRemove(Type type, Group group) {
+ if (!types.containsKey(type)) {
+ return;
+ }
+
+ types.get(type).remove(group);
+ }
+}
diff --git a/src/main/java/mops/gruppen2/infrastructure/ModelAttributeControllerAdvice.java b/src/main/java/mops/gruppen2/infrastructure/ModelAttributeControllerAdvice.java
new file mode 100644
index 0000000..5ebfa79
--- /dev/null
+++ b/src/main/java/mops/gruppen2/infrastructure/ModelAttributeControllerAdvice.java
@@ -0,0 +1,36 @@
+package mops.gruppen2.infrastructure;
+
+import lombok.RequiredArgsConstructor;
+import mops.gruppen2.domain.Account;
+import mops.gruppen2.domain.model.group.Role;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.model.group.User;
+import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ModelAttribute;
+
+@RequiredArgsConstructor
+@ControllerAdvice
+public class ModelAttributeControllerAdvice {
+
+ // Add modelAttributes before each @RequestMapping
+ @ModelAttribute
+ public void modelAttributes(KeycloakAuthenticationToken token,
+ Model model) {
+
+ // Prevent NullPointerException if not logged in
+ if (token != null) {
+ model.addAttribute("account", new Account(token));
+ model.addAttribute("principal", new User(token));
+ }
+
+ // Add enums
+ model.addAttribute("REGULAR", Role.REGULAR);
+ model.addAttribute("ADMIN", Role.ADMIN);
+ model.addAttribute("PUBLIC", Type.PUBLIC);
+ model.addAttribute("PRIVATE", Type.PRIVATE);
+ model.addAttribute("LECTURE", Type.LECTURE);
+ }
+
+}
diff --git a/src/main/java/mops/gruppen2/domain/api/GroupRequestWrapper.java b/src/main/java/mops/gruppen2/infrastructure/api/GroupRequestWrapper.java
similarity index 61%
rename from src/main/java/mops/gruppen2/domain/api/GroupRequestWrapper.java
rename to src/main/java/mops/gruppen2/infrastructure/api/GroupRequestWrapper.java
index b56589c..d2d059d 100644
--- a/src/main/java/mops/gruppen2/domain/api/GroupRequestWrapper.java
+++ b/src/main/java/mops/gruppen2/infrastructure/api/GroupRequestWrapper.java
@@ -1,18 +1,17 @@
-package mops.gruppen2.domain.api;
+package mops.gruppen2.infrastructure.api;
import lombok.AllArgsConstructor;
import lombok.Getter;
-import mops.gruppen2.domain.Group;
import java.util.List;
/**
* Kombiniert den Status und die Gruppenliste zur ausgabe über die API.
*/
-@AllArgsConstructor
@Getter
+@AllArgsConstructor
public class GroupRequestWrapper {
- private final Long status;
- private final List groupList;
+ private final long version;
+ private final List groups;
}
diff --git a/src/main/java/mops/gruppen2/infrastructure/api/GroupWrapper.java b/src/main/java/mops/gruppen2/infrastructure/api/GroupWrapper.java
new file mode 100644
index 0000000..75b628d
--- /dev/null
+++ b/src/main/java/mops/gruppen2/infrastructure/api/GroupWrapper.java
@@ -0,0 +1,31 @@
+package mops.gruppen2.infrastructure.api;
+
+import lombok.Value;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.model.group.User;
+
+import java.util.List;
+import java.util.UUID;
+
+@Value
+public class GroupWrapper {
+
+ UUID groupid;
+ Type type;
+ UUID parent;
+ String title;
+ String description;
+ List admins;
+ List regulars;
+
+ public GroupWrapper(Group group) {
+ groupid = group.getId();
+ type = group.getType();
+ parent = group.getParent();
+ title = group.getTitle();
+ description = group.getDescription();
+ admins = group.getAdmins();
+ regulars = group.getRegulars();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/infrastructure/controller/APIController.java b/src/main/java/mops/gruppen2/infrastructure/controller/APIController.java
new file mode 100644
index 0000000..1c79bd2
--- /dev/null
+++ b/src/main/java/mops/gruppen2/infrastructure/controller/APIController.java
@@ -0,0 +1,83 @@
+package mops.gruppen2.infrastructure.controller;
+
+
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.aspect.annotation.TraceMethodCalls;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.domain.service.helper.APIHelper;
+import mops.gruppen2.domain.service.helper.ProjectionHelper;
+import mops.gruppen2.infrastructure.GroupCache;
+import mops.gruppen2.infrastructure.api.GroupRequestWrapper;
+import org.springframework.security.access.annotation.Secured;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * Api zum Datenabgleich.
+ */
+@Log4j2
+@TraceMethodCalls
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/gruppen2/api")
+public class APIController {
+
+ private final GroupCache cache;
+ private final EventStoreService eventStoreService;
+
+ /**
+ * Erzeugt eine Liste aus Gruppen, welche sich seit einer übergebenen Event-Id geändert haben.
+ * Die Gruppen werden vollständig projiziert, enthalten also alle Informationen zum entsprechenden Zeitpunkt.
+ *
+ * @param eventId Die Event-ID, welche der Anfragesteller beim letzten Aufruf erhalten hat
+ */
+ //TODO: sollte den cache benutzen, am besten wäre eine groupversion, welche der eventid
+ //TODO: entspricht, dann kann man leicht alle geänderten gruppen finden
+ @GetMapping("/update/{id}")
+ @Secured("ROLE_api_user")
+ @ApiOperation("Gibt veränderte Gruppen zurück")
+ public GroupRequestWrapper getApiUpdate(@ApiParam("Letzte gespeicherte EventId des Anfragestellers")
+ @PathVariable("id") long eventId) {
+
+ return APIHelper.wrap(eventStoreService.findMaxEventId(),
+ ProjectionHelper.project(eventStoreService.findGroupEvents(eventStoreService.findChangedGroups(eventId))));
+ }
+
+ /**
+ * Gibt die Gruppen-IDs von Gruppen, in welchen der übergebene Nutzer teilnimmt, zurück.
+ */
+ @GetMapping("/usergroups/{id}")
+ @Secured("ROLE_api_user")
+ @ApiOperation("Gibt Gruppen zurück, in welchen ein Nutzer teilnimmt")
+ public List getApiUserGroups(@ApiParam("Nutzer-Id")
+ @PathVariable("id") String userId) {
+
+ return cache.userGroups(userId).stream()
+ .map(Group::getId)
+ .map(UUID::toString)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ /**
+ * Konstruiert eine einzelne, vollständige Gruppe.
+ */
+ @GetMapping("/group/{id}")
+ @Secured("ROLE_api_user")
+ @ApiOperation("Gibt die Gruppe mit der als Parameter mitgegebenden groupId zurück")
+ public Group getApiGroup(@ApiParam("Gruppen-Id der gefordeten Gruppe")
+ @PathVariable("id") String groupId) {
+
+ return cache.group(UUID.fromString(groupId));
+ }
+
+}
diff --git a/src/main/java/mops/gruppen2/infrastructure/controller/GroupCreationController.java b/src/main/java/mops/gruppen2/infrastructure/controller/GroupCreationController.java
new file mode 100644
index 0000000..60cb879
--- /dev/null
+++ b/src/main/java/mops/gruppen2/infrastructure/controller/GroupCreationController.java
@@ -0,0 +1,75 @@
+package mops.gruppen2.infrastructure.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.aspect.annotation.TraceMethodCalls;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.domain.model.group.wrapper.Description;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.domain.model.group.wrapper.Parent;
+import mops.gruppen2.domain.model.group.wrapper.Title;
+import mops.gruppen2.domain.service.GroupService;
+import mops.gruppen2.domain.service.helper.FileHelper;
+import mops.gruppen2.domain.service.helper.ValidationHelper;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+
+@SuppressWarnings("SameReturnValue")
+@Log4j2
+@TraceMethodCalls
+@RequiredArgsConstructor
+@Controller
+@RequestMapping("/gruppen2")
+public class GroupCreationController {
+
+ private final GroupCache groupCache;
+ private final GroupService groupService;
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping("/create")
+ public String getCreate(Model model) {
+
+ model.addAttribute("lectures", groupCache.lectures());
+
+ return "create";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/create")
+ public String postCreateOrga(KeycloakAuthenticationToken token,
+ @RequestParam("type") Type type,
+ @RequestParam("parent") @Valid Parent parent,
+ @RequestParam("title") @Valid Title title,
+ @RequestParam("description") @Valid Description description,
+ @RequestParam("limit") @Valid Limit limit,
+ @RequestParam(value = "file", required = false) MultipartFile file) {
+
+ // Zusätzlicher check: studentin kann keine lecture erstellen
+ ValidationHelper.validateCreateForm(token, type);
+
+ String principal = token.getName();
+ Group group = groupService.createGroup(principal);
+ groupService.initGroupMembers(group, principal, principal, new User(token), limit);
+ groupService.initGroupMeta(group, principal, type, parent);
+ groupService.initGroupText(group, principal, title, description);
+
+ // ROLE_studentin kann kein CSV importieren
+ if (token.getAccount().getRoles().contains("orga")) {
+ groupService.addUsersToGroup(group, principal, FileHelper.readCsvFile(file));
+ }
+
+ return "redirect:/gruppen2/details/" + group.getId();
+ }
+}
diff --git a/src/main/java/mops/gruppen2/infrastructure/controller/GroupDetailsController.java b/src/main/java/mops/gruppen2/infrastructure/controller/GroupDetailsController.java
new file mode 100644
index 0000000..a75abf6
--- /dev/null
+++ b/src/main/java/mops/gruppen2/infrastructure/controller/GroupDetailsController.java
@@ -0,0 +1,296 @@
+package mops.gruppen2.infrastructure.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.aspect.annotation.TraceMethodCalls;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.domain.model.group.wrapper.Description;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.domain.model.group.wrapper.Title;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.domain.service.GroupService;
+import mops.gruppen2.domain.service.helper.FileHelper;
+import mops.gruppen2.domain.service.helper.ValidationHelper;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.security.RolesAllowed;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.UUID;
+
+@SuppressWarnings("SameReturnValue")
+@Log4j2
+@TraceMethodCalls
+@RequiredArgsConstructor
+@Controller
+@RequestMapping("/gruppen2")
+public class GroupDetailsController {
+
+ private final GroupCache groupCache;
+ private final GroupService groupService;
+ private final EventStoreService eventStoreService;
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping("/details/{id}")
+ public String getDetailsPage(KeycloakAuthenticationToken token,
+ Model model,
+ @PathVariable("id") String groupId) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ // Parent Badge
+ Group parent = Group.EMPTY();
+ if (group.hasParent()) {
+ parent = groupCache.group(group.getParent());
+ }
+
+ model.addAttribute("group", group);
+ model.addAttribute("parent", parent);
+
+ // Detailseite für nicht-Mitglieder
+ if (!group.isMember(principal)) {
+ return "preview";
+ }
+
+ return "details";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/details/{id}/join")
+ public String postDetailsJoin(KeycloakAuthenticationToken token,
+ @PathVariable("id") String groupId) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ if (group.isMember(principal)) {
+ return "redirect:/gruppen2/details/" + groupId;
+ }
+
+ groupService.addMember(group, principal, principal, new User(token));
+
+ return "redirect:/gruppen2/details/" + groupId;
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/details/{id}/leave")
+ public String postDetailsLeave(KeycloakAuthenticationToken token,
+ @PathVariable("id") String groupId) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ groupService.kickMember(group, principal, principal);
+
+ return "redirect:/gruppen2";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping("details/{id}/history")
+ public String getDetailsHistory(KeycloakAuthenticationToken token,
+ Model model,
+ @PathVariable("id") String groupId) {
+
+ model.addAttribute("events",
+ eventStoreService.findGroupEvents(UUID.fromString(groupId)));
+
+ return "log";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping(value = "details/{id}/export/history/plain", produces = "text/plain;charset=UTF-8")
+ public void getDetailsExportHistoryPlain(HttpServletResponse response,
+ @PathVariable("id") String groupId) {
+
+ String filename = "eventlog-" + groupId + ".txt";
+
+ response.setContentType("text/txt;charset=UTF-8");
+ response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
+ "attachment; filename=\"" + filename + "\"");
+
+ try {
+ response.getWriter()
+ .write(FileHelper.payloadsToPlain(
+ eventStoreService.findGroupPayloads(UUID.fromString(groupId))));
+ } catch (IOException e) {
+ log.error("Payloads konnten nicht geschrieben werden.", e);
+ }
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping(value = "details/{id}/export/history/sql", produces = "application/sql;charset=UTF-8")
+ public void getDetailsExportHistorySql(HttpServletResponse response,
+ @PathVariable("id") String groupId) {
+
+ String filename = "data.sql";
+
+ response.setContentType("application/sql;charset=UTF-8");
+ response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
+ "attachment; filename=\"" + filename + "\"");
+
+ try {
+ response.getWriter()
+ .write(FileHelper.eventDTOsToSql(
+ eventStoreService.findGroupDTOs(UUID.fromString(groupId))));
+ } catch (IOException e) {
+ log.error("Payloads konnten nicht geschrieben werden.", e);
+ }
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping(value = "details/{id}/export/members", produces = "text/csv;charset=UTF-8")
+ public void getDetailsExportMembers(HttpServletResponse response,
+ @PathVariable("id") String groupId) {
+
+ String filename = "teilnehmer-" + groupId + ".csv";
+
+ response.setContentType("text/csv;charset=UTF-8");
+ response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
+ "attachment; filename=\"" + filename + "\"");
+
+ try {
+ response.getWriter()
+ .print(FileHelper.writeCsvUserList(groupCache.group(UUID.fromString(groupId)).getMembers()));
+ } catch (IOException e) {
+ log.error("Teilnehmerliste konnte nicht geschrieben werden.", e);
+ }
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping("/details/{id}/edit")
+ public String getDetailsEdit(KeycloakAuthenticationToken token,
+ Model model,
+ HttpServletRequest request,
+ @PathVariable("id") String groupId) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ // Invite Link
+ String actualURL = request.getRequestURL().toString();
+ String serverURL = actualURL.substring(0, actualURL.indexOf("gruppen2/"));
+ String link = serverURL + "gruppen2/join/" + group.getLink();
+
+ ValidationHelper.throwIfNoAdmin(group, principal);
+
+ model.addAttribute("group", group);
+ model.addAttribute("link", link);
+
+ return "edit";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/details/{id}/edit/meta")
+ public String postDetailsEditMeta(KeycloakAuthenticationToken token,
+ @PathVariable("id") String groupId,
+ @Valid Title title,
+ @Valid Description description) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ groupService.setTitle(group, principal, title);
+ groupService.setDescription(group, principal, description);
+
+ return "redirect:/gruppen2/details/" + groupId + "/edit";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/details/{id}/edit/userlimit")
+ public String postDetailsEditUserLimit(KeycloakAuthenticationToken token,
+ @PathVariable("id") String groupId,
+ @Valid Limit limit) {
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ groupService.setLimit(group, principal, limit);
+
+ return "redirect:/gruppen2/details/" + groupId + "/edit";
+ }
+
+ @RolesAllowed("ROLE_orga")
+ @PostMapping("/details/{id}/edit/csv")
+ public String postDetailsEditCsv(KeycloakAuthenticationToken token,
+ @PathVariable("id") String groupId,
+ @RequestParam(value = "file", required = false) MultipartFile file) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ groupService.addUsersToGroup(group, principal, FileHelper.readCsvFile(file));
+
+ return "redirect:/gruppen2/details/" + groupId + "/edit";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/details/{id}/edit/role/{userid}")
+ public String postDetailsEditRole(KeycloakAuthenticationToken token,
+ @PathVariable("id") String groupId,
+ @PathVariable("userid") String target) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ ValidationHelper.throwIfNoAdmin(group, principal);
+ if (target.equals(principal)) {
+ ValidationHelper.throwIfLastAdmin(group, principal);
+ }
+
+ groupService.toggleMemberRole(group, principal, target);
+
+ // Falls sich der User selbst die Rechte genommen hat
+ if (!ValidationHelper.checkIfAdmin(group, principal)) {
+ return "redirect:/gruppen2/details/" + groupId;
+ }
+
+ return "redirect:/gruppen2/details/" + groupId + "/edit";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/details/{id}/edit/delete/{userid}")
+ public String postDetailsEditDelete(KeycloakAuthenticationToken token,
+ @PathVariable("id") String groupId,
+ @PathVariable("userid") String target) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupId));
+
+ ValidationHelper.throwIfNoAdmin(group, principal);
+
+ // Der eingeloggte User kann sich nicht selbst entfernen (er kann aber verlassen)
+ if (!principal.equals(target)) {
+ groupService.kickMember(group, principal, target);
+ }
+
+ return "redirect:/gruppen2/details/" + groupId + "/edit";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/details/{id}/edit/destroy")
+ public String postDetailsEditDestroy(KeycloakAuthenticationToken token,
+ @PathVariable("id") String groupid) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(UUID.fromString(groupid));
+
+ groupService.deleteGroup(group, principal);
+
+ return "redirect:/gruppen2";
+ }
+
+ //TODO: Method + view for /details/{id}/member/{id}
+}
diff --git a/src/main/java/mops/gruppen2/controller/GruppenfindungController.java b/src/main/java/mops/gruppen2/infrastructure/controller/GruppenfindungController.java
similarity index 55%
rename from src/main/java/mops/gruppen2/controller/GruppenfindungController.java
rename to src/main/java/mops/gruppen2/infrastructure/controller/GruppenfindungController.java
index c1e156a..2e414ba 100644
--- a/src/main/java/mops/gruppen2/controller/GruppenfindungController.java
+++ b/src/main/java/mops/gruppen2/infrastructure/controller/GruppenfindungController.java
@@ -1,10 +1,10 @@
-package mops.gruppen2.controller;
+package mops.gruppen2.infrastructure.controller;
-import mops.gruppen2.domain.Account;
-import mops.gruppen2.domain.User;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.aspect.annotation.TraceMethodCall;
import mops.gruppen2.domain.exception.PageNotFoundException;
-import mops.gruppen2.service.KeyCloakService;
-import mops.gruppen2.service.UserService;
+import mops.gruppen2.infrastructure.GroupCache;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
@@ -14,31 +14,29 @@ import javax.annotation.security.RolesAllowed;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
+@SuppressWarnings("SameReturnValue")
+@Log4j2
+@RequiredArgsConstructor
@Controller
public class GruppenfindungController {
- private final UserService userService;
-
- public GruppenfindungController(UserService userService) {
- this.userService = userService;
- }
+ private final GroupCache groupCache;
+ // For convenience
@GetMapping("")
public String redirect() {
return "redirect:/gruppen2";
}
- @RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
+ @TraceMethodCall
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
@GetMapping("/gruppen2")
- public String index(KeycloakAuthenticationToken token,
- Model model) {
+ public String getIndexPage(KeycloakAuthenticationToken token,
+ Model model) {
- Account account = KeyCloakService.createAccountFromPrincipal(token);
- User user = new User(account);
-
- model.addAttribute("account", account);
- model.addAttribute("gruppen", userService.getUserGroups(user));
- model.addAttribute("user", user);
+ model.addAttribute("lectures", groupCache.userLectures(token.getName()));
+ model.addAttribute("publics", groupCache.userPublics(token.getName()));
+ model.addAttribute("privates", groupCache.userPrivates(token.getName()));
return "index";
}
diff --git a/src/main/java/mops/gruppen2/infrastructure/controller/SearchAndInviteController.java b/src/main/java/mops/gruppen2/infrastructure/controller/SearchAndInviteController.java
new file mode 100644
index 0000000..35ae56c
--- /dev/null
+++ b/src/main/java/mops/gruppen2/infrastructure/controller/SearchAndInviteController.java
@@ -0,0 +1,107 @@
+package mops.gruppen2.infrastructure.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import mops.gruppen2.aspect.annotation.TraceMethodCalls;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.service.SearchService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.annotation.security.RolesAllowed;
+import java.util.Collections;
+import java.util.List;
+
+@SuppressWarnings("SameReturnValue")
+@Log4j2
+@TraceMethodCalls
+@RequiredArgsConstructor
+@Controller
+@RequestMapping("/gruppen2")
+public class SearchAndInviteController {
+
+ private final GroupCache groupCache;
+ private final SearchService searchService;
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping("/search")
+ public String getSearch(Model model) {
+ // Noch keine Suche gestartet: leeres Suchergebnis
+ model.addAttribute("gruppen", Collections.emptyList());
+
+ return "search";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @PostMapping("/search/string")
+ public String postSearchString(KeycloakAuthenticationToken token,
+ Model model,
+ @RequestParam("string") String search) {
+
+ String principal = token.getName();
+ List groups = searchService.searchString(search, principal);
+
+ model.addAttribute("groups", groups);
+
+ return "search";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping("/search/all")
+ public String getSearchAll(KeycloakAuthenticationToken token,
+ Model model) {
+
+ String principal = token.getName();
+ List groups = searchService.searchString("", principal);
+
+ model.addAttribute("groups", groups);
+
+ return "search";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping("/search/type/{type}")
+ public String getSearchType(KeycloakAuthenticationToken token,
+ Model model,
+ @PathVariable("type") Type type) {
+
+ String principal = token.getName();
+ List groups = searchService.searchType(type, principal);
+
+ model.addAttribute("groups", groups);
+
+ return "search";
+ }
+
+ @RolesAllowed({"ROLE_orga", "ROLE_studentin"})
+ @GetMapping("/join/{link}")
+ public String getJoin(KeycloakAuthenticationToken token,
+ Model model,
+ @PathVariable("link") String link) {
+
+ String principal = token.getName();
+ Group group = groupCache.group(link);
+
+ model.addAttribute("group", group);
+
+ // Gruppe öffentlich
+ if (group.getType() == Type.PUBLIC) {
+ return "redirect:/gruppen2/details/" + group.getId();
+ }
+
+ // Bereits Mitglied
+ if (group.isMember(principal)) {
+ return "redirect:/gruppen2/details/" + group.getId();
+ }
+
+ return "link";
+ }
+}
diff --git a/src/main/java/mops/gruppen2/persistance/EventRepository.java b/src/main/java/mops/gruppen2/persistance/EventRepository.java
new file mode 100644
index 0000000..8d21c79
--- /dev/null
+++ b/src/main/java/mops/gruppen2/persistance/EventRepository.java
@@ -0,0 +1,32 @@
+package mops.gruppen2.persistance;
+
+import mops.gruppen2.persistance.dto.EventDTO;
+import org.springframework.data.jdbc.repository.query.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface EventRepository extends CrudRepository {
+
+
+ // ####################################### EVENT DTOs ########################################
+
+
+ @Query("SELECT * FROM event")
+ List findAllEvents();
+
+ @Query("SELECT * FROM event WHERE group_id = :groupid")
+ List findGroupEvents(@Param("groupid") String groupId);
+
+ @Query("SELECT event_payload FROM event WHERE group_id = :groupid")
+ List findGroupPayloads(@Param("groupid") String groupId);
+
+ @Query("SELECT MAX(event_id) FROM event")
+ long findMaxEventId();
+
+ @Query("SELECT DISTINCT group_id FROM event WHERE event_id > :eventid")
+ List findChangedGroupIds(@Param("eventid") long eventid);
+}
diff --git a/src/main/java/mops/gruppen2/domain/dto/EventDTO.java b/src/main/java/mops/gruppen2/persistance/dto/EventDTO.java
similarity index 57%
rename from src/main/java/mops/gruppen2/domain/dto/EventDTO.java
rename to src/main/java/mops/gruppen2/persistance/dto/EventDTO.java
index 817c53b..c46878a 100644
--- a/src/main/java/mops/gruppen2/domain/dto/EventDTO.java
+++ b/src/main/java/mops/gruppen2/persistance/dto/EventDTO.java
@@ -1,19 +1,26 @@
-package mops.gruppen2.domain.dto;
+package mops.gruppen2.persistance.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
+import java.sql.Timestamp;
+
@Table("event")
@Getter
@AllArgsConstructor
public class EventDTO {
@Id
- Long event_id;
+ Long event_id; // Cache-Version
+
String group_id;
- String user_id;
- String event_type;
+ long group_version; // Group-Version
+
+ String exec_id;
+ String target_id;
+
+ Timestamp event_date;
String event_payload;
}
diff --git a/src/main/java/mops/gruppen2/repository/EventRepository.java b/src/main/java/mops/gruppen2/repository/EventRepository.java
deleted file mode 100644
index 775991f..0000000
--- a/src/main/java/mops/gruppen2/repository/EventRepository.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package mops.gruppen2.repository;
-
-import mops.gruppen2.domain.dto.EventDTO;
-import org.springframework.data.jdbc.repository.query.Query;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.data.repository.query.Param;
-import org.springframework.stereotype.Repository;
-
-import java.util.List;
-
-@Repository
-public interface EventRepository extends CrudRepository {
-
- @Query("SELECT distinct group_id FROM event WHERE user_id =:id AND event_type = :type")
- List findGroupIdsWhereUserId(@Param("id") String userId, @Param("type") String type);
-
- @Query("SELECT * from event WHERE group_id =:id")
- List findEventDTOByGroupId(@Param("id") String groupId);
-
- @Query("SELECT DISTINCT group_id FROM event WHERE event_id > :status")
- List findNewEventSinceStatus(@Param("status") Long status);
-
- @Query("SELECT * FROM event WHERE group_id IN (:groupIds) ")
- List findAllEventsOfGroups(@Param("groupIds") List groupIds);
-
- @Query("SELECT MAX(event_id) FROM event")
- Long getHighesEventID();
-
- @Query("SELECT * FROM event WHERE event_type = :type")
- List findAllEventsByType(@Param("type") String type);
-
- @Query("SELECT * FROM event WHERE event_type = :type AND user_id = :userId")
- List findEventsByTypeAndUserId(@Param("type") String type, @Param("userId") String userId);
-
- @Query("SELECT COUNT(*) FROM event WHERE event_type = :type AND group_id = :groupId")
- Long countEventsByTypeAndGroupId(@Param("type") String type, @Param("groupId") String groupId);
-
- @Query("SELECT COUNT(*) FROM event WHERE group_id = :groupId AND user_id = :userId AND event_type = :type")
- Long countEventsByGroupIdAndUserIdAndEventType(@Param("groupId") String groupId, @Param("userId") String userId, @Param("type") String type);
-}
diff --git a/src/main/java/mops/gruppen2/repository/InviteRepository.java b/src/main/java/mops/gruppen2/repository/InviteRepository.java
deleted file mode 100644
index 7899c29..0000000
--- a/src/main/java/mops/gruppen2/repository/InviteRepository.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package mops.gruppen2.repository;
-
-import mops.gruppen2.domain.dto.InviteLinkDTO;
-import org.springframework.data.jdbc.repository.query.Modifying;
-import org.springframework.data.jdbc.repository.query.Query;
-import org.springframework.data.repository.CrudRepository;
-import org.springframework.data.repository.query.Param;
-import org.springframework.stereotype.Repository;
-
-@Repository
-public interface InviteRepository extends CrudRepository {
-
- @Query("SELECT group_id FROM invite WHERE invite_link = :link")
- String findGroupIdByLink(@Param("link") String link);
-
- @Modifying
- @Query("DELETE FROM invite WHERE group_id = :group")
- void deleteLinkOfGroup(@Param("group") String group);
-
- @Query("SELECT invite_link FROM invite WHERE group_id = :group")
- String findLinkByGroupId(@Param("group") String group);
-}
diff --git a/src/main/java/mops/gruppen2/service/APIFormatterService.java b/src/main/java/mops/gruppen2/service/APIFormatterService.java
deleted file mode 100644
index 2985a4f..0000000
--- a/src/main/java/mops/gruppen2/service/APIFormatterService.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.api.GroupRequestWrapper;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-@Service
-public final class APIFormatterService {
-
- private APIFormatterService() {}
-
- public static GroupRequestWrapper wrap(long status, List groupList) {
- return new GroupRequestWrapper(status, groupList);
- }
-}
diff --git a/src/main/java/mops/gruppen2/service/ControllerService.java b/src/main/java/mops/gruppen2/service/ControllerService.java
deleted file mode 100644
index 0d932d3..0000000
--- a/src/main/java/mops/gruppen2/service/ControllerService.java
+++ /dev/null
@@ -1,359 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.domain.Account;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.GroupType;
-import mops.gruppen2.domain.Role;
-import mops.gruppen2.domain.User;
-import mops.gruppen2.domain.Visibility;
-import mops.gruppen2.domain.event.AddUserEvent;
-import mops.gruppen2.domain.event.CreateGroupEvent;
-import mops.gruppen2.domain.event.DeleteGroupEvent;
-import mops.gruppen2.domain.event.DeleteUserEvent;
-import mops.gruppen2.domain.event.UpdateGroupDescriptionEvent;
-import mops.gruppen2.domain.event.UpdateGroupTitleEvent;
-import mops.gruppen2.domain.event.UpdateRoleEvent;
-import mops.gruppen2.domain.event.UpdateUserMaxEvent;
-import mops.gruppen2.domain.exception.EventException;
-import mops.gruppen2.domain.exception.WrongFileException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-import static mops.gruppen2.domain.Role.ADMIN;
-
-
-@Service
-public class ControllerService {
-
- private static final Logger LOG = LoggerFactory.getLogger("controllerServiceLogger");
- private final EventService eventService;
- private final UserService userService;
- private final ValidationService validationService;
- private final InviteService inviteService;
-
- public ControllerService(EventService eventService, UserService userService, ValidationService validationService, InviteService inviteService) {
- this.eventService = eventService;
- this.userService = userService;
- this.validationService = validationService;
- this.inviteService = inviteService;
- }
-
- private static User getVeteranMember(Account account, Group group) {
- List members = group.getMembers();
- String newAdminId;
- if (members.get(0).getId().equals(account.getName())) {
- newAdminId = members.get(1).getId();
- } else {
- newAdminId = members.get(0).getId();
- }
- return new User(newAdminId, "", "", "");
- }
-
- /**
- * Wie createGroup, nur das hier die Gruppe auch als Veranstaltung gesetzt werden kann und CSV Dateien mit Nutzern
- * eingelesen werden können.
- *
- * @param account Der Nutzer der die Gruppe erstellt
- * @param title Parameter für die neue Gruppe
- * @param description Parameter für die neue Gruppe
- * @param isVisibilityPrivate Parameter für die neue Gruppe
- * @param isLecture Parameter für die neue Gruppe
- * @param isMaximumInfinite Parameter für die neue Gruppe
- * @param userMaximum Parameter für die neue Gruppe
- * @param parent Parameter für die neue Gruppe
- * @param file Parameter für die neue Gruppe
- */
- public void createGroupAsOrga(Account account,
- String title,
- String description,
- Boolean isVisibilityPrivate,
- Boolean isLecture,
- Boolean isMaximumInfinite,
- Long userMaximum,
- UUID parent,
- MultipartFile file) {
-
- userMaximum = checkInfiniteUsers(isMaximumInfinite, userMaximum);
-
- List newUsers = readCsvFile(file);
-
- List oldUsers = new ArrayList<>();
- User user = new User(account);
- oldUsers.add(user);
-
- removeOldUsersFromNewUsers(oldUsers, newUsers);
-
- userMaximum = adjustUserMaximum((long) newUsers.size(), 1L, userMaximum);
-
- UUID groupId = createGroup(account,
- title,
- description,
- isVisibilityPrivate,
- isLecture,
- isMaximumInfinite,
- userMaximum, parent);
-
- addUserList(newUsers, groupId);
- }
-
- /**
- * Wenn die maximale Useranzahl unendlich ist, wird das Maximum auf 100000 gesetzt. Praktisch gibt es also Maximla 100000
- * Nutzer pro Gruppe.
- *
- * @param isMaximumInfinite Gibt an ob es unendlich viele User geben soll
- * @param userMaximum Das Maximum an Usern, falls es eins gibt
- *
- * @return Maximum an Usern
- */
- private static Long checkInfiniteUsers(Boolean isMaximumInfinite, Long userMaximum) {
- isMaximumInfinite = isMaximumInfinite != null;
-
- if (isMaximumInfinite) {
- userMaximum = 100_000L;
- }
-
- return userMaximum;
- }
-
- /**
- * Erzeugt eine neue Gruppe, fügt den User, der die Gruppe erstellt hat, hinzu und setzt seine Rolle als Admin fest.
- * Zudem wird der Gruppentitel und die Gruppenbeschreibung erzeugt, welche vorher der Methode übergeben wurden.
- * Aus diesen Event-Objekten wird eine Liste erzeugt, welche daraufhin mithilfe des EventServices gesichert wird.
- *
- * @param account Keycloak-Account
- * @param title Gruppentitel
- * @param description Gruppenbeschreibung
- */
- //TODO: remove booleans
- public UUID createGroup(Account account,
- String title,
- String description,
- Boolean isVisibilityPrivate,
- Boolean isLecture,
- Boolean isMaximumInfinite,
- Long userMaximum,
- UUID parent) {
-
- userMaximum = checkInfiniteUsers(isMaximumInfinite, userMaximum);
-
- Visibility groupVisibility = setGroupVisibility(isVisibilityPrivate);
- UUID groupId = UUID.randomUUID();
-
- GroupType groupType = setGroupType(isLecture);
-
- CreateGroupEvent createGroupEvent = new CreateGroupEvent(groupId,
- account.getName(),
- parent,
- groupType,
- groupVisibility,
- userMaximum);
- eventService.saveEvent(createGroupEvent);
-
- inviteService.createLink(groupId);
-
- User user = new User(account.getName(), "", "", "");
-
- addUser(account, groupId);
- updateTitle(account, groupId, title);
- updateDescription(account, groupId, description);
- updateRole(user, groupId);
-
- return groupId;
- }
-
- private static List readCsvFile(MultipartFile file) throws EventException {
- if (file == null) {
- return new ArrayList<>();
- }
- if (!file.isEmpty()) {
- try {
- List userList = CsvService.read(file.getInputStream());
- return userList.stream().distinct().collect(Collectors.toList()); //filters duplicates from list
- } catch (IOException ex) {
- LOG.warn("File konnte nicht gelesen werden");
- throw new WrongFileException(file.getOriginalFilename());
- }
- }
- return new ArrayList<>();
- }
-
- private static void removeOldUsersFromNewUsers(List oldUsers, List newUsers) {
- for (User oldUser : oldUsers) {
- newUsers.remove(oldUser);
- }
- }
-
- private static Long adjustUserMaximum(Long newUsers, Long oldUsers, Long maxUsers) {
- if (oldUsers + newUsers > maxUsers) {
- maxUsers = oldUsers + newUsers;
- }
- return maxUsers;
- }
-
- private void addUserList(List newUsers, UUID groupId) {
- for (User user : newUsers) {
- Group group = userService.getGroupById(groupId);
- if (group.getMembers().contains(user)) {
- LOG.info("Benutzer {} ist bereits in Gruppe", user.getId());
- } else {
- AddUserEvent addUserEvent = new AddUserEvent(groupId, user.getId(), user.getGivenname(), user.getFamilyname(), user.getEmail());
- eventService.saveEvent(addUserEvent);
- }
- }
- }
-
- private static Visibility setGroupVisibility(Boolean isVisibilityPrivate) {
- isVisibilityPrivate = isVisibilityPrivate != null;
-
- if (isVisibilityPrivate) {
- return Visibility.PRIVATE;
- } else {
- return Visibility.PUBLIC;
- }
- }
-
- private static GroupType setGroupType(Boolean isLecture) {
- isLecture = isLecture != null;
- if (isLecture) {
- return GroupType.LECTURE;
- } else {
- return GroupType.SIMPLE;
- }
- }
-
- public void addUser(Account account, UUID groupId) {
- AddUserEvent addUserEvent = new AddUserEvent(groupId, account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail());
- eventService.saveEvent(addUserEvent);
- }
-
- private void updateTitle(Account account, UUID groupId, String title) {
- UpdateGroupTitleEvent updateGroupTitleEvent = new UpdateGroupTitleEvent(groupId, account.getName(), title);
- eventService.saveEvent(updateGroupTitleEvent);
- }
-
- public void updateRole(User user, UUID groupId) throws EventException {
- UpdateRoleEvent updateRoleEvent;
- Group group = userService.getGroupById(groupId);
- validationService.throwIfNotInGroup(group, user);
-
- if (group.getRoles().get(user.getId()) == ADMIN) {
- updateRoleEvent = new UpdateRoleEvent(group.getId(), user.getId(), Role.MEMBER);
- } else {
- updateRoleEvent = new UpdateRoleEvent(group.getId(), user.getId(), ADMIN);
- }
- eventService.saveEvent(updateRoleEvent);
- }
-
- private void updateDescription(Account account, UUID groupId, String description) {
- UpdateGroupDescriptionEvent updateGroupDescriptionEvent = new UpdateGroupDescriptionEvent(groupId, account.getName(), description);
- eventService.saveEvent(updateGroupDescriptionEvent);
- }
-
- public void addUsersFromCsv(Account account, MultipartFile file, String groupId) {
- Group group = userService.getGroupById(UUID.fromString(groupId));
-
- List newUserList = readCsvFile(file);
- removeOldUsersFromNewUsers(group.getMembers(), newUserList);
-
- UUID groupUUID = getUUID(groupId);
-
- Long newUserMaximum = adjustUserMaximum((long) newUserList.size(), (long) group.getMembers().size(), group.getUserMaximum());
- if (newUserMaximum > group.getUserMaximum()) {
- updateMaxUser(account, groupUUID, newUserMaximum);
- }
-
- addUserList(newUserList, groupUUID);
- }
-
- public UUID getUUID(String id) {
- return UUID.fromString(Objects.requireNonNullElse(id, "00000000-0000-0000-0000-000000000000"));
- }
-
- public void updateMaxUser(Account account, UUID groupId, Long userMaximum) {
- UpdateUserMaxEvent updateUserMaxEvent = new UpdateUserMaxEvent(groupId, account.getName(), userMaximum);
- eventService.saveEvent(updateUserMaxEvent);
- }
-
- public void changeMetaData(Account account, Group group, String title, String description) {
- if (!title.equals(group.getTitle())) {
- updateTitle(account, group.getId(), title);
- }
-
- if (!description.equals(group.getDescription())) {
- updateDescription(account, group.getId(), description);
- }
- }
-
- public Group getParent(UUID parentId) {
- Group parent = new Group();
- if (!idIsEmpty(parentId)) {
- parent = userService.getGroupById(parentId);
- }
- return parent;
- }
-
- public void deleteUser(Account account, User user, Group group) throws EventException {
- changeRoleIfLastAdmin(account, group);
-
- validationService.throwIfNotInGroup(group, user);
-
- deleteUserEvent(user, group.getId());
-
- if (validationService.checkIfGroupEmpty(group.getId())) {
- deleteGroupEvent(user.getId(), group.getId());
- }
- }
-
- private static boolean idIsEmpty(UUID id) {
- if (id == null) {
- return true;
- }
-
- return "00000000-0000-0000-0000-000000000000".equals(id.toString());
- }
-
- private void deleteUserEvent(User user, UUID groupId) {
- DeleteUserEvent deleteUserEvent = new DeleteUserEvent(groupId, user.getId());
- eventService.saveEvent(deleteUserEvent);
- }
-
- public void deleteGroupEvent(String userId, UUID groupId) {
- DeleteGroupEvent deleteGroupEvent = new DeleteGroupEvent(groupId, userId);
- inviteService.destroyLink(groupId);
- eventService.saveEvent(deleteGroupEvent);
- }
-
- private void promoteVeteranMember(Account account, Group group) {
- if (validationService.checkIfLastAdmin(account, group)) {
- User newAdmin = getVeteranMember(account, group);
- updateRole(newAdmin, group.getId());
- }
- }
-
- public void changeRoleIfLastAdmin(Account account, Group group) {
- if (group.getMembers().size() <= 1) {
- return;
- }
- promoteVeteranMember(account, group);
- }
-
- public void changeRole(Account account, User user, Group group) {
- if (user.getId().equals(account.getName())) {
- if (group.getMembers().size() <= 1) {
- validationService.throwIfLastAdmin(account, group);
- }
- promoteVeteranMember(account, group);
- }
- updateRole(user, group.getId());
- }
-
-}
diff --git a/src/main/java/mops/gruppen2/service/CsvService.java b/src/main/java/mops/gruppen2/service/CsvService.java
deleted file mode 100644
index a476481..0000000
--- a/src/main/java/mops/gruppen2/service/CsvService.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package mops.gruppen2.service;
-
-import com.fasterxml.jackson.databind.ObjectReader;
-import com.fasterxml.jackson.dataformat.csv.CsvMapper;
-import com.fasterxml.jackson.dataformat.csv.CsvSchema;
-import mops.gruppen2.domain.User;
-import org.springframework.stereotype.Service;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-
-@Service
-public final class CsvService {
-
- private CsvService() {}
-
- static List read(InputStream stream) throws IOException {
- CsvMapper mapper = new CsvMapper();
-
- CsvSchema schema = mapper.schemaFor(User.class).withHeader().withColumnReordering(true);
- ObjectReader reader = mapper.readerFor(User.class).with(schema);
-
- return reader.readValues(stream).readAll();
- }
-}
diff --git a/src/main/java/mops/gruppen2/service/EventService.java b/src/main/java/mops/gruppen2/service/EventService.java
deleted file mode 100644
index 5226519..0000000
--- a/src/main/java/mops/gruppen2/service/EventService.java
+++ /dev/null
@@ -1,168 +0,0 @@
-package mops.gruppen2.service;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import mops.gruppen2.domain.dto.EventDTO;
-import mops.gruppen2.domain.event.Event;
-import mops.gruppen2.repository.EventRepository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-@Service
-//TODO: Evtl aufsplitten in EventRepoService und EventService?
-public class EventService {
-
- private static final Logger LOG = LoggerFactory.getLogger(EventService.class);
- private final EventRepository eventStore;
-
- public EventService(EventRepository eventStore) {
- this.eventStore = eventStore;
- }
-
- /**
- * Erzeugt ein DTO aus einem Event und speicher es.
- *
- * @param event Event, welches gespeichert wird
- */
- public void saveEvent(Event event) {
- eventStore.save(getDTOFromEvent(event));
- }
-
- public void saveAll(Event... events) {
- for (Event event : events) {
- eventStore.save(getDTOFromEvent(event));
- }
- }
-
- /**
- * Erzeugt aus einem Event Objekt ein EventDTO Objekt.
- *
- * @param event Event, welches in DTO übersetzt wird
- *
- * @return EventDTO (Neues DTO)
- */
- public EventDTO getDTOFromEvent(Event event) {
- String payload = "";
- try {
- payload = JsonService.serializeEvent(event);
- } catch (JsonProcessingException e) {
- LOG.error("Event ({}) konnte nicht serialisiert werden!", event.getClass());
- }
-
- return new EventDTO(null, event.getGroupId().toString(), event.getUserId(), getEventType(event), payload);
- }
-
- /**
- * Gibt den Eventtyp als String wieder.
- *
- * @param event Event dessen Typ abgefragt werden soll
- *
- * @return Der Name des Typs des Events
- */
- private static String getEventType(Event event) {
- int lastDot = event.getClass().getName().lastIndexOf('.');
-
- return event.getClass().getName().substring(lastDot + 1);
- }
-
- /**
- * Speichert alle Events aus der übergebenen Liste in der DB.
- *
- * @param events Liste an Events die gespeichert werden soll
- */
- @SafeVarargs
- public final void saveAll(List... events) {
- for (List eventlist : events) {
- for (Event event : eventlist) {
- eventStore.save(getDTOFromEvent(event));
- }
- }
- }
-
- /**
- * Findet alle Events welche ab dem neuen Status hinzugekommen sind.
- * Sucht alle Events mit event_id > status
- *
- * @param status Die Id des zuletzt gespeicherten Events
- *
- * @return Liste von neueren Events
- */
- public List getNewEvents(Long status) {
- List groupIdsThatChanged = eventStore.findNewEventSinceStatus(status);
-
- List groupEventDTOS = eventStore.findAllEventsOfGroups(groupIdsThatChanged);
- return getEventsFromDTOs(groupEventDTOS);
- }
-
- /**
- * Erzeugt aus einer Liste von eventDTOs eine Liste von Events.
- *
- * @param eventDTOS Liste von DTOs
- *
- * @return Liste von Events
- */
- List getEventsFromDTOs(Iterable eventDTOS) {
- List events = new ArrayList<>();
-
- for (EventDTO eventDTO : eventDTOS) {
- try {
- events.add(JsonService.deserializeEvent(eventDTO.getEvent_payload()));
- } catch (JsonProcessingException e) {
- LOG.error("Payload\n {}\n konnte nicht deserialisiert werden!", eventDTO.getEvent_payload());
- }
- }
- return events;
- }
-
- public long getMaxEventId() {
- long highestEvent = 0;
-
- try {
- highestEvent = eventStore.getHighesEventID();
- } catch (NullPointerException e) {
- LOG.debug("Eine maxId von 0 wurde zurückgegeben, da keine Events vorhanden sind.");
- }
-
- return highestEvent;
- }
-
- /**
- * Gibt eine Liste mit allen Events zurück, die zu der Gruppe gehören.
- *
- * @param groupId Gruppe die betrachtet werden soll
- *
- * @return Liste aus Events
- */
- public List getEventsOfGroup(UUID groupId) {
- List eventDTOList = eventStore.findEventDTOByGroupId(groupId.toString());
- return getEventsFromDTOs(eventDTOList);
- }
-
- /**
- * Gibt eine Liste aus GruppenIds zurück, in denen sich der User befindet.
- *
- * @param userId Die Id des Users
- *
- * @return Liste aus GruppenIds
- */
- public List findGroupIdsByUser(String userId) {
- return eventStore.findGroupIdsWhereUserId(userId, "AddUserEvent").stream().map(UUID::fromString).collect(Collectors.toList());
- }
-
- /**
- * Gibt true zurück, falls der User aktuell in der Gruppe ist, sonst false.
- *
- * @param groupId Id der Gruppe
- * @param userId Id des zu überprüfenden Users
- *
- * @return true or false
- */
- boolean userInGroup(UUID groupId, String userId) {
- return eventStore.countEventsByGroupIdAndUserIdAndEventType(groupId.toString(), userId, "AddUserEvent") > eventStore.countEventsByGroupIdAndUserIdAndEventType(groupId.toString(), userId, "DeleteUserEvent");
- }
-}
diff --git a/src/main/java/mops/gruppen2/service/GroupService.java b/src/main/java/mops/gruppen2/service/GroupService.java
deleted file mode 100644
index 03549ea..0000000
--- a/src/main/java/mops/gruppen2/service/GroupService.java
+++ /dev/null
@@ -1,170 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.domain.Account;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.GroupType;
-import mops.gruppen2.domain.Visibility;
-import mops.gruppen2.domain.dto.EventDTO;
-import mops.gruppen2.domain.event.Event;
-import mops.gruppen2.domain.exception.EventException;
-import mops.gruppen2.repository.EventRepository;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-@Service
-public class GroupService {
-
- private final EventService eventService;
- private final EventRepository eventRepository;
-
- public GroupService(EventService eventService, EventRepository eventRepository) {
- this.eventService = eventService;
- this.eventRepository = eventRepository;
- }
-
- /**
- * Sucht in der DB alle Zeilen raus welche eine der Gruppen_ids hat.
- * Wandelt die Zeilen in Events um und gibt davon eine Liste zurück.
- *
- * @param groupIds Liste an IDs
- *
- * @return Liste an Events
- */
- //TODO: Das vielleicht in den EventRepoService?
- public List getGroupEvents(List groupIds) {
- List eventDTOS = new ArrayList<>();
- for (UUID groupId : groupIds) {
- eventDTOS.addAll(eventRepository.findEventDTOByGroupId(groupId.toString()));
- }
- return eventService.getEventsFromDTOs(eventDTOS);
- }
-
- /**
- * Wird verwendet beim Gruppe erstellen bei der Parent-Auswahl: nur Titel benötigt.
- *
- * @return List of groups
- */
- @Cacheable("groups")
- public List getAllLecturesWithVisibilityPublic() {
- List createEvents = eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("CreateGroupEvent"));
- createEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("DeleteGroupEvent")));
- createEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("UpdateGroupTitleEvent")));
- createEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("DeleteGroupEvent")));
-
- List visibleGroups = projectEventList(createEvents);
-
- return visibleGroups.stream()
- .filter(group -> group.getType() == GroupType.LECTURE)
- .filter(group -> group.getVisibility() == Visibility.PUBLIC)
- .collect(Collectors.toList());
- }
-
- /**
- * Erzeugt eine neue Map wo Gruppen aus den Events erzeugt und den Gruppen_ids zugeordnet werden.
- * Die Gruppen werden als Liste zurückgegeben.
- *
- * @param events Liste an Events
- *
- * @return Liste an Projizierten Gruppen
- *
- * @throws EventException Projektionsfehler
- */
- public List projectEventList(List events) throws EventException {
- Map groupMap = new HashMap<>();
-
- events.parallelStream()
- .forEachOrdered(event -> event.apply(getOrCreateGroup(groupMap, event.getGroupId())));
-
- return new ArrayList<>(groupMap.values());
- }
-
- /**
- * Gibt die Gruppe mit der richtigen Id aus der übergebenen Map wieder, existiert diese nicht
- * wird die Gruppe erstellt und der Map hizugefügt.
- *
- * @param groups Map aus GruppenIds und Gruppen
- * @param groupId Die Id der Gruppe, die zurückgegeben werden soll
- *
- * @return Die gesuchte Gruppe
- */
- private static Group getOrCreateGroup(Map groups, UUID groupId) {
- if (!groups.containsKey(groupId)) {
- groups.put(groupId, new Group());
- }
-
- return groups.get(groupId);
- }
-
- /**
- * Filtert alle öffentliche Gruppen nach dem Suchbegriff und gibt diese als Liste von Gruppen zurück.
- * Groß und Kleinschreibung wird nicht beachtet.
- *
- * @param search Der Suchstring
- *
- * @return Liste von projizierten Gruppen
- *
- * @throws EventException Projektionsfehler
- */
- //Todo Rename
- @Cacheable("groups")
- public List findGroupWith(String search, Account account) throws EventException {
- if (search.isEmpty()) {
- return getAllGroupWithVisibilityPublic(account.getName());
- }
-
- return getAllGroupWithVisibilityPublic(account.getName()).parallelStream().filter(group -> group.getTitle().toLowerCase().contains(search.toLowerCase()) || group.getDescription().toLowerCase().contains(search.toLowerCase())).collect(Collectors.toList());
- }
-
- /**
- * Wird verwendet bei der Suche nach Gruppen: Titel, Beschreibung werden benötigt.
- * Außerdem wird beachtet, ob der eingeloggte User bereits in entsprechenden Gruppen mitglied ist.
- *
- * @return Liste von projizierten Gruppen
- *
- * @throws EventException Projektionsfehler
- */
- //TODO Rename
- @Cacheable("groups")
- public List getAllGroupWithVisibilityPublic(String userId) throws EventException {
- List groupEvents = eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("CreateGroupEvent"));
- groupEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("UpdateGroupDescriptionEvent")));
- groupEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("UpdateGroupTitleEvent")));
- groupEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("DeleteGroupEvent")));
- groupEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("UpdateUserMaxEvent")));
-
- List visibleGroups = projectEventList(groupEvents);
-
- sortByGroupType(visibleGroups);
-
- return visibleGroups.stream()
- .filter(group -> group.getType() != null)
- .filter(group -> !eventService.userInGroup(group.getId(), userId))
- .filter(group -> group.getVisibility() == Visibility.PUBLIC)
- .collect(Collectors.toList());
- }
-
- /**
- * Sortiert die übergebene Liste an Gruppen, sodass Veranstaltungen am Anfang der Liste sind.
- *
- * @param groups Die Liste von Gruppen die sortiert werden soll
- */
- void sortByGroupType(List groups) {
- groups.sort((Group g1, Group g2) -> {
- if (g1.getType() == GroupType.LECTURE) {
- return -1;
- }
- if (g2.getType() == GroupType.LECTURE) {
- return 0;
- }
-
- return 1;
- });
- }
-}
diff --git a/src/main/java/mops/gruppen2/service/InviteService.java b/src/main/java/mops/gruppen2/service/InviteService.java
deleted file mode 100644
index 962dd81..0000000
--- a/src/main/java/mops/gruppen2/service/InviteService.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.domain.dto.InviteLinkDTO;
-import mops.gruppen2.domain.exception.InvalidInviteException;
-import mops.gruppen2.domain.exception.NoInviteExistException;
-import mops.gruppen2.repository.InviteRepository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import java.util.UUID;
-
-@Service
-public class InviteService {
-
- private static final Logger LOG = LoggerFactory.getLogger(InviteService.class);
- private final InviteRepository inviteRepository;
-
- public InviteService(InviteRepository inviteRepository) {
- this.inviteRepository = inviteRepository;
- }
-
- void createLink(UUID groupId) {
- inviteRepository.save(new InviteLinkDTO(null, groupId.toString(), UUID.randomUUID().toString()));
- }
-
- void destroyLink(UUID groupId) {
- inviteRepository.deleteLinkOfGroup(groupId.toString());
- }
-
- public UUID getGroupIdFromLink(String link) {
- try {
- return UUID.fromString(inviteRepository.findGroupIdByLink(link));
- } catch (Exception e) {
- LOG.error("Gruppe zu Link ({}) konnte nicht gefunden werden!", link);
- }
-
- throw new InvalidInviteException(link);
- }
-
- public String getLinkByGroupId(UUID groupId) {
- try {
- return inviteRepository.findLinkByGroupId(groupId.toString());
- } catch (Exception e) {
- LOG.error("Link zu Gruppe ({}) konnte nicht gefunden werden!", groupId);
- }
-
- throw new NoInviteExistException(groupId.toString());
- }
-}
diff --git a/src/main/java/mops/gruppen2/service/JsonService.java b/src/main/java/mops/gruppen2/service/JsonService.java
deleted file mode 100644
index 9f3150b..0000000
--- a/src/main/java/mops/gruppen2/service/JsonService.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package mops.gruppen2.service;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import mops.gruppen2.domain.event.Event;
-import org.springframework.stereotype.Service;
-
-/**
- * Übersetzt JSON-Event-Payloads zu Java-Event-Repräsentationen und zurück.
- */
-@Service
-public final class JsonService {
-
- private JsonService() {}
-
- /**
- * Übersetzt mithilfe der Jackson-Library eine Java-Event-Repräsentation zu einem JSON-Event-Payload.
- *
- * @param event Java-Event-Repräsentation
- *
- * @return JSON-Event-Payload als String
- *
- * @throws JsonProcessingException Bei JSON Fehler
- */
-
- static String serializeEvent(Event event) throws JsonProcessingException {
- ObjectMapper mapper = new ObjectMapper();
- return mapper.writeValueAsString(event);
- }
-
- /**
- * Übersetzt mithilfe der Jackson-Library einen JSON-Event-Payload zu einer Java-Event-Repräsentation.
- *
- * @param json JSON-Event-Payload als String
- *
- * @return Java-Event-Repräsentation
- *
- * @throws JsonProcessingException Bei JSON Fehler
- */
- static Event deserializeEvent(String json) throws JsonProcessingException {
- ObjectMapper mapper = new ObjectMapper();
- return mapper.readValue(json, Event.class);
- }
-}
diff --git a/src/main/java/mops/gruppen2/service/KeyCloakService.java b/src/main/java/mops/gruppen2/service/KeyCloakService.java
deleted file mode 100644
index 3067da1..0000000
--- a/src/main/java/mops/gruppen2/service/KeyCloakService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.domain.Account;
-import org.keycloak.KeycloakPrincipal;
-import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
-import org.springframework.stereotype.Service;
-
-@Service
-public final class KeyCloakService {
-
- private KeyCloakService() {}
-
- /**
- * Creates an Account.
- *
- * @param token Ein toller token
- *
- * @return Account with current userdata
- */
- public static Account createAccountFromPrincipal(KeycloakAuthenticationToken token) {
- KeycloakPrincipal principal = (KeycloakPrincipal) token.getPrincipal();
- return new Account(
- principal.getName(),
- principal.getKeycloakSecurityContext().getIdToken().getEmail(),
- null,
- principal.getKeycloakSecurityContext().getIdToken().getGivenName(),
- principal.getKeycloakSecurityContext().getIdToken().getFamilyName(),
- token.getAccount().getRoles());
- }
-}
diff --git a/src/main/java/mops/gruppen2/service/SearchService.java b/src/main/java/mops/gruppen2/service/SearchService.java
deleted file mode 100644
index 6e94bdf..0000000
--- a/src/main/java/mops/gruppen2/service/SearchService.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package mops.gruppen2.service;
-
-import org.springframework.stereotype.Service;
-
-@Service
-public class SearchService {}
diff --git a/src/main/java/mops/gruppen2/service/UserService.java b/src/main/java/mops/gruppen2/service/UserService.java
deleted file mode 100644
index dd6d65b..0000000
--- a/src/main/java/mops/gruppen2/service/UserService.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.User;
-import mops.gruppen2.domain.event.Event;
-import mops.gruppen2.domain.exception.EventException;
-import mops.gruppen2.domain.exception.GroupNotFoundException;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-@Service
-public class UserService {
-
- private final GroupService groupService;
- private final EventService eventService;
-
- public UserService(GroupService groupService, EventService eventService) {
- this.groupService = groupService;
- this.eventService = eventService;
- }
-
- @Cacheable("groups")
- public List getUserGroups(String userId) throws EventException {
- return getUserGroups(new User(userId, "", "", ""));
- }
-
- /**
- * Gibt eine Liste aus Gruppen zurück, in denen sich der übergebene User befindet.
- *
- * @param user Der User
- *
- * @return Liste aus Gruppen
- */
- //TODO: Nur AddUserEvents + DeleteUserEvents betrachten
- @Cacheable("groups")
- public List getUserGroups(User user) {
- List groupIds = eventService.findGroupIdsByUser(user.getId());
- List events = groupService.getGroupEvents(groupIds);
- List groups = groupService.projectEventList(events);
- List newGroups = new ArrayList<>();
-
- for (Group group : groups) {
- if (group.getMembers().contains(user)) {
- newGroups.add(group);
- }
- }
- groupService.sortByGroupType(newGroups);
-
- return newGroups;
- }
-
- /**
- * Gibt die Gruppe zurück, die zu der übergebenen Id passt.
- *
- * @param groupId Die Id der gesuchten Gruppe
- *
- * @return Die gesuchte Gruppe
- *
- * @throws EventException Wenn die Gruppe nicht gefunden wird
- */
- public Group getGroupById(UUID groupId) throws EventException {
- List groupIds = new ArrayList<>();
- groupIds.add(groupId);
-
- try {
- List events = groupService.getGroupEvents(groupIds);
- return groupService.projectEventList(events).get(0);
- } catch (IndexOutOfBoundsException e) {
- throw new GroupNotFoundException("@UserService");
- }
- }
-}
diff --git a/src/main/java/mops/gruppen2/service/ValidationService.java b/src/main/java/mops/gruppen2/service/ValidationService.java
deleted file mode 100644
index b1defef..0000000
--- a/src/main/java/mops/gruppen2/service/ValidationService.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.domain.Account;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.Role;
-import mops.gruppen2.domain.User;
-import mops.gruppen2.domain.Visibility;
-import mops.gruppen2.domain.exception.BadParameterException;
-import mops.gruppen2.domain.exception.GroupFullException;
-import mops.gruppen2.domain.exception.GroupNotFoundException;
-import mops.gruppen2.domain.exception.NoAccessException;
-import mops.gruppen2.domain.exception.NoAdminAfterActionException;
-import mops.gruppen2.domain.exception.UserAlreadyExistsException;
-import mops.gruppen2.domain.exception.UserNotFoundException;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import static mops.gruppen2.domain.Role.ADMIN;
-
-@Service
-public class ValidationService {
-
- private final UserService userService;
- private final GroupService groupService;
-
- public ValidationService(UserService userService, GroupService groupService) {
- this.userService = userService;
- this.groupService = groupService;
- }
-
- //TODO: make static or change return + assignment
- public List checkSearch(String search, List groups, Account account) {
- if (search != null) {
- groups = groupService.findGroupWith(search, account);
- }
- return groups;
- }
-
- public void throwIfGroupNotExisting(String title) {
- if (title == null) {
- throw new GroupNotFoundException("@details");
- }
- }
-
- public void throwIfUserAlreadyInGroup(Group group, User user) {
- if (checkIfUserInGroup(group, user)) {
- throw new UserAlreadyExistsException("@details");
- }
- }
-
- void throwIfNotInGroup(Group group, User user) {
- if (!checkIfUserInGroup(group, user)) {
- throw new UserNotFoundException(getClass().toString());
- }
- }
-
- public boolean checkIfUserInGroup(Group group, User user) {
- return group.getMembers().contains(user);
- }
-
- public void throwIfGroupFull(Group group) {
- if (group.getUserMaximum() < group.getMembers().size() + 1) {
- throw new GroupFullException("Du kannst der Gruppe daher leider nicht beitreten.");
- }
- }
-
- boolean checkIfGroupEmpty(UUID groupId) {
- return userService.getGroupById(groupId).getMembers().isEmpty();
- }
-
- public void throwIfNoAdmin(Group group, User user) {
- throwIfNoAccessToPrivate(group, user);
- if (group.getRoles().get(user.getId()) != ADMIN) {
- throw new NoAccessException("");
- }
- }
-
- public void throwIfNoAccessToPrivate(Group group, User user) {
- if (!checkIfUserInGroup(group, user) && group.getVisibility() == Visibility.PRIVATE) {
- throw new NoAccessException("");
- }
- }
-
- public boolean checkIfAdmin(Group group, User user) {
- if (checkIfUserInGroup(group, user)) {
- return group.getRoles().get(user.getId()) == ADMIN;
- }
- return false;
- }
-
- void throwIfLastAdmin(Account account, Group group) {
- if (checkIfLastAdmin(account, group)) {
- throw new NoAdminAfterActionException("Du bist letzter Admin!");
- }
- }
-
- boolean checkIfLastAdmin(Account account, Group group) {
- for (Map.Entry entry : group.getRoles().entrySet()) {
- if (entry.getValue() == ADMIN && !(entry.getKey().equals(account.getName()))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Überprüft ob alle Felder richtig gesetzt sind.
- *
- * @param description Die Beschreibung der Gruppe
- * @param title Der Titel der Gruppe
- * @param userMaximum Das user Limit der Gruppe
- */
- public void checkFields(String title, String description, Long userMaximum, Boolean maxInfiniteUsers) {
- if (description == null || description.trim().isEmpty()) {
- throw new BadParameterException("Die Beschreibung wurde nicht korrekt angegeben");
- }
-
- if (title == null || title.trim().isEmpty()) {
- throw new BadParameterException("Der Titel wurde nicht korrekt angegeben");
- }
-
- if (userMaximum == null && maxInfiniteUsers == null) {
- throw new BadParameterException("Teilnehmeranzahl wurde nicht korrekt angegeben");
- }
-
- if (userMaximum != null && (userMaximum < 1 || userMaximum > 10000L)) {
- throw new BadParameterException("Teilnehmeranzahl wurde nicht korrekt angegeben");
- }
- }
-
- public void checkFields(String title, String description) {
- if (description == null || description.trim().isEmpty()) {
- throw new BadParameterException("Die Beschreibung wurde nicht korrekt angegeben");
- }
-
- if (title == null || title.trim().isEmpty()) {
- throw new BadParameterException("Der Titel wurde nicht korrekt angegeben");
- }
- }
-
- public void throwIfNewMaximumIsValid(Long newUserMaximum, Group group) {
- if (newUserMaximum == null) {
- throw new BadParameterException("Es wurde keine neue maximale Teilnehmeranzahl angegeben!");
- }
-
- if (newUserMaximum < 1 || newUserMaximum > 10000L) {
- throw new BadParameterException("Die neue maximale Teilnehmeranzahl wurde nicht korrekt angegeben!");
- }
-
- if (group.getMembers().size() > newUserMaximum) {
- throw new BadParameterException("Die neue maximale Teilnehmeranzahl ist kleiner als die aktuelle Teilnehmeranzahl!");
- }
- }
-}
diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties
index 0a56ff4..824d245 100644
--- a/src/main/resources/application-dev.properties
+++ b/src/main/resources/application-dev.properties
@@ -1,23 +1,18 @@
-application.name=gruppen2
-logging.pattern.console=[${application.name}],%magenta(%-5level), %d{dd-MM-yyyy HH:mm:ss.SSS}, %highlight(%msg),%thread,%logger.%M%n
-spring.datasource.platform=h2
-spring.datasource.url=jdbc:h2:mem:blogdb
-spring.datasource.driver-class-name=org.h2.Driver
-spring.datasource.username=sa
-spring.datasource.password=
-spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
-spring.h2.console.enabled=false
-logging.level.org.springframework.jdbc.core=INFO
-keycloak.principal-attribute=preferred_username
-keycloak.auth-server-url=https://keycloak.cs.hhu.de/auth
-keycloak.realm=MOPS
-hhu_keycloak.token-uri=https://keycloak.cs.hhu.de/auth/realms/MOPS/protocol/openid-connect/token
-keycloak.resource=gruppenfindung
-keycloak.credentials.secret=fc6ebf10-8c63-4e71-a667-4eae4e8209a1
-keycloak.verify-token-audience=true
-keycloak.use-resource-role-mappings=true
-keycloak.autodetect-bearer-only=true
-keycloak.confidential-port=443
-server.error.include-stacktrace=always
-management.endpoints.web.exposure.include=info,health
-spring.cache.type=NONE
+# Logging
+logging.level.mops.gruppen2 = trace
+logging.level.org.springframework.jdbc.core = info
+
+# Database
+spring.datasource.platform = h2
+spring.datasource.driver-class-name = org.h2.Driver
+spring.datasource.initialization-mode = always
+spring.datasource.url = jdbc:h2:mem:blogdb
+spring.datasource.username = sa
+spring.datasource.password =
+spring.jpa.database-platform = org.hibernate.dialect.H2Dialect
+spring.h2.console.enabled = false
+
+# Misc
+server.error.include-stacktrace = always
+management.endpoints.web.exposure.include = info,health
+spring.cache.type = none
diff --git a/src/main/resources/application-docker.properties b/src/main/resources/application-docker.properties
index 3474f7a..a9faa16 100644
--- a/src/main/resources/application-docker.properties
+++ b/src/main/resources/application-docker.properties
@@ -1,19 +1,15 @@
-application.name=gruppen2
-logging.pattern.console=[${application.name}],%magenta(%-5level), %d{dd-MM-yyyy HH:mm:ss.SSS}, %highlight(%msg),%thread,%logger.%M%n
-spring.datasource.platform=mysql
-spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
-spring.datasource.initialization-mode=NEVER
-spring.datasource.url=jdbc:mysql://dbmysql:3306/gruppen2
-spring.datasource.username=root
-spring.datasource.password=geheim
-keycloak.principal-attribute=preferred_username
-keycloak.auth-server-url=https://keycloak.cs.hhu.de/auth
-keycloak.realm=MOPS
-hhu_keycloak.token-uri=https://keycloak.cs.hhu.de/auth/realms/MOPS/protocol/openid-connect/token
-keycloak.resource=gruppenfindung
-keycloak.credentials.secret=fc6ebf10-8c63-4e71-a667-4eae4e8209a1
-keycloak.verify-token-audience=true
-keycloak.use-resource-role-mappings=true
-keycloak.autodetect-bearer-only=true
-keycloak.confidential-port=443
-management.endpoints.web.exposure.include=info,health
+# Logging
+logging.level.mops.gruppen2 = info
+logging.level.org.springframework.jdbc.core = info
+
+# Database
+spring.datasource.platform = mysql
+spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
+spring.datasource.initialization-mode = never
+spring.datasource.url = jdbc:mysql://dbmysql:3306/gruppen
+spring.datasource.username = gruppen
+spring.datasource.password = password
+
+# Misc
+management.endpoints.web.exposure.include = info,health
+server.error.include-stacktrace = always
diff --git a/src/main/resources/application-heroku.properties b/src/main/resources/application-heroku.properties
new file mode 100644
index 0000000..a2a87c7
--- /dev/null
+++ b/src/main/resources/application-heroku.properties
@@ -0,0 +1,15 @@
+# Logging
+logging.level.mops.gruppen2 = info
+logging.level.org.springframework.jdbc.core = info
+
+# Database
+spring.datasource.platform = mysql
+spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
+spring.datasource.initialization-mode = never
+spring.datasource.url = mysql://b4b665d39d0670:cc933ff7@eu-cdbr-west-02.cleardb.net/heroku_f6ff902475fc2fa?reconnect=true
+spring.datasource.username = b4b665d39d0670
+spring.datasource.password = cc933ff7
+
+# Misc
+management.endpoints.web.exposure.include = info,health
+server.error.include-stacktrace = always
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 7f0e7ec..be154ec 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,2 +1,28 @@
-spring.profiles.active=dev
+spring.profiles.active = dev
+# Security
+#keycloak.principal-attribute = preferred_username
+#keycloak.auth-server-url = https://keycloak.cs.hhu.de/auth
+#keycloak.realm = MOPS
+#hhu_keycloak.token-uri = https://keycloak.cs.hhu.de/auth/realms/MOPS/protocol/openid-connect/token
+#keycloak.resource = gruppenfindung
+#keycloak.credentials.secret = fc6ebf10-8c63-4e71-a667-4eae4e8209a1
+#keycloak.verify-token-audience = true
+#keycloak.use-resource-role-mappings = true
+#keycloak.autodetect-bearer-only = true
+#keycloak.confidential-port = 443
+keycloak.auth-server-url = https://churl-keycloak.herokuapp.com/auth
+hhu_keycloak.token-uri = https://churl-keycloak.herokuapp.com/auth/realms/gruppen/protocol/openid-connect/token
+keycloak.principal-attribute = preferred_username
+keycloak.realm = gruppen
+keycloak.resource = gruppen-app
+keycloak.credentials.secret = 2e2e5770-c454-4d31-be99-9d8c34c93089
+keycloak.verify-token-audience = true
+keycloak.use-resource-role-mappings = true
+keycloak.autodetect-bearer-only = true
+keycloak.confidential-port = 443
+
+# Logging
+logging.application.name = gruppen2
+logging.pattern.console = [${logging.application.name}], %magenta(%-5level), %d{dd-MM-yyyy HH:mm:ss.SSS},\t%blue(%msg)\t%thread,%logger.%M%n
+spring.output.ansi.enabled = always
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
new file mode 100644
index 0000000..45613fb
--- /dev/null
+++ b/src/main/resources/data.sql
@@ -0,0 +1,27 @@
+INSERT INTO event(group_id, group_version, exec_id, target_id, event_date, event_payload)
+VALUES ('e65dd5f1-b252-4512-8db4-0407b31d199f', '1', 'orga', 'null', '2020-04-17 18:52:01.259555',
+ '{"class":"CREATEGROUP","date":[2020,4,17,18,52,1,259555000],"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":1,"exec":"orga","target":null}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '2', 'orga', 'orga', '2020-04-17 18:52:01.291448',
+ '{"class":"ADDMEMBER","user":{"id":"orga","givenname":"Thomas","familyname":"Organisator","email":"orga@hhu.de"},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":2,"exec":"orga","target":"orga","date":[2020,4,17,18,52,1,291448000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '3', 'orga', 'orga', '2020-04-17 18:52:01.301972',
+ '{"class":"UPDATEROLE","role":"ADMIN","groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":3,"exec":"orga","target":"orga","date":[2020,4,17,18,52,1,301972000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '4', 'orga', 'null', '2020-04-17 18:52:01.3053',
+ '{"class":"SETLIMIT","limit":{"value":1000},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":4,"exec":"orga","target":null,"date":[2020,4,17,18,52,1,305300000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '5', 'orga', 'null', '2020-04-17 18:52:01.310406',
+ '{"class":"SETTYPE","type":"LECTURE","groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":5,"exec":"orga","target":null,"date":[2020,4,17,18,52,1,310406000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '6', 'orga', 'null', '2020-04-17 18:52:01.313421',
+ '{"class":"SETPARENT","parent":{"id":"00000000-0000-0000-0000-000000000000"},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":6,"exec":"orga","target":null,"date":[2020,4,17,18,52,1,313421000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '7', 'orga', 'null', '2020-04-17 18:52:01.317931',
+ '{"class":"SETTITLE","title":{"value":"Programmierung SS2020"},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":7,"exec":"orga","target":null,"date":[2020,4,17,18,52,1,317931000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '8', 'orga', 'null', '2020-04-17 18:52:01.320693',
+ '{"class":"SETDESCRIPTION","desc":{"value":"Einführung in die objektorientierte Programmierung mit Java."},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":8,"exec":"orga","target":null,"date":[2020,4,17,18,52,1,320693000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '9', 'orga', 'A5ggd', '2020-04-17 18:52:01.330879',
+ '{"class":"ADDMEMBER","user":{"id":"A5ggd","givenname":"peter","familyname":"pan","email":"peter@pan.com"},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":9,"exec":"orga","target":"A5ggd","date":[2020,4,17,18,52,1,330879000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '10', 'orga', 'Affs', '2020-04-17 18:52:01.333756',
+ '{"class":"ADDMEMBER","user":{"id":"Affs","givenname":"olaf","familyname":"pomodoro","email":"ol@f-99.de"},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":10,"exec":"orga","target":"Affs","date":[2020,4,17,18,52,1,333756000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '11', 'orga', '55fdd', '2020-04-17 18:52:01.336206',
+ '{"class":"ADDMEMBER","user":{"id":"55fdd","givenname":"dieter","familyname":"niemöller","email":"pfarrer@erde.de"},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":11,"exec":"orga","target":"55fdd","date":[2020,4,17,18,52,1,336206000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '12', 'orga', '22ööl', '2020-04-17 18:52:01.338582',
+ '{"class":"ADDMEMBER","user":{"id":"22ööl","givenname":"thomas","familyname":"müller","email":"thot@scheisse.de"},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":12,"exec":"orga","target":"22ööl","date":[2020,4,17,18,52,1,338582000]}'),
+ ('e65dd5f1-b252-4512-8db4-0407b31d199f', '13', 'orga', 'tdsd8', '2020-04-17 18:52:01.341216',
+ '{"class":"ADDMEMBER","user":{"id":"tdsd8","givenname":"tobidignouserandingdong","familyname":"abraham","email":"g@gmail.mail"},"groupid":"e65dd5f1-b252-4512-8db4-0407b31d199f","version":13,"exec":"orga","target":"tdsd8","date":[2020,4,17,18,52,1,341216000]}');
diff --git a/src/main/resources/schema-h2.sql b/src/main/resources/schema-h2.sql
index 72405f2..0f2779a 100644
--- a/src/main/resources/schema-h2.sql
+++ b/src/main/resources/schema-h2.sql
@@ -3,17 +3,10 @@ DROP TABLE IF EXISTS event;
CREATE TABLE event
(
event_id INT PRIMARY KEY AUTO_INCREMENT,
- group_id VARCHAR(36) NOT NULL,
- user_id VARCHAR(50),
- event_type VARCHAR(32),
- event_payload VARCHAR(2500)
-);
-
-DROP TABLE IF EXISTS invite;
-
-CREATE TABLE invite
-(
- invite_id INT PRIMARY KEY AUTO_INCREMENT,
- group_id VARCHAR(36) NOT NULL,
- invite_link VARCHAR(36) NOT NULL
+ group_id VARCHAR(36) NOT NULL,
+ group_version INT NOT NULL,
+ exec_id VARCHAR(50) NOT NULL,
+ target_id VARCHAR(50),
+ event_date DATETIME NOT NULL,
+ event_payload VARCHAR(2500) NOT NULL
);
diff --git a/src/main/resources/static/css/details.css b/src/main/resources/static/css/details.css
new file mode 100644
index 0000000..1df08cc
--- /dev/null
+++ b/src/main/resources/static/css/details.css
@@ -0,0 +1,17 @@
+/*Content*/
+.content-heading {
+ margin-bottom: 15px;
+}
+
+/*Member List*/
+.members {
+ overflow-y: auto;
+ overflow-x: hidden;
+ max-height: calc(100vh - 250px);
+ max-width: 100%;
+}
+
+li span {
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
diff --git a/src/main/resources/static/css/index.css b/src/main/resources/static/css/index.css
new file mode 100644
index 0000000..08993cb
--- /dev/null
+++ b/src/main/resources/static/css/index.css
@@ -0,0 +1,27 @@
+/*Grouplist Hover Effect*/
+.content {
+ background: #e6f4ff;
+ box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
+}
+
+.content:hover {
+ background: #d4ecff;
+ box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
+}
+
+.content:hover .content-heading {
+ padding-bottom: 10px;
+}
+
+.content-text-in {
+ box-shadow: inset 0 .125rem .25rem rgba(0, 0, 0, .075);
+}
+
+.content:hover .content-text-in {
+ box-shadow: inset 0 .125rem .25rem rgba(0, 0, 0, .25);
+}
+
+/*Badges*/
+.badge-pill {
+ margin-right: 15px;
+}
diff --git a/src/main/resources/static/css/search.css b/src/main/resources/static/css/search.css
new file mode 100644
index 0000000..eed7426
--- /dev/null
+++ b/src/main/resources/static/css/search.css
@@ -0,0 +1,27 @@
+/*Grouplist*/
+.content.top {
+ padding: 10px 10px !important;
+ margin-bottom: 15px !important;
+}
+
+.content {
+ margin-top: 5px;
+ padding: 5px 5px;
+}
+
+.content-heading {
+ margin-bottom: 5px;
+}
+
+.content-text-in {
+ box-shadow: none;
+ margin-bottom: 0;
+ padding: 5px;
+}
+
+/*Badges*/
+.badge-pill {
+ align-self: start;
+ margin-top: 2px;
+ margin-right: 15px;
+}
diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css
new file mode 100644
index 0000000..dab0b4a
--- /dev/null
+++ b/src/main/resources/static/css/style.css
@@ -0,0 +1,135 @@
+/*Background Light Blue: #e6f4ff*/
+/* Focused: #d4ecff*/
+/*Background Matt White: whitesmoke*/
+/*Text Heading Blue: dodgerblue*/
+/* Focused: #4fa4ff*/
+/*Badge Background Private: darkslategray*/
+/*Badge Background Public: #52a1eb*/
+/*Badge Background Veranstaltung: lightseagreen*/
+/*Badge Background Parent: mediumorchid*/
+
+/*Content Container*/
+.content {
+ border-radius: 5px;
+ background: #d4ecff;
+ padding: 10px 10px;
+ margin-bottom: 15px;
+ box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
+ transition: 100ms;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ cursor: default;
+}
+
+/*Content Heading*/
+.content-heading {
+ margin-bottom: 10px;
+ font-weight: bold;
+ font-optical-sizing: auto;
+ overflow-wrap: break-word;
+ transition: 100ms;
+}
+
+.content-heading .link {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+h1, h3 {
+ cursor: default;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+/*Content Paragraph*/
+.content-text {
+ margin-bottom: 15px;
+ cursor: default;
+ transition: 100ms;
+}
+
+.content-text-in {
+ background: whitesmoke;
+ border-radius: 5px;
+ padding: 10px;
+ margin-bottom: 15px;
+ cursor: default;
+ box-shadow: inset 0 .125rem .25rem rgba(0, 0, 0, .25);
+ transition: 100ms;
+}
+
+.content-text-in div {
+ overflow-wrap: break-word;
+ font-optical-sizing: auto;
+}
+
+/*Link*/
+.link {
+ color: var(--primary);
+ transition: 100ms;
+}
+
+.link:hover {
+ color: #4fa4ff;
+}
+
+/*Button*/
+.btn {
+ width: 250px;
+}
+
+.btn-spacer {
+}
+
+/*Badges*/
+.badge-pill {
+ cursor: default;
+ color: whitesmoke;
+ align-self: start;
+}
+
+.lecture {
+ background: var(--info);
+}
+
+.public {
+ background: var(--primary);
+}
+
+.private {
+ background: var(--secondary);
+}
+
+.parent {
+ background: var(--warning);
+}
+
+/*Input*/
+.input-group {
+ width: auto;
+}
+
+.input-group-append {
+ max-width: 50%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.input-group-append {
+ max-width: 50%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.input-group-append span {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-family: monospace;
+}
+
+.input-group-append span {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-family: monospace;
+}
diff --git a/src/main/resources/static/js/script.js b/src/main/resources/static/js/script.js
new file mode 100644
index 0000000..138e079
--- /dev/null
+++ b/src/main/resources/static/js/script.js
@@ -0,0 +1,18 @@
+// Add the following code if you want the name of the file appear on select
+
+function disable(id) {
+ $(id).prop('disabled', true);
+}
+
+function enable(id) {
+ $(id).prop('disabled', false);
+}
+
+function copyLink() {
+ const copyText = document.getElementById("linkview");
+
+ copyText.select();
+ copyText.setSelectionRange(0, 99999);
+
+ document.execCommand("copy");
+}
diff --git a/src/main/resources/templates/changeMetadata.html b/src/main/resources/templates/changeMetadata.html
deleted file mode 100644
index 7488365..0000000
--- a/src/main/resources/templates/changeMetadata.html
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
- Gruppenerstellung
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/create.html b/src/main/resources/templates/create.html
new file mode 100644
index 0000000..8c0d28b
--- /dev/null
+++ b/src/main/resources/templates/create.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ Neue Gruppe
+
+
+
+
Eigenschaften:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gruppe Erstellen
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/createOrga.html b/src/main/resources/templates/createOrga.html
deleted file mode 100644
index 99a129a..0000000
--- a/src/main/resources/templates/createOrga.html
+++ /dev/null
@@ -1,144 +0,0 @@
-
-
-
-
- Gruppenerstellung
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Gruppenerstellung
-
-
-
- Titel
-
-
-
- Beschreibung
-
-
-
-
- Anzahl
- unbegrenzt
-
-
- Teilnehmeranzahl
-
-
-
-
- Private
- Gruppe
-
-
-
- Veranstaltung
-
-
-
-
- --Bitte Veranstaltung auswählen--
-
-
-
-
-
-
-
- Erstellen
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/createStudent.html b/src/main/resources/templates/createStudent.html
deleted file mode 100644
index 022c918..0000000
--- a/src/main/resources/templates/createStudent.html
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
-
- Gruppenerstellung
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Gruppenerstellung
-
-
-
-
- Titel
-
-
-
- Beschreibung
-
-
-
-
- Anzahl
- unbegrenzt
-
-
- Teilnehmeranzahl
-
-
-
-
- Private
- Gruppe
-
-
-
-
- --Bitte Veranstaltung auswählen--
-
-
-
-
-
-
- Erstellen
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/details.html b/src/main/resources/templates/details.html
new file mode 100644
index 0000000..0a4a400
--- /dev/null
+++ b/src/main/resources/templates/details.html
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gruppenmaterialien
+
+
+
+
Neue Materialien:
+
+
Angepinnt:
+
+
+
+
+
+
+
+
+
+
+
+ Gruppentermine
+
+
+
+
+
+
+
+
+
+
+ Gruppenportfolio
+
+
+
+
+
+
+
+
+
+
+ Modulhandbuch
+
+
+
+
Veranstaltungsinfo:
+
+ Dieses Modul vermittelt grundlegende Programmierkenntnisse in einer
+ objektorientierten Programmiersprache.
+ Darüber hinaus werden einführend Aspekte von Algorithmen und
+ Datenstrukturen behandelt.
+ Es wird keine Programmiererfahrung vorausgesetzt.
+
+
+ Grundlegende Begriffe der Informatik
+ Primitive Datentypen und Variablen
+ Kontrollstrukturen
+ Eigene Datentypen (Klassen) und Arrays
+ Programmstrukturen im Speicher (Heap, Stack)
+ Konzepte der Objektorientierung (Polymorphie, Schnittstellen)
+
+ Rekursion
+ Fehlerbehandlung
+ Dynamische Datenstrukturen (Listen, Binärbäume, Hashing)
+ Suchen und Sortieren (ausgewählte Algorithmen, u.a. binäre
+ Suche, BubbleSort, QuickSort)
+
+ Datenströme (Standard-Eingabe und -Ausgabe, einfache 2D-Grafik,
+ Dateien)
+
+
+
+
+
+
+
+
+
+
+
+
Fertig
+
+
+
+
+ Gruppe verlassen
+
+
+
+
+
+
+
+
+
+
+
+ Teilnehmer:
+
+
+
+
+
+
+ Gruppe verwalten
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/detailsMember.html b/src/main/resources/templates/detailsMember.html
deleted file mode 100644
index 4fea4cc..0000000
--- a/src/main/resources/templates/detailsMember.html
+++ /dev/null
@@ -1,149 +0,0 @@
-
-
-
-
- Gruppendetails
-
-
-
-
-
-
-
-
-
-
-
-
- Private Gruppe
- Öffentliche Gruppe
- Veranstaltung
- Parent
-
-
-
-
-
-
-
-
- Zurück
-
-
- Gruppe verlassen
-
-
-
- Gruppe löschen
-
-
-
-
-
-
Mitglieder
-
-
-
unbegrenzte Teilnehmeranzahl
-
-
-
-
- Mitglieder bearbeiten
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/detailsNoMember.html b/src/main/resources/templates/detailsNoMember.html
deleted file mode 100644
index cafac72..0000000
--- a/src/main/resources/templates/detailsNoMember.html
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
- Gruppendetails
-
-
-
-
-
-
-
-
-
-
-
-
-
- Private Gruppe
- Öffentliche Gruppe
- Veranstaltung
- Parent
-
-
-
-
-
-
-
-
Mitglieder
-
-
-
unbegrenzte Teilnehmeranzahl
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/edit.html b/src/main/resources/templates/edit.html
new file mode 100644
index 0000000..0756e05
--- /dev/null
+++ b/src/main/resources/templates/edit.html
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
Fertig
+
+
+
+ Gruppe löschen
+
+
+
+
+
+
+
+
+
+ Einladungslink:
+
+
+
+ Link kopieren
+
+
+
+
+
+
+
+ Eigenschaften
+
+
+
+
+
+
+
+
+
+ Speichern
+
+
+
+
+
+
+
+
+
+
+
+
+ Speichern
+
+
+
+
+
+
+
+
+
+
+
+
+ Speichern
+
+
+
+
+
+
+
+
+
+
+
+
+ Teilnehmer
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Entfernen
+
+
+
+
+
+
+
+ Rolle ändern
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/editMembers.html b/src/main/resources/templates/editMembers.html
deleted file mode 100644
index afc7c77..0000000
--- a/src/main/resources/templates/editMembers.html
+++ /dev/null
@@ -1,152 +0,0 @@
-
-
-
-
- Gruppendetails
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Mitglieder bearbeiten
-
-
-
unbegrenzte Teilnehmeranzahl
-
-
-
-
-
-
-
-
- Mitglied
- Rolle
- Optionen
-
-
-
-
-
-
- Mitglied
- Admin
-
-
-
-
-
-
- Rolle ändern
-
-
-
-
-
-
- Mitglied entfernen
-
-
-
-
-
-
-
-
-
- Fertig
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html
index 4757838..a2c3274 100644
--- a/src/main/resources/templates/error.html
+++ b/src/main/resources/templates/error.html
@@ -1,38 +1,37 @@
-
-
-
-
-
-
-
-
+
+
-
-
-
-
UPSI
-
Da ist wohl etwas schiefgelaufen :(
-
-
+
+
-
-
-
-
+
+
UPSI
+
+
+
Da ist wohl etwas schiefgelaufen :(
+
+
-
- Zurück
-
-
+
+
+
diff --git a/src/main/resources/templates/fragments/forms.html b/src/main/resources/templates/fragments/forms.html
new file mode 100644
index 0000000..17607d7
--- /dev/null
+++ b/src/main/resources/templates/fragments/forms.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gruppentyp:
+
+
+
+
+
+ Teilnehmeranzahl:
+
+
+
+
+
diff --git a/src/main/resources/templates/fragments/general.html b/src/main/resources/templates/fragments/general.html
new file mode 100644
index 0000000..80e4a81
--- /dev/null
+++ b/src/main/resources/templates/fragments/general.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/fragments/groups.html b/src/main/resources/templates/fragments/groups.html
new file mode 100644
index 0000000..7030f88
--- /dev/null
+++ b/src/main/resources/templates/fragments/groups.html
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+ Privat
+ Öffentlich
+ Veranstaltung
+
+ Parent
+
+
+
+
+
+
+
+
+ Admin
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Möchtest du dieser Gruppe beitreten?
+
+
+ Diese Gruppe hat ihre maximale Teilnehmeranzahl erreicht.
+
+
+
+
+
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index 7160113..8f918c4 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -1,70 +1,36 @@
-
-
-
-
Eigene Gruppen
-
-
-
-
+
+
-
+
-
-
-
-
Meine Gruppen
-
-
- Mitglied in
-
- Gruppe.
- Gruppen.
-
-
-
-
-
- Veranstaltung
-
-
-
-
-
-
-
-
-
+
Meine Gruppen
+
+
+
+
+
+
Öffentliche Gruppen
+
+
+
+
+
diff --git a/src/main/resources/templates/joinprivate.html b/src/main/resources/templates/joinprivate.html
deleted file mode 100644
index c9b5832..0000000
--- a/src/main/resources/templates/joinprivate.html
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
Gruppendetails
-
-
-
-
-
-
-
-
-
-
-
-
-
Möchtest du dieser privaten Gruppe beitreten?
-
-
-
-
-
-
-
Mitglieder
-
-
-
unbegrenzte Teilnehmeranzahl
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/link.html b/src/main/resources/templates/link.html
new file mode 100644
index 0000000..c4f8f81
--- /dev/null
+++ b/src/main/resources/templates/link.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/log.html b/src/main/resources/templates/log.html
new file mode 100644
index 0000000..f60bd36
--- /dev/null
+++ b/src/main/resources/templates/log.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ Event-Log
+
+
+
+
+
+ Datum:
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/preview.html b/src/main/resources/templates/preview.html
new file mode 100644
index 0000000..2b78821
--- /dev/null
+++ b/src/main/resources/templates/preview.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/search.html b/src/main/resources/templates/search.html
index e90a8dd..4ed2c60 100644
--- a/src/main/resources/templates/search.html
+++ b/src/main/resources/templates/search.html
@@ -1,91 +1,52 @@
-
-
-
-
Suche
-
-
-
-
+
+
-
+
+
+
+
-
-
-
-
Gruppensuche
-
-
-
- Suchbegriff:
-
-
- Suchen
-
-
- Alle
- anzeigen
-
-
+
Suchen
+
+
+
+
+
+
-
-
-
-
-
- Gruppenname
- Beschreibung
- Max. Mitgliederanzahl
-
-
-
-
-
- Veranstaltung
- Gruppenname
-
-
- Beschreibung
-
-
-
-
- unbegrenzt
-
-
-
+
+
+ Suchen
+
+
+
+
+
+
+
+
diff --git a/src/test/java/mops/gruppen2/GroupBuilder.java b/src/test/java/mops/gruppen2/GroupBuilder.java
new file mode 100644
index 0000000..154c27c
--- /dev/null
+++ b/src/test/java/mops/gruppen2/GroupBuilder.java
@@ -0,0 +1,154 @@
+package mops.gruppen2;
+
+import mops.gruppen2.domain.event.AddMemberEvent;
+import mops.gruppen2.domain.event.CreateGroupEvent;
+import mops.gruppen2.domain.event.DestroyGroupEvent;
+import mops.gruppen2.domain.event.Event;
+import mops.gruppen2.domain.event.KickMemberEvent;
+import mops.gruppen2.domain.event.SetDescriptionEvent;
+import mops.gruppen2.domain.event.SetInviteLinkEvent;
+import mops.gruppen2.domain.event.SetLimitEvent;
+import mops.gruppen2.domain.event.SetTitleEvent;
+import mops.gruppen2.domain.event.SetTypeEvent;
+import mops.gruppen2.domain.event.UpdateRoleEvent;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Role;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.domain.model.group.wrapper.Description;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.domain.model.group.wrapper.Link;
+import mops.gruppen2.domain.model.group.wrapper.Title;
+import mops.gruppen2.infrastructure.GroupCache;
+
+import java.time.LocalDateTime;
+import java.util.UUID;
+
+import static mops.gruppen2.TestHelper.uuid;
+
+public final class GroupBuilder {
+
+ private final UUID groupid;
+ private int version;
+ private final GroupCache groupCache;
+ private final Group group = Group.EMPTY();
+
+ private GroupBuilder(GroupCache cache, UUID id) {
+ groupCache = cache;
+ groupid = id;
+ }
+
+ /**
+ * Erzeugt neuen GruppenBuilder mit Cache und ID
+ */
+ public static GroupBuilder get(GroupCache cache, int id) {
+ return new GroupBuilder(cache, uuid(id));
+ }
+
+ /**
+ * Initialisiert Gruppe mit Id, Creator und Zeit
+ */
+ public GroupBuilder group() {
+ return apply(new CreateGroupEvent(groupid, "TEST", LocalDateTime.now()));
+ }
+
+ /**
+ * Initialisiert TestAdmin
+ */
+ public GroupBuilder testadmin() {
+ apply(new AddMemberEvent(groupid, "TEST", "TEST", new User("TEST")));
+ return apply(new UpdateRoleEvent(groupid, "TEST", "TEST", Role.ADMIN));
+ }
+
+ /**
+ * Fügt Nutzer hinzu
+ */
+ public GroupBuilder add(String userid) {
+ return apply(new AddMemberEvent(groupid, "TEST", userid, new User(userid)));
+ }
+
+ /**
+ * Entfernt Nutzer
+ */
+ public GroupBuilder kick(String userid) {
+ return apply(new KickMemberEvent(groupid, "TEST", userid));
+ }
+
+ public GroupBuilder limit(int i) {
+ return apply(new SetLimitEvent(groupid, "TEST", new Limit(i)));
+ }
+
+ /**
+ * Macht Nutzer zu Admin
+ */
+ public GroupBuilder admin(String userid) {
+ return apply(new UpdateRoleEvent(groupid, "TEST", userid, Role.ADMIN));
+ }
+
+ /**
+ * Macht Nutzer zu regulärem
+ */
+ public GroupBuilder regular(String userid) {
+ return apply(new UpdateRoleEvent(groupid, "TEST", userid, Role.REGULAR));
+ }
+
+ /**
+ * Macht Gruppe öffentlich
+ */
+ public GroupBuilder publik() {
+ return apply(new SetTypeEvent(groupid, "TEST", Type.PUBLIC));
+ }
+
+ /**
+ * Macht Gruppe privat
+ */
+ public GroupBuilder privat() {
+ return apply(new SetTypeEvent(groupid, "TEST", Type.PRIVATE));
+ }
+
+ /**
+ * Macht Gruppe zu Veranstaltung
+ */
+ public GroupBuilder lecture() {
+ return apply(new SetTypeEvent(groupid, "TEST", Type.LECTURE));
+ }
+
+ /**
+ * Setzt Beschreibung
+ */
+ public GroupBuilder desc(String descr) {
+ return apply(new SetDescriptionEvent(groupid, "TEST", new Description(descr)));
+ }
+
+ /**
+ * Setzt Titel
+ */
+ public GroupBuilder title(String titl) {
+ return apply(new SetTitleEvent(groupid, "TEST", new Title(titl)));
+ }
+
+ /**
+ * Setzt Link
+ */
+ public GroupBuilder link(int lnk) {
+ return apply(new SetInviteLinkEvent(groupid, "TEST", new Link(uuid(lnk).toString())));
+ }
+
+ /**
+ * Löscht Gruppe
+ */
+ public GroupBuilder destroy() {
+ return apply(new DestroyGroupEvent(groupid, "TEST"));
+ }
+
+ public Group build() {
+ return group;
+ }
+
+ private GroupBuilder apply(Event event) {
+ version++;
+ event.init(version);
+ event.apply(group, groupCache);
+ return this;
+ }
+}
diff --git a/src/test/java/mops/gruppen2/Gruppen2ApplicationTests.java b/src/test/java/mops/gruppen2/Gruppen2ApplicationTests.java
index 5b437f6..5bbd706 100644
--- a/src/test/java/mops/gruppen2/Gruppen2ApplicationTests.java
+++ b/src/test/java/mops/gruppen2/Gruppen2ApplicationTests.java
@@ -6,6 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Gruppen2ApplicationTests {
+ @SuppressWarnings("EmptyMethod")
@Test
void contextLoads() {
}
diff --git a/src/test/java/mops/gruppen2/TestBuilder.java b/src/test/java/mops/gruppen2/TestBuilder.java
deleted file mode 100644
index d79f850..0000000
--- a/src/test/java/mops/gruppen2/TestBuilder.java
+++ /dev/null
@@ -1,320 +0,0 @@
-package mops.gruppen2;
-
-import com.github.javafaker.Faker;
-import mops.gruppen2.domain.Account;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.GroupType;
-import mops.gruppen2.domain.Role;
-import mops.gruppen2.domain.Visibility;
-import mops.gruppen2.domain.event.AddUserEvent;
-import mops.gruppen2.domain.event.CreateGroupEvent;
-import mops.gruppen2.domain.event.DeleteGroupEvent;
-import mops.gruppen2.domain.event.DeleteUserEvent;
-import mops.gruppen2.domain.event.Event;
-import mops.gruppen2.domain.event.UpdateGroupDescriptionEvent;
-import mops.gruppen2.domain.event.UpdateGroupTitleEvent;
-import mops.gruppen2.domain.event.UpdateRoleEvent;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-public class TestBuilder {
-
- private static final Faker faker = new Faker();
-
- public static Account account(String name) {
- return new Account(name,
- "",
- "",
- "",
- "",
- null);
- }
-
- public static Group apply(Group group, Event... events) {
- for (Event event : events) {
- event.apply(group);
- }
-
- return group;
- }
-
- public static Group apply(Event... events) {
- return apply(new Group(), events);
- }
-
- /**
- * Baut eine UUID.
- *
- * @param id Integer id
- *
- * @return UUID
- */
- public static UUID uuidMock(int id) {
- String idString = String.valueOf(Math.abs(id + 1));
- return UUID.fromString("00000000-0000-0000-0000-"
- + "0".repeat(11 - idString.length())
- + idString);
- }
-
- /**
- * Generiert ein EventLog mit mehreren Gruppen und Usern.
- *
- * @param count Gruppenanzahl
- * @param membercount Mitgliederanzahl pro Gruppe
- *
- * @return Eventliste
- */
- public static List
completePublicGroups(int count, int membercount) {
- return IntStream.range(0, count)
- .parallel()
- .mapToObj(i -> completePublicGroup(membercount))
- .flatMap(Collection::stream)
- .collect(Collectors.toList());
- }
-
- public static List completePrivateGroups(int count, int membercount) {
- return IntStream.range(0, count)
- .parallel()
- .mapToObj(i -> completePrivateGroup(membercount))
- .flatMap(Collection::stream)
- .collect(Collectors.toList());
- }
-
- public static List completePublicGroup(int membercount) {
- List eventList = new ArrayList<>();
- UUID groupId = UUID.randomUUID();
-
- eventList.add(createPublicGroupEvent(groupId));
- eventList.add(updateGroupTitleEvent(groupId));
- eventList.add(updateGroupDescriptionEvent(groupId));
- eventList.addAll(addUserEvents(membercount, groupId));
-
- return eventList;
- }
-
- public static List completePrivateGroup(int membercount) {
- List eventList = new ArrayList<>();
- UUID groupId = UUID.randomUUID();
-
- eventList.add(createPrivateGroupEvent(groupId));
- eventList.add(updateGroupTitleEvent(groupId));
- eventList.add(updateGroupDescriptionEvent(groupId));
- eventList.addAll(addUserEvents(membercount, groupId));
-
- return eventList;
- }
-
- public static List completePublicGroup() {
- return completePublicGroup(100);
- }
-
- public static List completePrivateGroup() {
- return completePrivateGroup(100);
- }
-
- /**
- * Generiert mehrere CreateGroupEvents, 1 <= groupId <= count.
- *
- * @param count Anzahl der verschiedenen Gruppen
- *
- * @return Eventliste
- */
- public static List createPublicGroupEvents(int count) {
- return IntStream.range(0, count)
- .parallel()
- .mapToObj(i -> createPublicGroupEvent())
- .collect(Collectors.toList());
- }
-
- public static List createPrivateGroupEvents(int count) {
- return IntStream.range(0, count)
- .parallel()
- .mapToObj(i -> createPublicGroupEvent())
- .collect(Collectors.toList());
- }
-
- public static List createMixedGroupEvents(int count) {
- return IntStream.range(0, count)
- .parallel()
- .mapToObj(i -> faker.random().nextInt(0, 1) > 0.5
- ? createPublicGroupEvent()
- : createPrivateGroupEvent())
- .collect(Collectors.toList());
- }
-
- public static Event createPrivateGroupEvent(UUID groupId) {
- return createGroupEvent(groupId, Visibility.PRIVATE);
- }
-
- public static Event createPrivateGroupEvent() {
- return createPrivateGroupEvent(UUID.randomUUID());
- }
-
- public static Event createPublicGroupEvent(UUID groupId) {
- return createGroupEvent(groupId, Visibility.PUBLIC);
- }
-
- public static Event createPublicGroupEvent() {
- return createPublicGroupEvent(UUID.randomUUID());
- }
-
- public static Event createGroupEvent(UUID groupId, Visibility visibility) {
- return new CreateGroupEvent(
- groupId,
- faker.random().hex(),
- null,
- GroupType.SIMPLE,
- visibility,
- 10000000L
- );
- }
-
- public static Event createLectureEvent() {
- return createLectureEvent(UUID.randomUUID());
- }
-
- public static Event createLectureEvent(UUID groupId) {
- return new CreateGroupEvent(
- groupId,
- faker.random().hex(),
- null,
- GroupType.LECTURE,
- Visibility.PUBLIC,
- 10000000L
- );
- }
-
- /**
- * Generiert mehrere AddUserEvents für eine Gruppe, 1 <= user_id <= count.
- *
- * @param count Anzahl der Mitglieder
- * @param groupId Gruppe, zu welcher geaddet wird
- *
- * @return Eventliste
- */
- public static List addUserEvents(int count, UUID groupId) {
- return IntStream.range(0, count)
- .parallel()
- .mapToObj(i -> addUserEvent(groupId, String.valueOf(i)))
- .collect(Collectors.toList());
- }
-
- public static Event addUserEvent(UUID groupId, String userId) {
- String firstname = firstname();
- String lastname = lastname();
-
- return new AddUserEvent(
- groupId,
- userId,
- firstname,
- lastname,
- firstname + "." + lastname + "@mail.de"
- );
- }
-
- public static Event addUserEvent(UUID groupId) {
- return addUserEvent(groupId, faker.random().hex());
- }
-
- // Am besten einfach nicht benutzen
- public static List deleteUserEvents(int count, List eventList) {
- List removeEvents = new ArrayList<>();
- List shuffle = eventList.parallelStream()
- .filter(event -> event instanceof AddUserEvent)
- .collect(Collectors.toList());
-
- Collections.shuffle(shuffle);
-
- for (Event event : shuffle) {
- removeEvents.add(new DeleteUserEvent(event.getGroupId(), event.getUserId()));
-
- if (removeEvents.size() >= count) {
- break;
- }
- }
-
- return removeEvents;
- }
-
- /**
- * Erzeugt mehrere DeleteUserEvents, sodass eine Gruppe komplett geleert wird.
- *
- * @param group Gruppe welche geleert wird
- *
- * @return Eventliste
- */
- public static List deleteUserEvents(Group group) {
- return group.getMembers().parallelStream()
- .map(user -> deleteUserEvent(group.getId(), user.getId()))
- .collect(Collectors.toList());
- }
-
- public static Event deleteUserEvent(UUID groupId, String userId) {
- return new DeleteUserEvent(
- groupId,
- userId
- );
- }
-
- public static Event updateGroupDescriptionEvent(UUID groupId) {
- return updateGroupDescriptionEvent(groupId, quote());
- }
-
- public static Event updateGroupDescriptionEvent(UUID groupId, String description) {
- return new UpdateGroupDescriptionEvent(
- groupId,
- faker.random().hex(),
- description
- );
- }
-
- public static Event updateGroupTitleEvent(UUID groupId) {
- return updateGroupTitleEvent(groupId, champion());
- }
-
- public static Event updateGroupTitleEvent(UUID groupId, String title) {
- return new UpdateGroupTitleEvent(
- groupId,
- faker.random().hex(),
- title
- );
- }
-
- public static Event updateRoleEvent(UUID groupId, String userId, Role role) {
- return new UpdateRoleEvent(
- groupId,
- userId,
- role
- );
- }
-
- public static Event deleteGroupEvent(UUID groupId) {
- return new DeleteGroupEvent(groupId, faker.random().hex());
- }
-
- private static String firstname() {
- return clean(faker.name().firstName());
- }
-
- private static String lastname() {
- return clean(faker.name().lastName());
- }
-
- private static String champion() {
- return clean(faker.leagueOfLegends().champion());
- }
-
- private static String quote() {
- return clean(faker.leagueOfLegends().quote());
- }
-
- private static String clean(String string) {
- return string.replaceAll("['\";,]", "");
- }
-}
diff --git a/src/test/java/mops/gruppen2/TestHelper.java b/src/test/java/mops/gruppen2/TestHelper.java
new file mode 100644
index 0000000..ad9968c
--- /dev/null
+++ b/src/test/java/mops/gruppen2/TestHelper.java
@@ -0,0 +1,24 @@
+package mops.gruppen2;
+
+import mops.gruppen2.domain.event.Event;
+
+import java.util.List;
+import java.util.UUID;
+
+public final class TestHelper {
+
+ public static UUID uuid(int id) {
+ String num = String.valueOf(id);
+ String string = "00000000-0000-0000-0000-";
+ string += "0".repeat(12 - num.length());
+ string += num;
+
+ return UUID.fromString(string);
+ }
+
+ public static void initEvents(List events) {
+ for (int i = 1; i <= events.size(); i++) {
+ events.get(i - 1).init(i);
+ }
+ }
+}
diff --git a/src/test/java/mops/gruppen2/architecture/ControllerTest.java b/src/test/java/mops/gruppen2/architecture/ControllerTest.java
index c954cce..5867549 100644
--- a/src/test/java/mops/gruppen2/architecture/ControllerTest.java
+++ b/src/test/java/mops/gruppen2/architecture/ControllerTest.java
@@ -11,7 +11,7 @@ import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
-public class ControllerTest {
+class ControllerTest {
@ArchTest
public static final ArchRule controllerClassesShouldBeAnnotatedWithControllerOrRestControllerAnnotation = classes()
@@ -23,18 +23,20 @@ public class ControllerTest {
public static final ArchRule controllerClassesShouldHaveControllerInName = classes()
.that().areAnnotatedWith(Controller.class)
.or().areAnnotatedWith(RestController.class)
- .should().haveSimpleNameEndingWith("Controller");
+ .should().haveSimpleNameEndingWith("Controller")
+ .orShould().haveSimpleNameEndingWith("ControllerAdvice");
@ArchTest
public static final ArchRule controllerClassesShouldBeInControllerPackage = classes()
.that().areAnnotatedWith(Controller.class)
.or().areAnnotatedWith(RestController.class)
- .should().resideInAPackage("..controller..");
+ .should().resideInAPackage("..controller");
@ArchTest
public static final ArchRule classesInControllerPackageShouldHaveControllerInName = classes()
- .that().resideInAPackage("..controller..")
- .should().haveSimpleNameEndingWith("Controller");
+ .that().resideInAPackage("..web")
+ .should().haveSimpleNameEndingWith("Controller")
+ .orShould().haveSimpleNameEndingWith("ControllerAdvice");
@ArchTest
public static final ArchRule controllerClassesShouldNotDependOnEachOther = noClasses()
diff --git a/src/test/java/mops/gruppen2/architecture/DomainTest.java b/src/test/java/mops/gruppen2/architecture/DomainTest.java
index caaa242..27f6c60 100644
--- a/src/test/java/mops/gruppen2/architecture/DomainTest.java
+++ b/src/test/java/mops/gruppen2/architecture/DomainTest.java
@@ -2,6 +2,7 @@ package mops.gruppen2.architecture;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
+import com.tngtech.archunit.junit.ArchIgnore;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import mops.gruppen2.domain.exception.EventException;
@@ -10,8 +11,9 @@ import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
-public class DomainTest {
+class DomainTest {
+ @ArchIgnore
@ArchTest
public static final ArchRule domainClassesShouldNotAccessClassesFromOtherPackagesExceptDomainItself = noClasses()
.that().resideInAPackage("..domain..")
@@ -25,7 +27,7 @@ public class DomainTest {
@ArchTest
public static final ArchRule classesInEventPackageShouldHaveEventInName = classes()
.that().resideInAPackage("..domain.event..")
- .should().haveSimpleNameEndingWith("Event");
+ .should().haveSimpleNameNotContaining("..Event..");
@ArchTest
public static final ArchRule exceptionClassesShouldBeInExceptionPackage = classes()
@@ -52,9 +54,4 @@ public class DomainTest {
.that().resideInAPackage("..domain.dto..")
.should().haveSimpleNameEndingWith("DTO");
- @ArchTest
- public static final ArchRule dtoClassesShouldBeInDtoPackage = classes()
- .that().haveSimpleNameEndingWith("DTO")
- .should().resideInAPackage("..domain.dto..");
-
}
diff --git a/src/test/java/mops/gruppen2/architecture/LayeredArchitectureTest.java b/src/test/java/mops/gruppen2/architecture/LayeredArchitectureTest.java
index 2596a1d..2556d08 100644
--- a/src/test/java/mops/gruppen2/architecture/LayeredArchitectureTest.java
+++ b/src/test/java/mops/gruppen2/architecture/LayeredArchitectureTest.java
@@ -2,35 +2,40 @@ package mops.gruppen2.architecture;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
+import com.tngtech.archunit.junit.ArchIgnore;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.library.Architectures;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
-public class LayeredArchitectureTest {
+class LayeredArchitectureTest {
private static final Architectures.LayeredArchitecture layeredArchitecture = Architectures
.layeredArchitecture()
.layer("Domain").definedBy("..domain..")
- .layer("Service").definedBy("..service")
- .layer("Controller").definedBy("..controller..")
- .layer("Repository").definedBy("..repository..");
+ .layer("Service").definedBy("..service..")
+ .layer("Controller").definedBy("..web..")
+ .layer("Repository").definedBy("..persistance..");
+ @ArchIgnore
@ArchTest
public static final ArchRule domainLayerShouldOnlyBeAccessedByServiceAndControllerLayer = layeredArchitecture
.whereLayer("Domain")
.mayOnlyBeAccessedByLayers("Service", "Controller");
+ @ArchIgnore
@ArchTest
public static final ArchRule serviceLayerShouldOnlyBeAccessedByControllerLayer = layeredArchitecture
.whereLayer("Service")
.mayOnlyBeAccessedByLayers("Controller");
+ @ArchIgnore
@ArchTest
public static final ArchRule repositoryLayerShouldOnlyBeAccessedByServiceLayer = layeredArchitecture
.whereLayer("Repository")
.mayOnlyBeAccessedByLayers("Service");
+ @ArchIgnore
@ArchTest
public static final ArchRule controllerLayerShouldNotBeAccessedByAnyLayer = layeredArchitecture
.whereLayer("Controller")
diff --git a/src/test/java/mops/gruppen2/architecture/RepositoryTest.java b/src/test/java/mops/gruppen2/architecture/RepositoryTest.java
index 946da19..82a5de3 100644
--- a/src/test/java/mops/gruppen2/architecture/RepositoryTest.java
+++ b/src/test/java/mops/gruppen2/architecture/RepositoryTest.java
@@ -10,7 +10,7 @@ import org.springframework.stereotype.Repository;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
-public class RepositoryTest {
+class RepositoryTest {
@ArchTest
public static final ArchRule repositoryClassesThatAreAnnotatedWithRepositoryShouldHaveRepositoryInName = classes()
@@ -20,7 +20,7 @@ public class RepositoryTest {
@ArchTest
public static final ArchRule repositoryClassesShouldBeInRepositoryPackage = classes()
.that().haveSimpleNameEndingWith("Repository")
- .should().resideInAPackage("..repository..");
+ .should().resideInAPackage("..persistance");
@ArchTest
public static final ArchRule repositoryClassesShouldBeAnnotatedWithRepositoryAnnotation = classes()
@@ -29,7 +29,7 @@ public class RepositoryTest {
@ArchTest
public static final ArchRule classesInRepositoryPackageShouldHaveRepositoryInName = classes()
- .that().resideInAPackage("..repository..")
+ .that().resideInAPackage("..persistance")
.should().haveSimpleNameEndingWith("Repository");
@ArchTest
@@ -37,4 +37,9 @@ public class RepositoryTest {
.that().areAssignableTo(CrudRepository.class)
.should().beAnnotatedWith(Repository.class);
+ @ArchTest
+ public static final ArchRule dtoClassesShouldBeInDtoPackage = classes()
+ .that().haveSimpleNameEndingWith("DTO")
+ .should().resideInAPackage("..persistance.dto..");
+
}
diff --git a/src/test/java/mops/gruppen2/architecture/ServiceTest.java b/src/test/java/mops/gruppen2/architecture/ServiceTest.java
index 716e8a0..84477a6 100644
--- a/src/test/java/mops/gruppen2/architecture/ServiceTest.java
+++ b/src/test/java/mops/gruppen2/architecture/ServiceTest.java
@@ -2,6 +2,7 @@ package mops.gruppen2.architecture;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.junit.AnalyzeClasses;
+import com.tngtech.archunit.junit.ArchIgnore;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import org.springframework.stereotype.Service;
@@ -9,7 +10,7 @@ import org.springframework.stereotype.Service;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
-public class ServiceTest {
+class ServiceTest {
@ArchTest
public static final ArchRule serviceClassesShouldHaveServiceInName = classes()
@@ -24,16 +25,17 @@ public class ServiceTest {
@ArchTest
public static final ArchRule serviceClassesShouldBeInServicePackage = classes()
.that().areAnnotatedWith(Service.class)
- .should().resideInAPackage("..service..");
+ .should().resideInAPackage("..service");
@ArchTest
public static final ArchRule classesInServicePackageShouldHaveServiceInName = classes()
- .that().resideInAPackage("..service..")
+ .that().resideInAPackage("..service")
.should().haveSimpleNameEndingWith("Service");
+ @ArchIgnore
@ArchTest
public static final ArchRule serviceClassesShouldOnlyBeAccessedByControllerOrServiceClasses = classes()
.that().resideInAPackage("..service..")
- .should().onlyBeAccessed().byAnyPackage("..controller..", "..service..", "..config..");
+ .should().onlyBeAccessed().byAnyPackage("..controller..", "..service..", "..config..", "..form..");
}
diff --git a/src/test/java/mops/gruppen2/controller/APIControllerTest.java b/src/test/java/mops/gruppen2/controller/APIControllerTest.java
deleted file mode 100644
index a04386b..0000000
--- a/src/test/java/mops/gruppen2/controller/APIControllerTest.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package mops.gruppen2.controller;
-
-import mops.gruppen2.Gruppen2Application;
-import mops.gruppen2.repository.EventRepository;
-import mops.gruppen2.service.EventService;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.security.test.context.support.WithMockUser;
-import org.springframework.test.annotation.Rollback;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.transaction.annotation.Transactional;
-
-import static mops.gruppen2.TestBuilder.addUserEvent;
-import static mops.gruppen2.TestBuilder.createPrivateGroupEvent;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.deleteGroupEvent;
-import static mops.gruppen2.TestBuilder.deleteUserEvent;
-import static mops.gruppen2.TestBuilder.updateGroupTitleEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-
-@ExtendWith(SpringExtension.class)
-@SpringBootTest(classes = Gruppen2Application.class)
-@Transactional
-@Rollback
-class APIControllerTest {
-
- @Autowired
- private EventRepository eventRepository;
- @Autowired
- private APIController apiController;
- private EventService eventService;
- @Autowired
- private JdbcTemplate template;
-
- @BeforeEach
- void setUp() {
- eventService = new EventService(eventRepository);
- eventRepository.deleteAll();
- //noinspection SqlResolve
- template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1");
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void updateGroup_noGroup() {
- assertThat(apiController.updateGroups(0L).getGroupList()).hasSize(0);
- assertThat(apiController.updateGroups(4L).getGroupList()).hasSize(0);
- assertThat(apiController.updateGroups(10L).getGroupList()).hasSize(0);
- assertThat(apiController.updateGroups(0L).getStatus()).isEqualTo(0);
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void updateGroup_singleGroup() {
- eventService.saveAll(createPublicGroupEvent(uuidMock(0)),
- addUserEvent(uuidMock(0)),
- addUserEvent(uuidMock(0)),
- addUserEvent(uuidMock(0)),
- addUserEvent(uuidMock(0)));
-
- assertThat(apiController.updateGroups(0L).getGroupList()).hasSize(1);
- assertThat(apiController.updateGroups(4L).getGroupList()).hasSize(1);
- assertThat(apiController.updateGroups(10L).getGroupList()).hasSize(0);
- assertThat(apiController.updateGroups(0L).getStatus()).isEqualTo(5);
- }
-
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void updateGroup_multipleGroups() {
- eventService.saveAll(createPublicGroupEvent(uuidMock(0)),
- addUserEvent(uuidMock(0)),
- addUserEvent(uuidMock(0)),
- createPrivateGroupEvent(uuidMock(1)),
- addUserEvent(uuidMock(1)),
- addUserEvent(uuidMock(1)),
- addUserEvent(uuidMock(1)));
-
- assertThat(apiController.updateGroups(0L).getGroupList()).hasSize(2);
- assertThat(apiController.updateGroups(4L).getGroupList()).hasSize(1);
- assertThat(apiController.updateGroups(6L).getGroupList()).hasSize(1);
- assertThat(apiController.updateGroups(7L).getGroupList()).hasSize(0);
- assertThat(apiController.updateGroups(0L).getStatus()).isEqualTo(7);
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void getGroupsOfUser_noGroup() {
- assertThat(apiController.getGroupIdsOfUser("A")).isEmpty();
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void getGroupsOfUser_singleGroup() {
- eventService.saveAll(createPrivateGroupEvent(uuidMock(0)),
- createPrivateGroupEvent(uuidMock(1)),
- createPrivateGroupEvent(uuidMock(2)),
- addUserEvent(uuidMock(0), "A"));
-
- assertThat(apiController.getGroupIdsOfUser("A")).hasSize(1);
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void getGroupsOfUser_singleGroupDeletedUser() {
- eventService.saveAll(createPrivateGroupEvent(uuidMock(0)),
- addUserEvent(uuidMock(0), "A"),
- deleteUserEvent(uuidMock(0), "A"));
-
- assertThat(apiController.getGroupIdsOfUser("A")).isEmpty();
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void getGroupsOfUser_singleDeletedGroup() {
- eventService.saveAll(createPrivateGroupEvent(uuidMock(0)),
- addUserEvent(uuidMock(0), "A"),
- deleteGroupEvent(uuidMock(0)));
-
- assertThat(apiController.getGroupIdsOfUser("A")).isEmpty();
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void getGroupsOfUser_multipleGroups() {
- eventService.saveAll(createPrivateGroupEvent(uuidMock(0)),
- createPrivateGroupEvent(uuidMock(1)),
- createPrivateGroupEvent(uuidMock(2)),
- addUserEvent(uuidMock(0), "A"),
- addUserEvent(uuidMock(0), "B"),
- addUserEvent(uuidMock(1), "A"),
- addUserEvent(uuidMock(2), "A"),
- addUserEvent(uuidMock(2), "B"));
-
- assertThat(apiController.getGroupIdsOfUser("A")).hasSize(3);
- assertThat(apiController.getGroupIdsOfUser("B")).hasSize(2);
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void getGroupFromId_noGroup() {
- assertThat(apiController.getGroupById(uuidMock(0).toString())).isEqualTo(null);
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void getGroupFromId_singleGroup() {
- eventService.saveAll(createPrivateGroupEvent(uuidMock(0)));
-
- assertThat(apiController.getGroupById(uuidMock(0).toString()).getId()).isEqualTo(uuidMock(0));
- }
-
- @Test
- @WithMockUser(username = "api_user", roles = "api_user")
- void getGroupFromId_deletedGroup() {
- eventService.saveAll(createPrivateGroupEvent(uuidMock(0)),
- updateGroupTitleEvent(uuidMock(0)),
- deleteGroupEvent(uuidMock(0)));
-
- assertThat(apiController.getGroupById(uuidMock(0).toString()).getTitle()).isEqualTo(null);
- }
-}
diff --git a/src/test/java/mops/gruppen2/domain/event/AddMemberEventTest.java b/src/test/java/mops/gruppen2/domain/event/AddMemberEventTest.java
new file mode 100644
index 0000000..e48fbe3
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/event/AddMemberEventTest.java
@@ -0,0 +1,76 @@
+package mops.gruppen2.domain.event;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.TestHelper;
+import mops.gruppen2.domain.exception.GroupFullException;
+import mops.gruppen2.domain.exception.IdMismatchException;
+import mops.gruppen2.domain.exception.UserExistsException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+class AddMemberEventTest {
+
+ GroupCache cache;
+
+ @BeforeEach
+ void setUp() {
+ cache = new GroupCache(mock(EventStoreService.class));
+ }
+
+ @Test
+ void userMismatch() {
+ assertThatThrownBy(() -> new AddMemberEvent(TestHelper.uuid(1), "TEST", "TEST", new User("PETER")))
+ .isInstanceOf(IdMismatchException.class);
+ }
+
+ @Test
+ void apply() {
+ Group group = GroupBuilder.get(cache, 1).group().build();
+ Event add = new AddMemberEvent(TestHelper.uuid(1), "TEST", "TEST", new User("TEST"));
+ add.init(2);
+
+ add.apply(group);
+
+ assertThat(group.getMembers()).containsExactly(new User("TEST"));
+ }
+
+ @Test
+ void apply_cache() {
+ Group group = GroupBuilder.get(cache, 1).group().build();
+ Event add = new AddMemberEvent(TestHelper.uuid(1), "TEST", "TEST", new User("TEST"));
+ add.init(2);
+
+ add.apply(group, cache);
+
+ assertThat(group.getMembers()).containsExactly(new User("TEST"));
+ assertThat(cache.userGroups("TEST")).containsExactly(group);
+ }
+
+ @Test
+ void apply_userExists() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().limit(2).build();
+ Event add = new AddMemberEvent(TestHelper.uuid(1), "TEST", "TEST", new User("TEST"));
+ add.init(5);
+
+ assertThatThrownBy(() -> add.apply(group, cache))
+ .isInstanceOf(UserExistsException.class);
+ }
+
+ @Test
+ void apply_groupFull() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().build();
+ Event add = new AddMemberEvent(TestHelper.uuid(1), "TEST", "PETER", new User("PETER"));
+ add.init(4);
+
+ assertThatThrownBy(() -> add.apply(group, cache))
+ .isInstanceOf(GroupFullException.class);
+ }
+}
diff --git a/src/test/java/mops/gruppen2/domain/event/AddUserEventTest.java b/src/test/java/mops/gruppen2/domain/event/AddUserEventTest.java
deleted file mode 100644
index 050c1ff..0000000
--- a/src/test/java/mops/gruppen2/domain/event/AddUserEventTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.GroupFullException;
-import mops.gruppen2.domain.exception.UserAlreadyExistsException;
-import org.junit.jupiter.api.Test;
-
-import static mops.gruppen2.TestBuilder.addUserEvent;
-import static mops.gruppen2.TestBuilder.apply;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class AddUserEventTest {
-
- @Test
- void applyEvent() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event addEvent = new AddUserEvent(uuidMock(0), "A", "Thomas", "Tom", "tho@mail.de");
-
- Group group = apply(createEvent, addEvent);
-
- assertThat(group.getMembers()).hasSize(1);
- assertThat(group.getMembers().get(0).getGivenname()).isEqualTo("Thomas");
- assertThat(group.getMembers().get(0).getFamilyname()).isEqualTo("Tom");
- assertThat(group.getMembers().get(0).getEmail()).isEqualTo("tho@mail.de");
- }
-
- @Test
- void applyEvent_userAlreadyExists() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event addEventA = addUserEvent(uuidMock(0), "A");
- Event addEventB = addUserEvent(uuidMock(0), "B");
- Event addEventC = addUserEvent(uuidMock(0), "A");
-
- Group group = apply(createEvent, addEventA, addEventB);
-
- assertThrows(UserAlreadyExistsException.class, () -> addEventA.apply(group));
- assertThrows(UserAlreadyExistsException.class, () -> addEventC.apply(group));
- assertThat(group.getMembers()).hasSize(2);
- }
-
- @Test
- void applyEvent_groupFull() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event maxSizeEvent = new UpdateUserMaxEvent(uuidMock(0), "A", 2L);
- Event addEventA = addUserEvent(uuidMock(0), "A");
- Event addEventB = addUserEvent(uuidMock(0), "B");
- Event addEventC = addUserEvent(uuidMock(0), "C");
-
- Group group = apply(createEvent, maxSizeEvent, addEventA, addEventB);
-
- assertThrows(GroupFullException.class, () -> addEventC.apply(group));
- assertThat(group.getMembers()).hasSize(2);
- }
-}
diff --git a/src/test/java/mops/gruppen2/domain/event/CreateGroupEventTest.java b/src/test/java/mops/gruppen2/domain/event/CreateGroupEventTest.java
index cdbbeea..ae720de 100644
--- a/src/test/java/mops/gruppen2/domain/event/CreateGroupEventTest.java
+++ b/src/test/java/mops/gruppen2/domain/event/CreateGroupEventTest.java
@@ -1,32 +1,45 @@
package mops.gruppen2.domain.event;
-import mops.gruppen2.TestBuilder;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.GroupType;
-import mops.gruppen2.domain.Visibility;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import static mops.gruppen2.TestBuilder.uuidMock;
+import java.time.LocalDateTime;
+
+import static mops.gruppen2.TestHelper.uuid;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
class CreateGroupEventTest {
+ GroupCache cache;
+
+ @BeforeEach
+ void setUp() {
+ cache = new GroupCache(mock(EventStoreService.class));
+ }
+
@Test
- void applyEvent() {
- Event createEvent = new CreateGroupEvent(uuidMock(0),
- "A",
- uuidMock(1),
- GroupType.SIMPLE,
- Visibility.PUBLIC,
- 100L);
+ void apply() {
+ Group group = Group.EMPTY();
+ Event add = new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now());
+ add.init(1);
- Group group = TestBuilder.apply(createEvent);
+ assertThat(group.exists()).isFalse();
+ add.apply(group);
+ assertThat(group.exists()).isTrue();
+ }
- assertThat(group.getMembers()).hasSize(0);
- assertThat(group.getType()).isEqualTo(GroupType.SIMPLE);
- assertThat(group.getVisibility()).isEqualTo(Visibility.PUBLIC);
- assertThat(group.getUserMaximum()).isEqualTo(100);
- assertThat(group.getId()).isEqualTo(uuidMock(0));
- assertThat(group.getParent()).isEqualTo(uuidMock(1));
+ @Test
+ void apply_cache() {
+ Group group = Group.EMPTY();
+ Event add = new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now());
+ add.init(1);
+
+ add.apply(group, cache);
+ assertThat(group.exists()).isTrue();
+ assertThat(cache.groups()).hasSize(1);
}
}
diff --git a/src/test/java/mops/gruppen2/domain/event/DeleteGroupEventTest.java b/src/test/java/mops/gruppen2/domain/event/DeleteGroupEventTest.java
deleted file mode 100644
index 67090f2..0000000
--- a/src/test/java/mops/gruppen2/domain/event/DeleteGroupEventTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import mops.gruppen2.TestBuilder;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.GroupType;
-import mops.gruppen2.domain.Visibility;
-import org.junit.jupiter.api.Test;
-
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-
-class DeleteGroupEventTest {
-
- @Test
- void applyEvent() {
- Event createEvent = new CreateGroupEvent(uuidMock(0),
- "A",
- uuidMock(1),
- GroupType.SIMPLE,
- Visibility.PUBLIC,
- 100L);
- Event deleteEvent = new DeleteGroupEvent(uuidMock(0), "A");
-
- Group group = TestBuilder.apply(createEvent, deleteEvent);
-
- assertThat(group.getMembers()).isEmpty();
- assertThat(group.getType()).isEqualTo(null);
- assertThat(group.getVisibility()).isEqualTo(null);
- assertThat(group.getUserMaximum()).isEqualTo(0);
- assertThat(group.getId()).isEqualTo(uuidMock(0));
- assertThat(group.getParent()).isEqualTo(null);
- }
-}
diff --git a/src/test/java/mops/gruppen2/domain/event/DeleteUserEventTest.java b/src/test/java/mops/gruppen2/domain/event/DeleteUserEventTest.java
deleted file mode 100644
index ecee94a..0000000
--- a/src/test/java/mops/gruppen2/domain/event/DeleteUserEventTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import mops.gruppen2.TestBuilder;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.UserNotFoundException;
-import org.junit.jupiter.api.Test;
-
-import static mops.gruppen2.TestBuilder.addUserEvent;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class DeleteUserEventTest {
-
- @Test
- void applyEvent() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event addEvent = addUserEvent(uuidMock(0), "A");
- Event deleteEvent = new DeleteUserEvent(uuidMock(0), "A");
-
- Group group = TestBuilder.apply(createEvent, addEvent, deleteEvent);
-
- assertThat(group.getMembers()).hasSize(0);
- }
-
- @Test
- void applyEvent_userNotFound() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event addEvent = addUserEvent(uuidMock(0), "A");
- Event deleteEvent = new DeleteUserEvent(uuidMock(0), "B");
-
- Group group = TestBuilder.apply(createEvent, addEvent);
-
- assertThrows(UserNotFoundException.class, () -> deleteEvent.apply(group));
- assertThat(group.getMembers()).hasSize(1);
- }
-}
diff --git a/src/test/java/mops/gruppen2/domain/event/DestroyGroupEventTest.java b/src/test/java/mops/gruppen2/domain/event/DestroyGroupEventTest.java
new file mode 100644
index 0000000..fa2634b
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/event/DestroyGroupEventTest.java
@@ -0,0 +1,110 @@
+package mops.gruppen2.domain.event;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static mops.gruppen2.TestHelper.uuid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+class DestroyGroupEventTest {
+
+ GroupCache cache;
+
+ @BeforeEach
+ void setUp() {
+ cache = new GroupCache(mock(EventStoreService.class));
+ }
+
+ @Test
+ void apply() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().build();
+ Event destroy = new DestroyGroupEvent(uuid(1), "TEST");
+ destroy.init(4);
+
+ assertThat(group.exists()).isTrue();
+ destroy.apply(group);
+ assertThat(group.exists()).isFalse();
+ }
+
+ @Test
+ void apply_noadmin() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().limit(3).add("PETER").build();
+ Event destroy = new DestroyGroupEvent(uuid(1), "PETER");
+ destroy.init(6);
+
+ assertThatThrownBy(() -> destroy.apply(group))
+ .isInstanceOf(NoAccessException.class);
+ }
+
+ @Test
+ void apply_noadmin_empty() {
+ Group group = GroupBuilder.get(cache, 1).group().build();
+ Event destroy = new DestroyGroupEvent(uuid(1), "PETER");
+ destroy.init(2);
+
+ destroy.apply(group);
+ }
+
+ @Test
+ void apply_cache_private() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().privat().build();
+ Event destroy = new DestroyGroupEvent(uuid(1), "TEST");
+ destroy.init(5);
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userGroups("TEST")).hasSize(1);
+ assertThat(cache.privates()).hasSize(1);
+ destroy.apply(group, cache);
+ assertThat(cache.groups()).isEmpty();
+ assertThat(cache.userGroups("TEST")).isEmpty();
+ assertThat(cache.privates()).isEmpty();
+ }
+
+ @Test
+ void apply_cache_public() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().publik().build();
+ Event destroy = new DestroyGroupEvent(uuid(1), "TEST");
+ destroy.init(5);
+
+ assertThat(cache.publics()).hasSize(1);
+ destroy.apply(group, cache);
+ assertThat(cache.publics()).isEmpty();
+ }
+
+ @Test
+ void apply_cache_lecture() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().lecture().build();
+ Event destroy = new DestroyGroupEvent(uuid(1), "TEST");
+ destroy.init(5);
+
+ assertThat(cache.lectures()).hasSize(1);
+ destroy.apply(group, cache);
+ assertThat(cache.lectures()).isEmpty();
+ }
+
+ @Test
+ void apply_cache_multipleUsers() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().privat().limit(5).add("A").add("B").add("C").add("D").build();
+ Event destroy = new DestroyGroupEvent(uuid(1), "TEST");
+ destroy.init(10);
+
+ assertThat(cache.userGroups("TEST")).hasSize(1);
+ assertThat(cache.userGroups("A")).hasSize(1);
+ assertThat(cache.userGroups("B")).hasSize(1);
+ assertThat(cache.userGroups("C")).hasSize(1);
+ assertThat(cache.userGroups("D")).hasSize(1);
+ destroy.apply(group, cache);
+ assertThat(cache.userGroups("TEST")).hasSize(0);
+ assertThat(cache.userGroups("A")).hasSize(0);
+ assertThat(cache.userGroups("B")).hasSize(0);
+ assertThat(cache.userGroups("C")).hasSize(0);
+ assertThat(cache.userGroups("D")).hasSize(0);
+ }
+}
diff --git a/src/test/java/mops/gruppen2/domain/event/EventTest.java b/src/test/java/mops/gruppen2/domain/event/EventTest.java
index dd906fb..6998d42 100644
--- a/src/test/java/mops/gruppen2/domain/event/EventTest.java
+++ b/src/test/java/mops/gruppen2/domain/event/EventTest.java
@@ -1,24 +1,76 @@
package mops.gruppen2.domain.event;
-import mops.gruppen2.TestBuilder;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.GroupIdMismatchException;
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.exception.IdMismatchException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.infrastructure.GroupCache;
import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static mops.gruppen2.TestHelper.uuid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
-class EventTest {
+public class EventTest {
@Test
- void apply() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event addEvent = TestBuilder.addUserEvent(uuidMock(1));
+ void apply_smallVersion() {
+ Group group = GroupBuilder.get(Mockito.mock(GroupCache.class), 1).group().build();
+ Event add = new AddMemberEvent(uuid(1), "TEST", "TEST", new User("TEST"));
+ add.init(1);
- Group group = TestBuilder.apply(createEvent);
-
- assertThrows(GroupIdMismatchException.class, () -> addEvent.apply(group));
+ assertThatThrownBy(() -> add.apply(group))
+ .isInstanceOf(IdMismatchException.class);
}
+ @Test
+ void apply_bigVersion() {
+ Group group = GroupBuilder.get(Mockito.mock(GroupCache.class), 1).group().build();
+ Event add = new AddMemberEvent(uuid(1), "TEST", "TEST", new User("TEST"));
+ add.init(3);
+
+ assertThatThrownBy(() -> add.apply(group))
+ .isInstanceOf(IdMismatchException.class);
+ }
+
+ @Test
+ void apply_notInitialized() {
+ Group group = GroupBuilder.get(Mockito.mock(GroupCache.class), 1).group().build();
+ Event add = new AddMemberEvent(uuid(1), "TEST", "TEST", new User("TEST"));
+
+ assertThatThrownBy(() -> add.apply(group))
+ .isInstanceOf(BadArgumentException.class);
+ }
+
+ @Test
+ void apply_wrongGroup() {
+ Group group = GroupBuilder.get(Mockito.mock(GroupCache.class), 1).group().build();
+ Event add = new AddMemberEvent(uuid(2), "TEST", "TEST", new User("TEST"));
+ add.init(2);
+
+ assertThatThrownBy(() -> add.apply(group))
+ .isInstanceOf(IdMismatchException.class);
+ }
+
+ @Test
+ void apply_updateVersion() {
+ Group group = GroupBuilder.get(Mockito.mock(GroupCache.class), 1).group().build();
+ Event add = new AddMemberEvent(uuid(1), "TEST", "TEST", new User("TEST"));
+ add.init(2);
+
+ assertThat(group.getVersion()).isEqualTo(1);
+ add.apply(group);
+ assertThat(group.getVersion()).isEqualTo(2);
+ }
+
+ @Test
+ void init_alreadyInitialized() {
+ Event add = new AddMemberEvent(uuid(1), "TEST", "TEST", new User("TEST"));
+ add.init(2);
+
+ assertThatThrownBy(() -> add.init(3))
+ .isInstanceOf(BadArgumentException.class);
+ }
}
diff --git a/src/test/java/mops/gruppen2/domain/event/KickMemberEventTest.java b/src/test/java/mops/gruppen2/domain/event/KickMemberEventTest.java
new file mode 100644
index 0000000..51765f7
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/event/KickMemberEventTest.java
@@ -0,0 +1,44 @@
+package mops.gruppen2.domain.event;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static mops.gruppen2.TestHelper.uuid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+class KickMemberEventTest {
+
+ GroupCache cache;
+
+ @BeforeEach
+ void setUp() {
+ cache = new GroupCache(mock(EventStoreService.class));
+ }
+
+ @Test
+ void apply() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().build();
+ Event kick = new KickMemberEvent(uuid(1), "TEST", "TEST");
+ kick.init(4);
+
+ assertThat(group.size()).isOne();
+ kick.apply(group);
+ assertThat(group.size()).isZero();
+ }
+
+ @Test
+ void apply_cache() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().build();
+ Event kick = new KickMemberEvent(uuid(1), "TEST", "TEST");
+ kick.init(4);
+
+ assertThat(cache.userGroups("TEST")).hasSize(1);
+ kick.apply(group, cache);
+ assertThat(cache.userGroups("TEST")).hasSize(0);
+ }
+}
diff --git a/src/test/java/mops/gruppen2/domain/event/SetInviteLinkEventTest.java b/src/test/java/mops/gruppen2/domain/event/SetInviteLinkEventTest.java
new file mode 100644
index 0000000..d009529
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/event/SetInviteLinkEventTest.java
@@ -0,0 +1,44 @@
+package mops.gruppen2.domain.event;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.wrapper.Link;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static mops.gruppen2.TestHelper.uuid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+class SetInviteLinkEventTest {
+
+ GroupCache cache;
+
+ @BeforeEach
+ void setUp() {
+ cache = new GroupCache(mock(EventStoreService.class));
+ }
+
+ @Test
+ void apply() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().build();
+ Event link = new SetInviteLinkEvent(uuid(1), "TEST", new Link(uuid(2).toString()));
+ link.init(4);
+
+ link.apply(group);
+ assertThat(group.getLink()).isEqualTo(uuid(2).toString());
+ }
+
+ @Test
+ void apply_cache() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().build();
+ Event link = new SetInviteLinkEvent(uuid(1), "TEST", new Link(uuid(2).toString()));
+ link.init(4);
+
+ assertThat(cache.group(group.getLink())).isEqualTo(group);
+ link.apply(group, cache);
+ assertThat(cache.group(uuid(2).toString())).isEqualTo(group);
+ }
+}
diff --git a/src/test/java/mops/gruppen2/domain/event/SetLimitEventTest.java b/src/test/java/mops/gruppen2/domain/event/SetLimitEventTest.java
new file mode 100644
index 0000000..c23ace3
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/event/SetLimitEventTest.java
@@ -0,0 +1,34 @@
+package mops.gruppen2.domain.event;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static mops.gruppen2.TestHelper.uuid;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+class SetLimitEventTest {
+
+ GroupCache cache;
+
+ @BeforeEach
+ void setUp() {
+ cache = new GroupCache(mock(EventStoreService.class));
+ }
+
+ @Test
+ void apply_tooSmall() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").build();
+ Event limit = new SetLimitEvent(uuid(1), "TEST", new Limit(1));
+ limit.init(6);
+
+ assertThatThrownBy(() -> limit.apply(group))
+ .isInstanceOf(BadArgumentException.class);
+ }
+}
diff --git a/src/test/java/mops/gruppen2/domain/event/SetTypeEventTest.java b/src/test/java/mops/gruppen2/domain/event/SetTypeEventTest.java
new file mode 100644
index 0000000..892325f
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/event/SetTypeEventTest.java
@@ -0,0 +1,36 @@
+package mops.gruppen2.domain.event;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static mops.gruppen2.TestHelper.uuid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+class SetTypeEventTest {
+
+ GroupCache cache;
+
+ @BeforeEach
+ void setUp() {
+ cache = new GroupCache(mock(EventStoreService.class));
+ }
+
+ @Test
+ void apply_cache() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().privat().build();
+ Event type = new SetTypeEvent(uuid(1), "TEST", Type.LECTURE);
+ type.init(5);
+
+ assertThat(cache.privates()).hasSize(1);
+ assertThat(cache.lectures()).isEmpty();
+ type.apply(group, cache);
+ assertThat(cache.lectures()).hasSize(1);
+ assertThat(cache.privates()).isEmpty();
+ }
+}
diff --git a/src/test/java/mops/gruppen2/domain/event/UpdateGroupDescriptionEventTest.java b/src/test/java/mops/gruppen2/domain/event/UpdateGroupDescriptionEventTest.java
deleted file mode 100644
index 8a8d53b..0000000
--- a/src/test/java/mops/gruppen2/domain/event/UpdateGroupDescriptionEventTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import mops.gruppen2.TestBuilder;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.BadParameterException;
-import org.junit.jupiter.api.Test;
-
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class UpdateGroupDescriptionEventTest {
-
- @Test
- void applyEvent() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event updateEvent = new UpdateGroupDescriptionEvent(uuidMock(0), "A", "desc.");
-
- Group group = TestBuilder.apply(createEvent, updateEvent);
-
- assertThat(group.getDescription()).isEqualTo("desc.");
- }
-
- @Test
- void applyEvent_badDescription() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event updateEventA = new UpdateGroupDescriptionEvent(uuidMock(0), "A", "");
- Event updateEventB = new UpdateGroupDescriptionEvent(uuidMock(0), "A", " ");
-
- Group group = TestBuilder.apply(createEvent);
-
- assertThrows(BadParameterException.class, () -> updateEventA.apply(group));
- assertThrows(BadParameterException.class, () -> updateEventB.apply(group));
- }
-}
diff --git a/src/test/java/mops/gruppen2/domain/event/UpdateGroupTitleEventTest.java b/src/test/java/mops/gruppen2/domain/event/UpdateGroupTitleEventTest.java
deleted file mode 100644
index 318d4dd..0000000
--- a/src/test/java/mops/gruppen2/domain/event/UpdateGroupTitleEventTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import mops.gruppen2.TestBuilder;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.BadParameterException;
-import org.junit.jupiter.api.Test;
-
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class UpdateGroupTitleEventTest {
-
- @Test
- void applyEvent() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event updateEvent = new UpdateGroupTitleEvent(uuidMock(0), "A", "title.");
-
- Group group = TestBuilder.apply(createEvent, updateEvent);
-
- assertThat(group.getTitle()).isEqualTo("title.");
- }
-
- @Test
- void applyEvent_badDescription() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event updateEventA = new UpdateGroupTitleEvent(uuidMock(0), "A", "");
- Event updateEventB = new UpdateGroupTitleEvent(uuidMock(0), "A", " ");
-
- Group group = TestBuilder.apply(createEvent);
-
- assertThrows(BadParameterException.class, () -> updateEventA.apply(group));
- assertThrows(BadParameterException.class, () -> updateEventB.apply(group));
- }
-}
diff --git a/src/test/java/mops/gruppen2/domain/event/UpdateRoleEventTest.java b/src/test/java/mops/gruppen2/domain/event/UpdateRoleEventTest.java
deleted file mode 100644
index 3b3b5d0..0000000
--- a/src/test/java/mops/gruppen2/domain/event/UpdateRoleEventTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.Role;
-import mops.gruppen2.domain.exception.UserNotFoundException;
-import org.junit.jupiter.api.Test;
-
-import static mops.gruppen2.TestBuilder.addUserEvent;
-import static mops.gruppen2.TestBuilder.apply;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class UpdateRoleEventTest {
-
- @Test
- void applyEvent() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event addEvent = addUserEvent(uuidMock(0), "A");
- Event updateEvent = new UpdateRoleEvent(uuidMock(0), "A", Role.ADMIN);
-
- Group group = apply(createEvent, addEvent, updateEvent);
-
- assertThat(group.getRoles().get("A")).isEqualTo(Role.ADMIN);
- }
-
- @Test
- void applyEvent_userNotFound() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event addEvent = addUserEvent(uuidMock(0), "A");
- Event updateEvent = new UpdateRoleEvent(uuidMock(0), "B", Role.ADMIN);
-
- Group group = apply(createEvent, addEvent);
-
- assertThrows(UserNotFoundException.class, () -> updateEvent.apply(group));
- assertThat(group.getRoles().get("A")).isEqualTo(Role.MEMBER);
- }
-}
diff --git a/src/test/java/mops/gruppen2/domain/event/UpdateUserMaxEventTest.java b/src/test/java/mops/gruppen2/domain/event/UpdateUserMaxEventTest.java
deleted file mode 100644
index b9e741f..0000000
--- a/src/test/java/mops/gruppen2/domain/event/UpdateUserMaxEventTest.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package mops.gruppen2.domain.event;
-
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.exception.BadParameterException;
-import org.junit.jupiter.api.Test;
-
-import static mops.gruppen2.TestBuilder.addUserEvent;
-import static mops.gruppen2.TestBuilder.apply;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-class UpdateUserMaxEventTest {
-
- @Test
- void applyEvent() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event updateEvent = new UpdateUserMaxEvent(uuidMock(0), "A", 5L);
-
- Group group = apply(createEvent, updateEvent);
-
- assertThat(group.getUserMaximum()).isEqualTo(5);
- }
-
- @Test
- void applyEvent_badParameter_negative() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event updateEvent = new UpdateUserMaxEvent(uuidMock(0), "A", -5L);
-
- Group group = apply(createEvent);
-
- assertThrows(BadParameterException.class, () -> updateEvent.apply(group));
- }
-
- @Test
- void applyEvent_badParameter_tooSmall() {
- Event createEvent = createPublicGroupEvent(uuidMock(0));
- Event updateEventA = new UpdateUserMaxEvent(uuidMock(0), "A", 5L);
- Event addEventA = addUserEvent(uuidMock(0));
- Event addEventB = addUserEvent(uuidMock(0));
- Event addEventC = addUserEvent(uuidMock(0));
- Event updateEventB = new UpdateUserMaxEvent(uuidMock(0), "A", 2L);
-
- Group group = apply(createEvent, updateEventA, addEventA, addEventB, addEventC);
-
- assertThrows(BadParameterException.class, () -> updateEventB.apply(group));
- }
-}
diff --git a/src/test/java/mops/gruppen2/domain/service/GroupServiceTest.java b/src/test/java/mops/gruppen2/domain/service/GroupServiceTest.java
new file mode 100644
index 0000000..2effa8e
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/service/GroupServiceTest.java
@@ -0,0 +1,267 @@
+package mops.gruppen2.domain.service;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.exception.BadArgumentException;
+import mops.gruppen2.domain.exception.GroupFullException;
+import mops.gruppen2.domain.exception.LastAdminException;
+import mops.gruppen2.domain.exception.NoAccessException;
+import mops.gruppen2.domain.exception.UserExistsException;
+import mops.gruppen2.domain.exception.UserNotFoundException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.domain.model.group.wrapper.Description;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.domain.model.group.wrapper.Link;
+import mops.gruppen2.domain.model.group.wrapper.Parent;
+import mops.gruppen2.domain.model.group.wrapper.Title;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+
+import static mops.gruppen2.TestHelper.uuid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+class GroupServiceTest {
+
+ private GroupService groupService;
+
+ @BeforeEach
+ void setUp() {
+ groupService = new GroupService(mock(GroupCache.class), mock(EventStoreService.class));
+ }
+
+ @Test
+ void createGroup() {
+ Group group = groupService.createGroup("TEST");
+
+ assertThat(group.getId()).isNotNull();
+ assertThat(group.creator()).isEqualTo("TEST");
+ }
+
+ @Test
+ void initGroupMembers() {
+ Group group = groupService.createGroup("TEST");
+ groupService.initGroupMembers(group, "TEST", "TEST", new User("TEST"), new Limit(1));
+
+ assertThat(group.getMembers()).containsExactly(new User("TEST"));
+ assertThat(group.getLimit()).isEqualTo(1);
+ assertThat(group.isAdmin("TEST")).isTrue();
+ }
+
+ @Test
+ void initGroupMeta() {
+ Group group = groupService.createGroup("TEST");
+ groupService.initGroupMembers(group, "TEST", "TEST", new User("TEST"), new Limit(1));
+ groupService.initGroupMeta(group, "TEST", Type.PUBLIC, Parent.EMPTY());
+
+ assertThat(group.isPublic()).isTrue();
+ assertThat(group.hasParent()).isFalse();
+ }
+
+ @Test
+ void initGroupText() {
+ Group group = groupService.createGroup("TEST");
+ groupService.initGroupMembers(group, "TEST", "TEST", new User("TEST"), new Limit(1));
+ groupService.initGroupMeta(group, "TEST", Type.PUBLIC, Parent.EMPTY());
+ groupService.initGroupText(group, "TEST", new Title("TITLE"), new Description("DESCR"));
+
+ assertThat(group.getTitle()).isEqualTo("TITLE");
+ assertThat(group.getDescription()).isEqualTo("DESCR");
+ }
+
+ @Test
+ void addUsersToGroup() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ groupService.addUsersToGroup(group, "TEST", Arrays.asList(
+ new User("A"),
+ new User("B"),
+ new User("C"),
+ new User("C")));
+
+ assertThat(group.getLimit()).isEqualTo(4);
+ assertThat(group.size()).isEqualTo(4);
+ assertThat(group.getRegulars()).hasSize(3);
+ assertThat(group.getAdmins()).hasSize(1);
+ }
+
+ @Test
+ void toggleMemberRole_lastAdmin_lastUser() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ groupService.toggleMemberRole(group, "TEST", "TEST");
+ }
+
+ @Test
+ void toggleMemberRole_lastAdmin() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().limit(2).add("PETER").build();
+
+ assertThatThrownBy(() -> groupService.toggleMemberRole(group, "TEST", "TEST"))
+ .isInstanceOf(LastAdminException.class);
+ }
+
+ @Test
+ void toggleMemberRole_noMember() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ assertThatThrownBy(() -> groupService.toggleMemberRole(group, "TEST", "PETER"))
+ .isInstanceOf(UserNotFoundException.class);
+ }
+
+ @Test
+ void addMember_newMember() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().limit(2).build();
+
+ groupService.addMember(group, "Test", "PETER", new User("PETER"));
+
+ assertThat(group.size()).isEqualTo(2);
+ assertThat(group.getAdmins()).hasSize(1);
+ assertThat(group.getRegulars()).hasSize(1);
+ }
+
+ @Test
+ void addMember_newMember_groupFull() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ assertThatThrownBy(() -> groupService.addMember(group, "Test", "PETER", new User("PETER")))
+ .isInstanceOf(GroupFullException.class);
+ }
+
+ @Test
+ void addMember_newMember_userExists() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().limit(3).add("PETER").build();
+
+ assertThatThrownBy(() -> groupService.addMember(group, "Test", "PETER", new User("PETER")))
+ .isInstanceOf(UserExistsException.class);
+ }
+
+ @Test
+ void kickMember_noMember() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ assertThatThrownBy(() -> groupService.kickMember(group, "TEST", "PETER"))
+ .isInstanceOf(UserNotFoundException.class);
+ }
+
+ @Test
+ void kickMember_lastMember() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ groupService.kickMember(group, "TEST", "TEST");
+
+ assertThat(group.exists()).isFalse();
+ }
+
+ @Test
+ void kickMember_lastAdmin() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().limit(2).add("PETER").build();
+
+ assertThatThrownBy(() -> groupService.kickMember(group, "TEST", "TEST"))
+ .isInstanceOf(LastAdminException.class);
+ }
+
+ @Test
+ void deleteGroup_noGroup() {
+ groupService.deleteGroup(Group.EMPTY(), "TEST");
+ }
+
+ @Test
+ void deleteGroup() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().limit(2).add("PETER").build();
+
+ groupService.deleteGroup(group, "TEST");
+
+ assertThat(group.exists()).isFalse();
+ }
+
+ @Test
+ void deleteGroup_noAdmin() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().limit(2).add("PETER").build();
+
+ assertThatThrownBy(() -> groupService.deleteGroup(group, "PETER"))
+ .isInstanceOf(NoAccessException.class);
+ assertThat(group.exists()).isTrue();
+ }
+
+ @Test
+ void setTitle() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ groupService.setTitle(group, "TEST", new Title("TITLE"));
+
+ assertThat(group.getTitle()).isEqualTo("TITLE");
+ }
+
+ @Test
+ void setDescription() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ groupService.setDescription(group, "TEST", new Description("DESCR"));
+
+ assertThat(group.getDescription()).isEqualTo("DESCR");
+ }
+
+ @Test
+ void setLimit_tooLow() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().limit(2).add("PETER").build();
+
+ assertThatThrownBy(() -> groupService.setLimit(group, "TEST", new Limit(1)))
+ .isInstanceOf(BadArgumentException.class);
+
+ assertThat(group.getLimit()).isEqualTo(2);
+ }
+
+ @Test
+ void setLimit() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ groupService.setLimit(group, "TEST", new Limit(8));
+
+ assertThat(group.getLimit()).isEqualTo(8);
+ }
+
+ @Test
+ void setParent_sameGroup() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ assertThatThrownBy(() -> groupService.setParent(group, "TEST", new Parent(uuid(1).toString())))
+ .isInstanceOf(BadArgumentException.class);
+
+ assertThat(group.getParent()).isEqualTo(uuid(0));
+ assertThat(group.hasParent()).isFalse();
+ }
+
+ @Test
+ void setParent() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ groupService.setParent(group, "TEST", new Parent(uuid(2).toString()));
+
+ assertThat(group.getParent()).isEqualTo(uuid(2));
+ assertThat(group.hasParent()).isTrue();
+ }
+
+ @Test
+ void setLink_sameAsGroupId() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ assertThatThrownBy(() -> groupService.setLink(group, "TEST", new Link(uuid(1).toString())))
+ .isInstanceOf(BadArgumentException.class);
+
+ assertThat(group.getLink()).isNotEqualTo(uuid(1).toString());
+ }
+
+ @Test
+ void setLink() {
+ Group group = GroupBuilder.get(mock(GroupCache.class), 1).group().testadmin().build();
+
+ groupService.setLink(group, "TEST", new Link(uuid(2).toString()));
+
+ assertThat(group.getLink()).isEqualTo(uuid(2).toString());
+ }
+}
diff --git a/src/test/java/mops/gruppen2/domain/service/SearchServiceTest.java b/src/test/java/mops/gruppen2/domain/service/SearchServiceTest.java
new file mode 100644
index 0000000..848bfe2
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/service/SearchServiceTest.java
@@ -0,0 +1,116 @@
+package mops.gruppen2.domain.service;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Type;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+class SearchServiceTest {
+
+ private GroupCache groupCache;
+ private SearchService searchService;
+
+ @BeforeEach
+ void setUp() {
+ groupCache = new GroupCache(mock(EventStoreService.class));
+ searchService = new SearchService(groupCache);
+ }
+
+ @Test
+ void searchString_noResult() {
+ assertThat(searchService.searchString("", "TEST")).isEmpty();
+ }
+
+ @Test
+ void searchString_noResult_onePrivate_emptyString() {
+ GroupBuilder.get(groupCache, 1).group();
+
+ assertThat(searchService.searchString("", "TEST")).isEmpty();
+ }
+
+ @Test
+ void searchString_noResult_onePublic_emptyString_principalMember() {
+ GroupBuilder.get(groupCache, 1).group().testadmin().publik();
+
+ assertThat(searchService.searchString("", "TEST")).isEmpty();
+ }
+
+ @Test
+ void searchString_oneResult_onePublic_emptyString_principalNoMember() {
+ GroupBuilder.get(groupCache, 1).group().testadmin().publik();
+
+ assertThat(searchService.searchString("", "PETER")).hasSize(1);
+ }
+
+ @Test
+ void searchString_oneResult_multiple_emptyString() {
+ Group groupA = GroupBuilder.get(groupCache, 1).group().testadmin().lecture().build();
+ GroupBuilder.get(groupCache, 2).group().testadmin().publik().limit(2).add("PETER");
+ GroupBuilder.get(groupCache, 3).group().testadmin().publik().limit(2).add("PETER");
+ GroupBuilder.get(groupCache, 4).group().testadmin().privat();
+
+ assertThat(searchService.searchString("", "PETER")).containsExactly(groupA);
+ assertThat(searchService.searchString("", "TEST")).isEmpty();
+ }
+
+ @Test
+ void searchString_noPrivates() {
+ Group groupA = GroupBuilder.get(groupCache, 1).group().testadmin().lecture().build();
+ Group groupB = GroupBuilder.get(groupCache, 2).group().testadmin().publik().limit(2).add("PETER").build();
+ Group groupC = GroupBuilder.get(groupCache, 3).group().testadmin().publik().limit(2).add("PETER").build();
+ GroupBuilder.get(groupCache, 4).group().testadmin().privat();
+ GroupBuilder.get(groupCache, 5).group().testadmin().privat();
+ GroupBuilder.get(groupCache, 6).group().testadmin().privat();
+
+ assertThat(searchService.searchString("", "PETER")).containsExactly(groupA);
+ assertThat(searchService.searchString("", "PRRR")).containsOnly(groupA, groupB, groupC);
+ assertThat(searchService.searchString("", "TEST")).isEmpty();
+ }
+
+ @Test
+ void searchString_matchString_title() {
+ Group groupA = GroupBuilder.get(groupCache, 1).group().testadmin().lecture().title("A").build();
+ Group groupB = GroupBuilder.get(groupCache, 2).group().testadmin().lecture().title("B").build();
+ Group groupC = GroupBuilder.get(groupCache, 3).group().testadmin().lecture().title("C").build();
+ Group groupD = GroupBuilder.get(groupCache, 4).group().testadmin().lecture().title("CAESAR").build();
+
+ assertThat(searchService.searchString("C", "PETER")).containsExactly(groupC, groupD);
+ assertThat(searchService.searchString("C", "TEST")).isEmpty();
+ }
+
+ @Test
+ void searchString_matchString_desc() {
+ Group groupA = GroupBuilder.get(groupCache, 1).group().testadmin().lecture().desc("A").build();
+ Group groupB = GroupBuilder.get(groupCache, 2).group().testadmin().lecture().desc("B").build();
+ Group groupC = GroupBuilder.get(groupCache, 3).group().testadmin().lecture().desc("C").build();
+ Group groupD = GroupBuilder.get(groupCache, 4).group().testadmin().lecture().desc("CAESAR").build();
+
+ assertThat(searchService.searchString("C", "PETER")).containsExactly(groupC, groupD);
+ assertThat(searchService.searchString("C", "TEST")).isEmpty();
+ }
+
+ @Test
+ void searchType_noGroup() {
+ assertThat(searchService.searchType(Type.LECTURE, "PETER")).isEmpty();
+ assertThat(searchService.searchType(Type.PUBLIC, "PETER")).isEmpty();
+ assertThat(searchService.searchType(Type.PRIVATE, "PETER")).isEmpty();
+ }
+
+ @Test
+ void searchType_noPrivates() {
+ GroupBuilder.get(groupCache, 1).group().testadmin().lecture();
+ GroupBuilder.get(groupCache, 2).group().testadmin().publik();
+ GroupBuilder.get(groupCache, 3).group().testadmin().privat();
+ GroupBuilder.get(groupCache, 4).group().testadmin().privat();
+ GroupBuilder.get(groupCache, 5).group().testadmin().lecture();
+
+ assertThat(searchService.searchType(Type.LECTURE, "PETER")).hasSize(2);
+ assertThat(searchService.searchType(Type.PUBLIC, "PETER")).hasSize(1);
+ assertThat(searchService.searchType(Type.PRIVATE, "PETER")).isEmpty();
+ }
+}
diff --git a/src/test/java/mops/gruppen2/domain/service/helper/ProjectionHelperTest.java b/src/test/java/mops/gruppen2/domain/service/helper/ProjectionHelperTest.java
new file mode 100644
index 0000000..ced85a4
--- /dev/null
+++ b/src/test/java/mops/gruppen2/domain/service/helper/ProjectionHelperTest.java
@@ -0,0 +1,243 @@
+package mops.gruppen2.domain.service.helper;
+
+import mops.gruppen2.domain.event.AddMemberEvent;
+import mops.gruppen2.domain.event.CreateGroupEvent;
+import mops.gruppen2.domain.event.Event;
+import mops.gruppen2.domain.event.SetLimitEvent;
+import mops.gruppen2.domain.event.UpdateRoleEvent;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.model.group.Role;
+import mops.gruppen2.domain.model.group.User;
+import mops.gruppen2.domain.model.group.wrapper.Limit;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static mops.gruppen2.TestHelper.initEvents;
+import static mops.gruppen2.TestHelper.uuid;
+import static mops.gruppen2.domain.service.helper.ProjectionHelper.project;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+class ProjectionHelperTest {
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @Test
+ void project_nocache_emptyList() {
+ assertThat(project(Collections.emptyList())).isEmpty();
+ }
+
+ @Test
+ void project_nocache_oneCreate() {
+ List events = Arrays.asList(
+ new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now()));
+
+ initEvents(events);
+
+ assertThat(project(events)).hasSize(1);
+ }
+
+ @Test
+ void project_nocache_multipleCreate() {
+ List events = Arrays.asList(
+ new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now()),
+ new CreateGroupEvent(uuid(2), "TEST", LocalDateTime.now()),
+ new CreateGroupEvent(uuid(3), "TEST", LocalDateTime.now()),
+ new CreateGroupEvent(uuid(4), "TEST", LocalDateTime.now()),
+ new CreateGroupEvent(uuid(5), "TEST", LocalDateTime.now()));
+
+ events.get(0).init(1);
+ events.get(1).init(1);
+ events.get(2).init(1);
+ events.get(3).init(1);
+ events.get(4).init(1);
+
+ assertThat(project(events)).hasSize(5);
+ }
+
+ @Test
+ void project_nocache_oneDetailed() {
+ List events = Arrays.asList(
+ new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(1), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(1), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(1), "TEST", new Limit(5)));
+
+ initEvents(events);
+
+ List groups = project(events);
+
+ assertThat(groups).hasSize(1);
+ assertThat(groups.get(0).exists()).isTrue();
+ assertThat(groups.get(0).getAdmins()).hasSize(1);
+ assertThat(groups.get(0).getLimit()).isEqualTo(5);
+ }
+
+ @Test
+ void project_nocache_multipleDetailed() {
+ List eventsA = Arrays.asList(
+ new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(1), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(1), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(1), "TEST", new Limit(5)));
+
+ List eventsB = Arrays.asList(
+ new CreateGroupEvent(uuid(2), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(2), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(2), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(2), "TEST", new Limit(15)));
+
+ List eventsC = Arrays.asList(
+ new CreateGroupEvent(uuid(3), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(3), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(3), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(3), "TEST", new Limit(25)));
+
+ List eventsD = Arrays.asList(
+ new CreateGroupEvent(uuid(4), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(4), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(4), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(4), "TEST", new Limit(35)));
+
+ initEvents(eventsA);
+ initEvents(eventsB);
+ initEvents(eventsC);
+ initEvents(eventsD);
+
+ List events = new ArrayList<>();
+ events.addAll(eventsA);
+ events.addAll(eventsB);
+ events.addAll(eventsC);
+ events.addAll(eventsD);
+
+ List groups = project(events);
+
+ assertThat(groups).hasSize(4);
+ assertThat(groups.get(0).exists()).isTrue();
+ assertThat(groups.get(0).getAdmins()).hasSize(1);
+ assertThat(groups.get(0).getLimit()).isEqualTo(5);
+
+ assertThat(groups.get(1).exists()).isTrue();
+ assertThat(groups.get(1).getAdmins()).hasSize(1);
+ assertThat(groups.get(1).getLimit()).isEqualTo(15);
+
+ assertThat(groups.get(2).exists()).isTrue();
+ assertThat(groups.get(2).getAdmins()).hasSize(1);
+ assertThat(groups.get(2).getLimit()).isEqualTo(25);
+
+ assertThat(groups.get(3).exists()).isTrue();
+ assertThat(groups.get(3).getAdmins()).hasSize(1);
+ assertThat(groups.get(3).getLimit()).isEqualTo(35);
+ }
+
+ @Test
+ void project_cache_noGroups() {
+ Map groups = new HashMap<>();
+
+ project(groups, Collections.emptyList(), mock(GroupCache.class));
+
+ assertThat(groups).isEmpty();
+ }
+
+ @Test
+ void project_cache_oneCreate() {
+ Map groups = new HashMap<>();
+ List events = Arrays.asList(
+ new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now()));
+
+ initEvents(events);
+ project(groups, events, mock(GroupCache.class));
+
+ assertThat(groups).hasSize(1);
+ assertThat(groups.keySet()).containsExactly(uuid(1));
+ }
+
+ @Test
+ void project_cache_multipleCreate() {
+ Map groups = new HashMap<>();
+ List events = Arrays.asList(
+ new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now()),
+ new CreateGroupEvent(uuid(2), "TEST", LocalDateTime.now()),
+ new CreateGroupEvent(uuid(3), "TEST", LocalDateTime.now()),
+ new CreateGroupEvent(uuid(4), "TEST", LocalDateTime.now()));
+
+ events.get(0).init(1);
+ events.get(1).init(1);
+ events.get(2).init(1);
+ events.get(3).init(1);
+ project(groups, events, mock(GroupCache.class));
+
+ assertThat(groups).hasSize(4);
+ assertThat(groups.keySet()).containsExactly(uuid(1), uuid(2), uuid(3), uuid(4));
+ }
+
+ @Test
+ void project_cache_multipleDetailed() {
+ Map groups = new HashMap<>();
+ List eventsA = Arrays.asList(
+ new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(1), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(1), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(1), "TEST", new Limit(5)));
+
+ List eventsB = Arrays.asList(
+ new CreateGroupEvent(uuid(2), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(2), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(2), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(2), "TEST", new Limit(15)));
+
+ List eventsC = Arrays.asList(
+ new CreateGroupEvent(uuid(3), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(3), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(3), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(3), "TEST", new Limit(25)));
+
+ List eventsD = Arrays.asList(
+ new CreateGroupEvent(uuid(4), "TEST", LocalDateTime.now()),
+ new AddMemberEvent(uuid(4), "TEST", "TEST", new User("TEST")),
+ new UpdateRoleEvent(uuid(4), "TEST", "TEST", Role.ADMIN),
+ new SetLimitEvent(uuid(4), "TEST", new Limit(35)));
+
+ initEvents(eventsA);
+ initEvents(eventsB);
+ initEvents(eventsC);
+ initEvents(eventsD);
+
+ List events = new ArrayList<>();
+ events.addAll(eventsA);
+ events.addAll(eventsB);
+ events.addAll(eventsC);
+ events.addAll(eventsD);
+
+ project(groups, events, mock(GroupCache.class));
+
+ assertThat(groups).hasSize(4);
+ assertThat(groups.get(uuid(1)).exists()).isTrue();
+ assertThat(groups.get(uuid(1)).getAdmins()).hasSize(1);
+ assertThat(groups.get(uuid(1)).getLimit()).isEqualTo(5);
+
+ assertThat(groups.get(uuid(2)).exists()).isTrue();
+ assertThat(groups.get(uuid(2)).getAdmins()).hasSize(1);
+ assertThat(groups.get(uuid(2)).getLimit()).isEqualTo(15);
+
+ assertThat(groups.get(uuid(3)).exists()).isTrue();
+ assertThat(groups.get(uuid(3)).getAdmins()).hasSize(1);
+ assertThat(groups.get(uuid(3)).getLimit()).isEqualTo(25);
+
+ assertThat(groups.get(uuid(4)).exists()).isTrue();
+ assertThat(groups.get(uuid(4)).getAdmins()).hasSize(1);
+ assertThat(groups.get(uuid(4)).getLimit()).isEqualTo(35);
+ }
+}
diff --git a/src/test/java/mops/gruppen2/infrastructure/GroupCacheTest.java b/src/test/java/mops/gruppen2/infrastructure/GroupCacheTest.java
new file mode 100644
index 0000000..8031301
--- /dev/null
+++ b/src/test/java/mops/gruppen2/infrastructure/GroupCacheTest.java
@@ -0,0 +1,312 @@
+package mops.gruppen2.infrastructure;
+
+import mops.gruppen2.GroupBuilder;
+import mops.gruppen2.domain.exception.GroupNotFoundException;
+import mops.gruppen2.domain.model.group.Group;
+import mops.gruppen2.domain.service.EventStoreService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static mops.gruppen2.TestHelper.uuid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+// Kann nur indirket über events getestet werden, diese werden also "mitgetestet"
+class GroupCacheTest {
+
+ private GroupCache cache;
+
+ @BeforeEach
+ void setUp() {
+ cache = new GroupCache(Mockito.mock(EventStoreService.class));
+ }
+
+ @Test
+ void groups_noGroups() {
+ assertThat(cache.groups()).isEmpty();
+ }
+
+ @Test
+ void group_groupNotFound() {
+ assertThatThrownBy(() -> cache.group(uuid(1)))
+ .isInstanceOf(GroupNotFoundException.class);
+ }
+
+ @Test
+ void group_linkNotFound() {
+ assertThatThrownBy(() -> cache.group("00000000-0000-0000-0000-000000000000"))
+ .isInstanceOf(GroupNotFoundException.class);
+ }
+
+ @Test
+ void group_groupFound() {
+ Group group = GroupBuilder.get(cache, 1).group().build();
+
+ assertThat(cache.group(uuid(1))).isEqualTo(group);
+ }
+
+ @Test
+ void group_linkFound() {
+ Group group = GroupBuilder.get(cache, 1).group().build();
+
+ assertThat(cache.group(group.getLink())).isEqualTo(group);
+ }
+
+ @Test
+ void userGroups_noGroups() {
+ assertThat(cache.userGroups("TEST")).isEmpty();
+ }
+
+ @Test
+ void userGroups_noUserGroups() {
+ Group group = GroupBuilder.get(cache, 1).group().add("PETER").build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userGroups("TEST")).isEmpty();
+ }
+
+ @Test
+ void userGroups_oneUserGroup() {
+ Group group = GroupBuilder.get(cache, 1).group().add("TEST").build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userGroups("TEST")).containsExactly(group);
+ }
+
+ @Test
+ void userGroups_userGroup_multiple() {
+ Group groupA = GroupBuilder.get(cache, 1).group().add("TEST").build();
+ Group groupB = GroupBuilder.get(cache, 2).group().add("PETER").build();
+ Group groupC = GroupBuilder.get(cache, 3).group().add("TEST").build();
+ Group groupD = GroupBuilder.get(cache, 4).group().add("PETER").build();
+
+ assertThat(cache.groups()).hasSize(4);
+ assertThat(cache.userGroups("PETER")).containsExactly(groupB, groupD);
+ }
+
+ @Test
+ void userLectures_noGroups() {
+ assertThat(cache.userLectures("PETER")).isEmpty();
+ }
+
+ @Test
+ void userLectures_noLecture() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().publik().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userLectures("PETER")).isEmpty();
+ }
+
+ @Test
+ void userLectures_oneLecture() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").lecture().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userLectures("PETER")).containsExactly(group);
+ }
+
+ @Test
+ void userLectures_lecture_multiple() {
+ Group groupA = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").lecture().build();
+ Group groupB = GroupBuilder.get(cache, 2).group().testadmin().limit(2).add("PETER").publik().build();
+ Group groupC = GroupBuilder.get(cache, 3).group().testadmin().limit(2).add("PETER").privat().build();
+ Group groupD = GroupBuilder.get(cache, 4).group().testadmin().lecture().build();
+
+ assertThat(cache.groups()).hasSize(4);
+ assertThat(cache.userLectures("PETER")).containsExactly(groupA);
+ }
+
+ @Test
+ void userPublics_noGroups() {
+ assertThat(cache.userPublics("PETER")).isEmpty();
+ }
+
+ @Test
+ void userPublics_noPublic() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").publik().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userLectures("PETER")).isEmpty();
+ }
+
+ @Test
+ void userPublics_onePublic() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").lecture().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userLectures("PETER")).containsExactly(group);
+ }
+
+ @Test
+ void userPublics_public_multiple() {
+ Group groupA = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").lecture().build();
+ Group groupB = GroupBuilder.get(cache, 2).group().testadmin().limit(2).add("PETER").publik().build();
+ Group groupC = GroupBuilder.get(cache, 3).group().testadmin().limit(2).add("PETER").privat().build();
+ Group groupD = GroupBuilder.get(cache, 4).group().testadmin().publik().build();
+
+ assertThat(cache.groups()).hasSize(4);
+ assertThat(cache.userPublics("PETER")).containsExactly(groupB);
+ }
+
+ @Test
+ void userPrivates_noGroups() {
+ assertThat(cache.userPrivates("PETER")).isEmpty();
+ }
+
+ @Test
+ void userPrivates_noPrivate() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").publik().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userPrivates("PETER")).isEmpty();
+ }
+
+ @Test
+ void userPrivates_onePrivate() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").privat().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userPrivates("PETER")).containsExactly(group);
+ }
+
+ @Test
+ void userPrivates_private_multiple() {
+ Group groupA = GroupBuilder.get(cache, 1).group().testadmin().limit(2).add("PETER").lecture().build();
+ Group groupB = GroupBuilder.get(cache, 2).group().testadmin().limit(2).add("PETER").privat().build();
+ Group groupC = GroupBuilder.get(cache, 3).group().testadmin().privat().build();
+ Group groupD = GroupBuilder.get(cache, 4).group().testadmin().publik().build();
+
+ assertThat(cache.groups()).hasSize(4);
+ assertThat(cache.userPrivates("PETER")).containsExactly(groupB);
+ }
+
+ @Test
+ void publics_noGroups() {
+ assertThat(cache.publics()).isEmpty();
+ }
+
+ @Test
+ void publics_noPublic() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().privat().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.publics()).isEmpty();
+ }
+
+ @Test
+ void publics_onePublic() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().publik().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.publics()).containsExactly(group);
+ }
+
+ @Test
+ void publics_public_multiple() {
+ Group groupA = GroupBuilder.get(cache, 1).group().testadmin().lecture().build();
+ Group groupB = GroupBuilder.get(cache, 2).group().testadmin().privat().build();
+ Group groupC = GroupBuilder.get(cache, 3).group().testadmin().privat().build();
+ Group groupD = GroupBuilder.get(cache, 4).group().testadmin().publik().build();
+
+ assertThat(cache.groups()).hasSize(4);
+ assertThat(cache.publics()).containsExactly(groupD);
+ }
+
+ @Test
+ void privates_noGroups() {
+ assertThat(cache.privates()).isEmpty();
+ }
+
+ @Test
+ void privates_noPrivate() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().publik().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.privates()).isEmpty();
+ }
+
+ @Test
+ void privates_onePrivate() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().privat().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.privates()).containsExactly(group);
+ }
+
+ @Test
+ void privates_private_multiple() {
+ Group groupA = GroupBuilder.get(cache, 1).group().testadmin().lecture().build();
+ Group groupB = GroupBuilder.get(cache, 2).group().testadmin().privat().build();
+ Group groupC = GroupBuilder.get(cache, 3).group().testadmin().privat().build();
+ Group groupD = GroupBuilder.get(cache, 4).group().testadmin().publik().build();
+
+ assertThat(cache.groups()).hasSize(4);
+ assertThat(cache.privates()).containsExactly(groupB, groupC);
+ }
+
+ @Test
+ void lectures_noGroups() {
+ assertThat(cache.lectures()).isEmpty();
+ }
+
+ @Test
+ void lectures_noLecture() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().privat().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.lectures()).isEmpty();
+ }
+
+ @Test
+ void lectures_oneLecture() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().lecture().build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.lectures()).containsExactly(group);
+ }
+
+ @Test
+ void lectures_lecture_multiple() {
+ Group groupA = GroupBuilder.get(cache, 1).group().testadmin().lecture().build();
+ Group groupB = GroupBuilder.get(cache, 2).group().testadmin().privat().build();
+ Group groupC = GroupBuilder.get(cache, 3).group().testadmin().lecture().build();
+ Group groupD = GroupBuilder.get(cache, 4).group().testadmin().publik().build();
+
+ assertThat(cache.groups()).hasSize(4);
+ assertThat(cache.lectures()).containsExactly(groupA, groupC);
+ }
+
+ //Indirekt: void usersPut() {}
+
+ @Test
+ void usersRemove() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().lecture().limit(2).add("PETER").kick("PETER").build();
+
+ assertThat(cache.groups()).hasSize(1);
+ assertThat(cache.userLectures("PETER")).isEmpty();
+ }
+
+ //Indirekt: void groupsPut() {}
+
+ @Test
+ void groupsRemove() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().lecture().destroy().build();
+
+ assertThat(cache.groups()).hasSize(0);
+ }
+
+
+ //Indirekt: void linksPut() {}
+
+ @Test
+ void linksRemove() {
+ Group group = GroupBuilder.get(cache, 1).group().testadmin().lecture().link(2).build();
+
+ assertThat(cache.group(String.valueOf(uuid(2)))).isEqualTo(group);
+ }
+
+ //Indirekt: void typesPut() {}
+
+ //Indirekt: void typesRemove() {}
+}
diff --git a/src/test/java/mops/gruppen2/infrastructure/controller/APIControllerTest.java b/src/test/java/mops/gruppen2/infrastructure/controller/APIControllerTest.java
new file mode 100644
index 0000000..e4cbf27
--- /dev/null
+++ b/src/test/java/mops/gruppen2/infrastructure/controller/APIControllerTest.java
@@ -0,0 +1,53 @@
+package mops.gruppen2.infrastructure.controller;
+
+import mops.gruppen2.domain.service.EventStoreService;
+import mops.gruppen2.infrastructure.GroupCache;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.springframework.security.test.context.support.WithMockUser;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class APIControllerTest {
+
+ private EventStoreService store;
+ private GroupCache cache;
+ private APIController controller;
+
+ @BeforeEach
+ void setUp() {
+ store = mock(EventStoreService.class);
+ cache = new GroupCache(store);
+ controller = new APIController(cache, store);
+ }
+
+ @WithMockUser("ROLE_api_user")
+ @Test
+ void getApiUpdate_noEvents() {
+ when(store.findMaxEventId()).thenReturn(0L);
+
+ assertThat(controller.getApiUpdate(0).getVersion()).isZero();
+ assertThat(controller.getApiUpdate(0).getGroups()).isEmpty();
+ }
+
+ @Disabled
+ @WithMockUser("ROLE_api_user")
+ @Test
+ void getApiUpdate_noUpdate() {
+ }
+
+ @Disabled
+ @WithMockUser("ROLE_api_user")
+ @Test
+ void getApiUserGroups() {
+ }
+
+ @Disabled
+ @WithMockUser("ROLE_api_user")
+ @Test
+ void getApiGroup() {
+ }
+}
diff --git a/src/test/java/mops/gruppen2/infrastructure/controller/GroupCreationControllerTest.java b/src/test/java/mops/gruppen2/infrastructure/controller/GroupCreationControllerTest.java
new file mode 100644
index 0000000..4d01119
--- /dev/null
+++ b/src/test/java/mops/gruppen2/infrastructure/controller/GroupCreationControllerTest.java
@@ -0,0 +1,19 @@
+package mops.gruppen2.infrastructure.controller;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class GroupCreationControllerTest {
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @Test
+ void getCreate() {
+ }
+
+ @Test
+ void postCreateOrga() {
+ }
+}
diff --git a/src/test/java/mops/gruppen2/infrastructure/controller/GroupDetailsControllerTest.java b/src/test/java/mops/gruppen2/infrastructure/controller/GroupDetailsControllerTest.java
new file mode 100644
index 0000000..42c7a9c
--- /dev/null
+++ b/src/test/java/mops/gruppen2/infrastructure/controller/GroupDetailsControllerTest.java
@@ -0,0 +1,67 @@
+package mops.gruppen2.infrastructure.controller;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class GroupDetailsControllerTest {
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @Test
+ void getDetailsPage() {
+ }
+
+ @Test
+ void postDetailsJoin() {
+ }
+
+ @Test
+ void postDetailsLeave() {
+ }
+
+ @Test
+ void getDetailsHistory() {
+ }
+
+ @Test
+ void getDetailsExportHistoryPlain() {
+ }
+
+ @Test
+ void getDetailsExportHistorySql() {
+ }
+
+ @Test
+ void getDetailsExportMembers() {
+ }
+
+ @Test
+ void getDetailsEdit() {
+ }
+
+ @Test
+ void postDetailsEditMeta() {
+ }
+
+ @Test
+ void postDetailsEditUserLimit() {
+ }
+
+ @Test
+ void postDetailsEditCsv() {
+ }
+
+ @Test
+ void postDetailsEditRole() {
+ }
+
+ @Test
+ void postDetailsEditDelete() {
+ }
+
+ @Test
+ void postDetailsEditDestroy() {
+ }
+}
diff --git a/src/test/java/mops/gruppen2/infrastructure/controller/SearchAndInviteControllerTest.java b/src/test/java/mops/gruppen2/infrastructure/controller/SearchAndInviteControllerTest.java
new file mode 100644
index 0000000..edc1ad0
--- /dev/null
+++ b/src/test/java/mops/gruppen2/infrastructure/controller/SearchAndInviteControllerTest.java
@@ -0,0 +1,31 @@
+package mops.gruppen2.infrastructure.controller;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class SearchAndInviteControllerTest {
+
+ @BeforeEach
+ void setUp() {
+ }
+
+ @Test
+ void getSearch() {
+ }
+
+ @Test
+ void postSearchString() {
+ }
+
+ @Test
+ void getSearchAll() {
+ }
+
+ @Test
+ void getSearchType() {
+ }
+
+ @Test
+ void getJoin() {
+ }
+}
diff --git a/src/test/java/mops/gruppen2/service/ControllerServiceTest.java b/src/test/java/mops/gruppen2/service/ControllerServiceTest.java
deleted file mode 100644
index 9cfc762..0000000
--- a/src/test/java/mops/gruppen2/service/ControllerServiceTest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.Gruppen2Application;
-import mops.gruppen2.domain.Account;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.GroupType;
-import mops.gruppen2.domain.Role;
-import mops.gruppen2.domain.User;
-import mops.gruppen2.domain.Visibility;
-import mops.gruppen2.domain.exception.UserNotFoundException;
-import mops.gruppen2.repository.EventRepository;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.annotation.Rollback;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-@ExtendWith(SpringExtension.class)
-@SpringBootTest(classes = Gruppen2Application.class)
-@Transactional
-@Rollback
-class ControllerServiceTest {
-
- Account account;
- Account account2;
- Account account3;
- ControllerService controllerService;
- EventService eventService;
- UserService userService;
- ValidationService validationService;
- @Autowired
- EventRepository eventRepository;
- GroupService groupService;
- @Autowired
- InviteService inviteService;
-
- @BeforeEach
- void setUp() {
- eventService = new EventService(eventRepository);
- groupService = new GroupService(eventService, eventRepository);
- userService = new UserService(groupService, eventService);
- validationService = new ValidationService(userService, groupService);
- controllerService = new ControllerService(eventService, userService, validationService, inviteService);
- Set roles = new HashSet<>();
- roles.add("l");
- account = new Account("ich", "ich@hhu.de", "l", "ichdude", "jap", roles);
- account2 = new Account("ich2", "ich2@hhu.de", "l", "ichdude2", "jap2", roles);
- account3 = new Account("ich3", "ich3@hhu.de", "l", "ichdude3", "jap3", roles);
- eventRepository.deleteAll();
- }
-
- @Test
- void createPublicGroupWithNoParentAndLimitedNumberTest() {
- controllerService.createGroup(account, "test", "hi", null, null, null, 20L, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
- assertEquals(20L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createPublicGroupWithNoParentAndUnlimitedNumberTest() {
- controllerService.createGroup(account, "test", "hi", null, null, true, null, null);
- User user = new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail());
- List groups = userService.getUserGroups(user);
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
- assertEquals(100000L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createPrivateGroupWithNoParentAndUnlimitedNumberTest() {
- controllerService.createGroup(account, "test", "hi", true, null, true, null, null);
- User user = new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail());
- List groups = userService.getUserGroups(user);
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
- assertEquals(100000L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createPrivateGroupWithNoParentAndLimitedNumberTest() {
- controllerService.createGroup(account, "test", "hi", true, null, null, 20L, null);
- User user = new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail());
- List groups = userService.getUserGroups(user);
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
- assertEquals(20L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createPrivateGroupWithParentAndLimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account2, "test", "hi", null, true, true, null, null, null);
- User user = new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail());
- List groups1 = userService.getUserGroups(user);
- controllerService.createGroup(account, "test", "hi", true, null, null, 20L, groups1.get(0).getId());
- User user2 = new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail());
- List groups = userService.getUserGroups(user2);
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
- assertEquals(20L, groups.get(0).getUserMaximum());
- assertEquals(groups1.get(0).getId(), groups.get(0).getParent());
- }
-
- @Test
- void createPublicGroupWithParentAndLimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account2, "test", "hi", null, null, true, null, null, null);
- List groups1 = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()));
- controllerService.createGroup(account, "test", "hi", null, null, null, 20L, groups1.get(0).getId());
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
- assertEquals(20L, groups.get(0).getUserMaximum());
- assertEquals(groups1.get(0).getId(), groups.get(0).getParent());
- }
-
- @Test
- void createPublicGroupWithParentAndUnlimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account2, "test", "hi", null, null, true, null, null, null);
- List groups1 = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()));
- controllerService.createGroup(account, "test", "hi", null, true, true, null, groups1.get(0).getId());
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
- assertEquals(100000L, groups.get(0).getUserMaximum());
- assertEquals(groups1.get(0).getId(), groups.get(0).getParent());
- }
-
- @Test
- void createPrivateGroupWithParentAndUnlimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account2, "test", "hi", null, null, true, null, null, null);
- List groups1 = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()));
- controllerService.createGroup(account, "test", "hi", true, true, true, null, groups1.get(0).getId());
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
- assertEquals(100000L, groups.get(0).getUserMaximum());
- assertEquals(groups1.get(0).getId(), groups.get(0).getParent());
- }
-
- @Test
- void createPublicOrgaGroupWithNoParentAndLimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account, "test", "hi", null, null, null, 20L, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(GroupType.SIMPLE, groups.get(0).getType());
- assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
- assertEquals(20L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createPublicOrgaGroupWithNoParentAndUnlimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account, "test", "hi", null, null, true, null, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(GroupType.SIMPLE, groups.get(0).getType());
- assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
- assertEquals(100000L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createPrivateOrgaGroupWithNoParentAndLimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account, "test", "hi", true, null, null, 20L, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(GroupType.SIMPLE, groups.get(0).getType());
- assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
- assertEquals(20L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createPrivateOrgaGroupWithNoParentAndUnlimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account, "test", "hi", true, null, true, null, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(GroupType.SIMPLE, groups.get(0).getType());
- assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
- assertEquals(100000L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createOrgaLectureGroupAndLimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account, "test", "hi", null, true, null, 20L, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(GroupType.LECTURE, groups.get(0).getType());
- assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
- assertEquals(20L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- void createOrgaLectureGroupAndUnlimitedNumberTest() throws IOException {
- controllerService.createGroupAsOrga(account, "test", "hi", null, true, true, null, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
- assertEquals(GroupType.LECTURE, groups.get(0).getType());
- assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
- assertEquals(100000L, groups.get(0).getUserMaximum());
- assertNull(groups.get(0).getParent());
- }
-
- @Test
- public void deleteUserTest() {
- controllerService.createGroup(account, "test", "hi", true, true, true, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- controllerService.addUser(account2, groups.get(0).getId());
- User user = new User(account.getName(), "", "", "");
- controllerService.deleteUser(account, user, groups.get(0));
- assertTrue(userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())).isEmpty());
- }
-
- @Test
- public void updateRoleAdminTest() {
- controllerService.createGroup(account, "test", "hi", null, null, true, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- controllerService.addUser(account2, groups.get(0).getId());
- User user = new User(account.getName(), "", "", "");
- controllerService.updateRole(user, groups.get(0).getId());
- groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account.getName()));
- }
-
- @Test
- public void updateRoleMemberTest() {
- controllerService.createGroup(account, "test", "hi", null, null, true, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- controllerService.addUser(account2, groups.get(0).getId());
- User user = new User(account2.getName(), "", "", "");
- controllerService.updateRole(user, groups.get(0).getId());
- groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName()));
- }
-
- @Test
- public void updateRoleNonUserTest() {
- controllerService.createGroup(account, "test", "hi", null, null, true, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- User user = new User(account2.getName(), "", "", "");
- Throwable exception = assertThrows(UserNotFoundException.class, () -> controllerService.updateRole(user, groups.get(0).getId()));
- assertEquals("404 NOT_FOUND \"Der User wurde nicht gefunden. (class mops.gruppen2.service.ValidationService)\"", exception.getMessage());
- }
-
- @Test
- public void deleteNonUserTest() {
- controllerService.createGroup(account, "test", "hi", true, null, true, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- User user = new User(account2.getName(), "", "", "");
- Throwable exception = assertThrows(UserNotFoundException.class, () -> controllerService.deleteUser(account, user, groups.get(0)));
- assertEquals("404 NOT_FOUND \"Der User wurde nicht gefunden. (class mops.gruppen2.service.ValidationService)\"", exception.getMessage());
- }
-
- void testTitleAndDescription(String title, String description) {
- assertEquals("test", title);
- assertEquals("hi", description);
- }
-
- @Test
- void passIfLastAdminTest() {
- controllerService.createGroup(account, "test", "hi", null, null, true, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- controllerService.addUser(account2, groups.get(0).getId());
- User user = new User(account.getName(), "", "", "");
- groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()));
- controllerService.deleteUser(account, user, groups.get(0));
- groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()));
- assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName()));
- }
-
- @Test
- void dontPassIfNotLastAdminTest() {
- controllerService.createGroup(account, "test", "hi", null, null, true, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- controllerService.addUser(account2, groups.get(0).getId());
- User user2 = new User(account2.getName(), "", "", "");
- controllerService.updateRole(user2, groups.get(0).getId());
- controllerService.addUser(account3, groups.get(0).getId());
- controllerService.changeRoleIfLastAdmin(account, groups.get(0));
- User user = new User(account.getName(), "", "", "");
- controllerService.deleteUser(account, user, groups.get(0));
- groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()));
- assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account3.getName()));
- }
-
- @Test
- void getVeteranMemberTest() {
- controllerService.createGroup(account, "test", "hi", null, null, true, null, null);
- List groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()));
- controllerService.addUser(account2, groups.get(0).getId());
- controllerService.addUser(account3, groups.get(0).getId());
- User user = new User(account.getName(), "", "", "");
- groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()));
- controllerService.deleteUser(account, user, groups.get(0));
- groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()));
- assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName()));
- assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account3.getName()));
- }
-}
diff --git a/src/test/java/mops/gruppen2/service/EventServiceTest.java b/src/test/java/mops/gruppen2/service/EventServiceTest.java
deleted file mode 100644
index 43e105c..0000000
--- a/src/test/java/mops/gruppen2/service/EventServiceTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.Gruppen2Application;
-import mops.gruppen2.domain.dto.EventDTO;
-import mops.gruppen2.domain.event.Event;
-import mops.gruppen2.repository.EventRepository;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.test.annotation.Rollback;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.transaction.annotation.Transactional;
-
-import static mops.gruppen2.TestBuilder.addUserEvent;
-import static mops.gruppen2.TestBuilder.addUserEvents;
-import static mops.gruppen2.TestBuilder.createPrivateGroupEvents;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvents;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-
-@ExtendWith(SpringExtension.class)
-@SpringBootTest(classes = Gruppen2Application.class)
-@Transactional
-@Rollback
-class EventServiceTest {
-
- @Autowired
- private EventRepository eventRepository;
- private EventService eventService;
- @Autowired
- private JdbcTemplate template;
-
- @BeforeEach
- void setUp() {
- eventService = new EventService(eventRepository);
- eventRepository.deleteAll();
- //noinspection SqlResolve
- template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1");
- }
-
- @Test
- void saveEvent() {
- eventService.saveEvent(createPublicGroupEvent());
-
- assertThat(eventRepository.findAll()).hasSize(1);
- }
-
- @Test
- void saveAll() {
- eventService.saveAll(createPrivateGroupEvents(10));
-
- assertThat(eventRepository.findAll()).hasSize(10);
- }
-
- @Test
- void testSaveAll() {
- eventService.saveAll(createPublicGroupEvents(5),
- createPrivateGroupEvents(5));
-
- assertThat(eventRepository.findAll()).hasSize(10);
- }
-
- @Test
- void getDTO() {
- Event event = createPublicGroupEvent();
-
- EventDTO dto = eventService.getDTOFromEvent(event);
-
- assertThat(dto.getGroup_id()).isEqualTo(event.getGroupId().toString());
- assertThat(dto.getUser_id()).isEqualTo(event.getUserId());
- assertThat(dto.getEvent_id()).isEqualTo(null);
- assertThat(dto.getEvent_type()).isEqualTo("CreateGroupEvent");
- }
-
- @Test
- void getEventsOfGroup() {
- eventService.saveAll(addUserEvents(10, uuidMock(0)),
- addUserEvents(5, uuidMock(1)));
-
- assertThat(eventService.getEventsOfGroup(uuidMock(0))).hasSize(10);
- assertThat(eventService.getEventsOfGroup(uuidMock(1))).hasSize(5);
- }
-
- @Test
- void findGroupIdsByUser() {
- eventService.saveAll(addUserEvent(uuidMock(0), "A"),
- addUserEvent(uuidMock(1), "A"),
- addUserEvent(uuidMock(2), "A"),
- addUserEvent(uuidMock(3), "A"),
- addUserEvent(uuidMock(3), "B"));
-
- assertThat(eventService.findGroupIdsByUser("A")).hasSize(4);
- assertThat(eventService.findGroupIdsByUser("B")).hasSize(1);
- }
-}
diff --git a/src/test/java/mops/gruppen2/service/GroupServiceTest.java b/src/test/java/mops/gruppen2/service/GroupServiceTest.java
deleted file mode 100644
index 488a22b..0000000
--- a/src/test/java/mops/gruppen2/service/GroupServiceTest.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package mops.gruppen2.service;
-
-import mops.gruppen2.Gruppen2Application;
-import mops.gruppen2.TestBuilder;
-import mops.gruppen2.domain.Group;
-import mops.gruppen2.domain.Visibility;
-import mops.gruppen2.domain.event.Event;
-import mops.gruppen2.repository.EventRepository;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.test.annotation.Rollback;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-
-import static mops.gruppen2.TestBuilder.account;
-import static mops.gruppen2.TestBuilder.addUserEvent;
-import static mops.gruppen2.TestBuilder.completePrivateGroup;
-import static mops.gruppen2.TestBuilder.completePrivateGroups;
-import static mops.gruppen2.TestBuilder.completePublicGroups;
-import static mops.gruppen2.TestBuilder.createLectureEvent;
-import static mops.gruppen2.TestBuilder.createPrivateGroupEvent;
-import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
-import static mops.gruppen2.TestBuilder.deleteGroupEvent;
-import static mops.gruppen2.TestBuilder.updateGroupDescriptionEvent;
-import static mops.gruppen2.TestBuilder.updateGroupTitleEvent;
-import static mops.gruppen2.TestBuilder.uuidMock;
-import static org.assertj.core.api.Assertions.assertThat;
-
-@ExtendWith(SpringExtension.class)
-@SpringBootTest(classes = Gruppen2Application.class)
-@Transactional
-@Rollback
-class GroupServiceTest {
-
- @Autowired
- private EventRepository eventRepository;
- @Autowired
- private EventService eventService;
- private GroupService groupService;
- @Autowired
- private JdbcTemplate template;
-
- @BeforeEach
- void setUp() {
- groupService = new GroupService(eventService, eventRepository);
- eventRepository.deleteAll();
- //noinspection SqlResolve
- template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1");
- }
-
- //TODO: Wofür ist dieser Test?
- @Test
- void rightClassForSuccessfulGroup() {
- List eventList = completePrivateGroup(1);
-
- List groups = groupService.projectEventList(eventList);
- assertThat(groups.get(0)).isInstanceOf(Group.class);
- }
-
- @Test
- void projectEventList_SingleGroup() {
- List eventList = completePrivateGroup(5);
-
- List groups = groupService.projectEventList(eventList);
-
- assertThat(groups).hasSize(1);
- assertThat(groups.get(0).getMembers()).hasSize(5);
- assertThat(groups.get(0).getVisibility()).isEqualTo(Visibility.PRIVATE);
- }
-
- @Test
- void projectEventList_MultipleGroups() {
- List eventList = completePrivateGroups(10, 2);
- eventList.addAll(completePublicGroups(10, 5));
-
- List groups = groupService.projectEventList(eventList);
-
- assertThat(groups).hasSize(20);
- assertThat(groups.stream().map(group -> group.getMembers().size()).reduce(Integer::sum).get()).isEqualTo(70);
- }
-
- @Test
- void getGroupEvents() {
- eventService.saveAll(createPublicGroupEvent(uuidMock(0)),
- createPublicGroupEvent(uuidMock(1)),
- createPrivateGroupEvent(uuidMock(2)));
-
- List groupIds = Arrays.asList(uuidMock(0), uuidMock(1));
-
- assertThat(groupService.getGroupEvents(groupIds)).hasSize(2);
- assertThat(groupService.getGroupEvents(groupIds).get(0).getGroupId()).isEqualTo(uuidMock(0));
- assertThat(groupService.getGroupEvents(groupIds).get(1).getGroupId()).isEqualTo(uuidMock(1));
- }
-
- @Test
- void getAllGroupWithVisibilityPublicTestCreateAndDeleteSameGroup() {
- Event test1 = createPublicGroupEvent(uuidMock(0));
- Event test2 = deleteGroupEvent(uuidMock(0));
-
- //TODO: Hier projectEventlist()?
- Group group = TestBuilder.apply(test1, test2);
-
- assertThat(group.getType()).isEqualTo(null);
- assertThat(groupService.getAllGroupWithVisibilityPublic("errer")).isEmpty();
- }
-
- @Test
- void getAllGroupWithVisibilityPublicTestGroupPublic() {
- eventService.saveAll(createPublicGroupEvent(uuidMock(0)),
- deleteGroupEvent(uuidMock(0)),
- createPublicGroupEvent());
-
- assertThat(groupService.getAllGroupWithVisibilityPublic("test1").size()).isEqualTo(1);
- }
-
- @Test
- void getAllGroupWithVisibilityPublicTestAddSomeEvents() {
- eventService.saveAll(createPublicGroupEvent(uuidMock(0)),
- deleteGroupEvent(uuidMock(0)),
- createPublicGroupEvent(),
- createPublicGroupEvent(),
- createPublicGroupEvent(),
- createPrivateGroupEvent());
-
- assertThat(groupService.getAllGroupWithVisibilityPublic("test1").size()).isEqualTo(3);
- }
-
- @Test
- void getAllGroupWithVisibilityPublic_UserInGroup() {
- eventService.saveAll(createPublicGroupEvent(uuidMock(0)),
- addUserEvent(uuidMock(0), "kobold"),
- createPrivateGroupEvent(),
- createPublicGroupEvent());
-
- assertThat(groupService.getAllGroupWithVisibilityPublic("kobold")).hasSize(1);
- assertThat(groupService.getAllGroupWithVisibilityPublic("peter")).hasSize(2);
- }
-
- @Test
- void getAllLecturesWithVisibilityPublic() {
- eventService.saveAll(createLectureEvent(),
- createPublicGroupEvent(),
- createLectureEvent(),
- createLectureEvent(),
- createLectureEvent());
-
- assertThat(groupService.getAllLecturesWithVisibilityPublic().size()).isEqualTo(4);
- }
-
- @Test
- void findGroupWith_UserMember_AllGroups() {
- eventService.saveAll(createPublicGroupEvent(uuidMock(0)),
- addUserEvent(uuidMock(0), "jens"),
- updateGroupTitleEvent(uuidMock(0)),
- updateGroupDescriptionEvent(uuidMock(0)));
-
- assertThat(groupService.findGroupWith("", account("jens"))).isEmpty();
- }
-
- @Test
- void findGroupWith_UserNoMember_AllGroups() {
- eventService.saveAll(completePublicGroups(10, 0),
- completePrivateGroups(10, 0));
-
- assertThat(groupService.findGroupWith("", account("jens"))).hasSize(10);
- }
-
- @Test
- void findGroupWith_FilterGroups() {
- eventService.saveAll(createPublicGroupEvent(uuidMock(0)),
- updateGroupTitleEvent(uuidMock(0), "KK"),
- updateGroupDescriptionEvent(uuidMock(0), "ABCDE"),
- createPublicGroupEvent(uuidMock(1)),
- updateGroupTitleEvent(uuidMock(1), "ABCDEFG"),
- updateGroupDescriptionEvent(uuidMock(1), "KK"),
- createPrivateGroupEvent());
-
- assertThat(groupService.findGroupWith("A", account("jesus"))).hasSize(2);
- assertThat(groupService.findGroupWith("F", account("jesus"))).hasSize(1);
- assertThat(groupService.findGroupWith("Z", account("jesus"))).hasSize(0);
- }
-
-}
diff --git a/system.properties b/system.properties
new file mode 100644
index 0000000..6bea4c3
--- /dev/null
+++ b/system.properties
@@ -0,0 +1 @@
+java.runtime.version = 11