@ -5,6 +5,6 @@ CREATE TABLE event
|
||||
group_version INT NOT NULL,
|
||||
exec_id VARCHAR(32) NOT NULL,
|
||||
target_id VARCHAR(32),
|
||||
event_type VARCHAR(16) NOT NULL,
|
||||
event_date DATETIME NOT NULL,
|
||||
event_payload JSON NOT NULL
|
||||
);
|
||||
|
@ -1,3 +1,5 @@
|
||||
DROP TABLE IF EXISTS event;
|
||||
|
||||
CREATE TABLE event
|
||||
(
|
||||
event_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
@ -5,6 +7,6 @@ CREATE TABLE event
|
||||
group_version INT NOT NULL,
|
||||
exec_id VARCHAR(32) NOT NULL,
|
||||
target_id VARCHAR(32),
|
||||
event_type VARCHAR(16) NOT NULL,
|
||||
event_date DATETIME NOT NULL,
|
||||
event_payload TEXT NOT NULL
|
||||
);
|
||||
|
@ -22,10 +22,10 @@ public class KeycloakConfig {
|
||||
@Value("${keycloak.resource}")
|
||||
private String clientId;
|
||||
|
||||
@Value("f73354fd-614e-4e24-b801-a8d0f4abf531")
|
||||
@Value("2e2e5770-c454-4d31-be99-9d8c34c93089")
|
||||
private String clientSecret;
|
||||
|
||||
@Value("https://gruppenkeycloak.herokuapp.com/auth/realms/master/protocol/openid-connect/token")
|
||||
@Value("https://churl-keycloak.herokuapp.com/auth/realms/Gruppen/protocol/openid-connect/token")
|
||||
private String tokenUri;
|
||||
|
||||
@Bean
|
||||
|
@ -6,7 +6,7 @@ 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.UserAlreadyExistsException;
|
||||
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;
|
||||
@ -39,12 +39,17 @@ public class AddMemberEvent extends Event {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyEvent(Group group) throws UserAlreadyExistsException, GroupFullException {
|
||||
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();
|
||||
|
@ -39,6 +39,11 @@ public class CreateGroupEvent extends Event {
|
||||
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();
|
||||
|
@ -20,7 +20,7 @@ public class DestroyGroupEvent extends Event {
|
||||
|
||||
@Override
|
||||
protected void updateCache(GroupCache cache, Group group) {
|
||||
cache.groupsRemove(group);
|
||||
cache.groupsRemove(groupid, group);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -30,6 +30,11 @@ public class DestroyGroupEvent extends Event {
|
||||
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();
|
||||
|
@ -13,21 +13,26 @@ 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;
|
||||
|
||||
@Log4j2
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "class")
|
||||
@JsonSubTypes({@JsonSubTypes.Type(value = AddMemberEvent.class, name = "ADDMEMBER"),
|
||||
@JsonSubTypes.Type(value = CreateGroupEvent.class, name = "CREATEGROUP"),
|
||||
@JsonSubTypes.Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"),
|
||||
@JsonSubTypes.Type(value = KickMemberEvent.class, name = "KICKMEMBER"),
|
||||
@JsonSubTypes.Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"),
|
||||
@JsonSubTypes.Type(value = SetInviteLinkEvent.class, name = "SETLINK"),
|
||||
@JsonSubTypes.Type(value = SetLimitEvent.class, name = "SETLIMIT"),
|
||||
@JsonSubTypes.Type(value = SetParentEvent.class, name = "SETPARENT"),
|
||||
@JsonSubTypes.Type(value = SetTitleEvent.class, name = "SETTITLE"),
|
||||
@JsonSubTypes.Type(value = SetTypeEvent.class, name = "SETTYPE"),
|
||||
@JsonSubTypes.Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")})
|
||||
@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 // Lombok needs a default constructor in the base class
|
||||
public abstract class Event {
|
||||
@ -44,6 +49,10 @@ public abstract class Event {
|
||||
@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;
|
||||
@ -54,6 +63,7 @@ public abstract class Event {
|
||||
if (this.version != 0) {
|
||||
throw new BadArgumentException("Event wurde schon initialisiert. (" + type() + ")");
|
||||
}
|
||||
date = LocalDateTime.now();
|
||||
|
||||
log.trace("Event wurde initialisiert. (" + type() + "," + version + ")");
|
||||
|
||||
@ -68,9 +78,22 @@ public abstract class Event {
|
||||
}
|
||||
|
||||
checkGroupIdMatch(group.getId());
|
||||
updateCache(cache, group);
|
||||
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 {
|
||||
@ -88,6 +111,9 @@ public abstract class Event {
|
||||
|
||||
protected abstract void applyEvent(Group group) throws EventException;
|
||||
|
||||
@JsonIgnore
|
||||
public abstract String format();
|
||||
|
||||
@JsonIgnore
|
||||
public abstract String type();
|
||||
}
|
||||
|
@ -34,6 +34,11 @@ public class KickMemberEvent extends Event {
|
||||
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();
|
||||
|
@ -38,6 +38,11 @@ public class SetDescriptionEvent extends Event {
|
||||
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();
|
||||
|
@ -38,6 +38,11 @@ public class SetInviteLinkEvent extends Event {
|
||||
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();
|
||||
|
@ -36,6 +36,11 @@ public class SetLimitEvent extends Event {
|
||||
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();
|
||||
|
@ -4,6 +4,7 @@ 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;
|
||||
@ -29,12 +30,17 @@ public class SetParentEvent extends Event {
|
||||
protected void updateCache(GroupCache cache, Group group) {}
|
||||
|
||||
@Override
|
||||
protected void applyEvent(Group group) throws NoAccessException {
|
||||
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();
|
||||
|
@ -38,6 +38,11 @@ public class SetTitleEvent extends Event {
|
||||
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();
|
||||
|
@ -3,6 +3,7 @@ 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;
|
||||
@ -20,6 +21,12 @@ 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);
|
||||
|
||||
@ -28,15 +35,21 @@ public class SetTypeEvent extends Event {
|
||||
|
||||
@Override
|
||||
protected void updateCache(GroupCache cache, Group group) {
|
||||
cache.typesRemove(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();
|
||||
|
@ -38,6 +38,11 @@ public class UpdateRoleEvent extends Event {
|
||||
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();
|
||||
|
@ -2,11 +2,11 @@ package mops.gruppen2.domain.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
public class UserAlreadyExistsException extends EventException {
|
||||
public class UserExistsException extends EventException {
|
||||
|
||||
private static final long serialVersionUID = -8150634358760194625L;
|
||||
|
||||
public UserAlreadyExistsException(String info) {
|
||||
public UserExistsException(String info) {
|
||||
super(HttpStatus.INTERNAL_SERVER_ERROR, "User existiert bereits.", info);
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ 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.UserAlreadyExistsException;
|
||||
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;
|
||||
@ -19,6 +19,7 @@ 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;
|
||||
@ -56,19 +57,21 @@ public class Group {
|
||||
|
||||
private GroupMeta meta = GroupMeta.EMPTY();
|
||||
|
||||
private GroupOptions options = GroupOptions.DEFAULT();
|
||||
//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 Map<String, Membership> memberships = new HashMap<>();
|
||||
private final Map<String, Membership> memberships = new HashMap<>();
|
||||
|
||||
|
||||
// ####################################### Members ###########################################
|
||||
@ -98,7 +101,7 @@ public class Group {
|
||||
return memberships.get(userid).getRole();
|
||||
}
|
||||
|
||||
public void addMember(String target, User user) throws UserAlreadyExistsException, GroupFullException {
|
||||
public void addMember(String target, User user) throws UserExistsException, GroupFullException {
|
||||
ValidationHelper.throwIfMember(this, target);
|
||||
ValidationHelper.throwIfGroupFull(this);
|
||||
|
||||
@ -215,6 +218,26 @@ public class Group {
|
||||
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 ##########################################
|
||||
|
||||
@ -255,14 +278,20 @@ public class Group {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public void setParent(String exec, @Valid Parent parent) throws NoAccessException {
|
||||
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;
|
||||
}
|
||||
@ -289,7 +318,9 @@ public class Group {
|
||||
}
|
||||
|
||||
groupid = null;
|
||||
type = 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;
|
||||
@ -298,11 +329,11 @@ public class Group {
|
||||
title = null;
|
||||
description = null;
|
||||
body = null;
|
||||
memberships = null;
|
||||
memberships = null;*/
|
||||
}
|
||||
|
||||
public String format() {
|
||||
return title + " " + description;
|
||||
return title + " - " + description;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -319,4 +350,8 @@ public class Group {
|
||||
public static Group EMPTY() {
|
||||
return new Group();
|
||||
}
|
||||
|
||||
public long getVersion() {
|
||||
return meta.getVersion();
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ class GroupMeta {
|
||||
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);
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ class GroupOptions {
|
||||
boolean hasMaterialIntegration;
|
||||
boolean hasTermineIntegration;
|
||||
boolean hasPortfolioIntegration;
|
||||
boolean hasForumsIntegration;
|
||||
boolean hasModulesIntegration;
|
||||
|
||||
static GroupOptions DEFAULT() {
|
||||
return new GroupOptions(true,
|
||||
@ -31,6 +33,8 @@ class GroupOptions {
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
package mops.gruppen2.domain.model.group;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class SortHelper {
|
||||
|
||||
/**
|
||||
* Sortiert die übergebene Liste an Gruppen, sodass Veranstaltungen am Anfang der Liste sind.
|
||||
*
|
||||
* @param groups Die Liste von Gruppen die sortiert werden soll
|
||||
*/
|
||||
public static void sortByGroupType(List<Group> groups) {
|
||||
groups.sort((Group g1, Group g2) -> {
|
||||
if (g1.getType() == Type.LECTURE) {
|
||||
return -1;
|
||||
}
|
||||
if (g2.getType() == Type.LECTURE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (g1.getType() == Type.PUBLIC) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g2.getType() == Type.PUBLIC) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
public static List<Membership> sortByMemberRole(List<Membership> 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;
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
|
||||
@Log4j2
|
||||
@Value
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||
@AllArgsConstructor
|
||||
public class User {
|
||||
|
||||
|
@ -4,18 +4,24 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Value;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.UUID;
|
||||
|
||||
@Value
|
||||
public class Link {
|
||||
|
||||
@NotNull
|
||||
@Size(min = 36, max = 36)
|
||||
@JsonProperty("value")
|
||||
String 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();
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,16 @@ 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.JsonHelper;
|
||||
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
|
||||
@ -52,13 +56,13 @@ public class EventStoreService {
|
||||
*/
|
||||
private static EventDTO getDTOFromEvent(Event event) {
|
||||
try {
|
||||
String payload = JsonHelper.serializeEvent(event);
|
||||
String payload = FileHelper.serializeEventJson(event);
|
||||
return new EventDTO(null,
|
||||
event.getGroupid().toString(),
|
||||
event.getVersion(),
|
||||
event.getExec(),
|
||||
event.getTarget(),
|
||||
event.type(),
|
||||
Timestamp.valueOf(event.getDate()),
|
||||
payload);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Event ({}) konnte nicht serialisiert werden!", event, e);
|
||||
@ -81,7 +85,7 @@ public class EventStoreService {
|
||||
|
||||
private static Event getEventFromDTO(EventDTO dto) {
|
||||
try {
|
||||
return JsonHelper.deserializeEvent(dto.getEvent_payload());
|
||||
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());
|
||||
@ -95,4 +99,32 @@ public class EventStoreService {
|
||||
public List<Event> findAllEvents() {
|
||||
return getEventsFromDTOs(eventStore.findAllEvents());
|
||||
}
|
||||
|
||||
public List<Event> findGroupEvents(UUID groupId) {
|
||||
return getEventsFromDTOs(eventStore.findGroupEvents(groupId.toString()));
|
||||
}
|
||||
|
||||
public List<Event> findGroupEvents(List<UUID> ids) {
|
||||
return ids.stream()
|
||||
.map(id -> eventStore.findGroupEvents(id.toString()))
|
||||
.map(EventStoreService::getEventsFromDTOs)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<String> findGroupPayloads(UUID groupId) {
|
||||
return eventStore.findGroupPayloads(groupId.toString());
|
||||
}
|
||||
|
||||
public List<EventDTO> findGroupDTOs(UUID groupid) {
|
||||
return eventStore.findGroupEvents(groupid.toString());
|
||||
}
|
||||
|
||||
public List<UUID> findChangedGroups(long eventid) {
|
||||
return CommonHelper.stringsToUUID(eventStore.findChangedGroupIds(eventid));
|
||||
}
|
||||
|
||||
public long findMaxEventId() {
|
||||
return eventStore.findMaxEventId();
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,15 @@ 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.
|
||||
@ -94,9 +97,11 @@ public class GroupService {
|
||||
* @param exec Ausführender User
|
||||
*/
|
||||
public void addUsersToGroup(Group group, String exec, List<User> newUsers) {
|
||||
setLimit(group, exec, getAdjustedUserLimit(newUsers, group));
|
||||
List<User> users = newUsers.stream().distinct().collect(Collectors.toUnmodifiableList());
|
||||
|
||||
newUsers.forEach(newUser -> addUserSilent(group, exec, newUser.getId(), newUser));
|
||||
setLimit(group, exec, getAdjustedUserLimit(users, group));
|
||||
|
||||
users.forEach(newUser -> addUserSilent(group, exec, newUser.getId(), newUser));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,6 +128,8 @@ public class GroupService {
|
||||
* @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());
|
||||
}
|
||||
|
||||
@ -192,7 +199,7 @@ public class GroupService {
|
||||
* 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, Title title) {
|
||||
public void setTitle(Group group, String exec, @Valid Title title) {
|
||||
if (group.getTitle().equals(title.getValue())) {
|
||||
return;
|
||||
}
|
||||
@ -205,7 +212,7 @@ public class GroupService {
|
||||
* 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, Description description) {
|
||||
public void setDescription(Group group, String exec, @Valid Description description) {
|
||||
if (group.getDescription().equals(description.getValue())) {
|
||||
return;
|
||||
}
|
||||
@ -231,7 +238,7 @@ public class GroupService {
|
||||
* 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, Limit userLimit) {
|
||||
public void setLimit(Group group, String exec, @Valid Limit userLimit) {
|
||||
if (userLimit.getValue() == group.getLimit()) {
|
||||
return;
|
||||
}
|
||||
@ -247,7 +254,8 @@ public class GroupService {
|
||||
applyAndSave(group, new SetParentEvent(group.getId(), exec, parent));
|
||||
}
|
||||
|
||||
public void setLink(Group group, String exec, Link link) {
|
||||
//TODO: UI Link regenerieren button
|
||||
public void setLink(Group group, String exec, @Valid Link link) {
|
||||
if (group.getLink().equals(link.getValue())) {
|
||||
return;
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ 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.SortHelper;
|
||||
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;
|
||||
|
||||
@ -30,25 +31,35 @@ public class SearchService {
|
||||
*
|
||||
* @throws EventException Projektionsfehler
|
||||
*/
|
||||
//TODO: search in lectures
|
||||
public List<Group> search(String search, String principal) {
|
||||
public List<Group> searchString(String search, String principal) {
|
||||
List<Group> groups = new ArrayList<>();
|
||||
groups.addAll(groupCache.publics());
|
||||
groups.addAll(groupCache.lectures());
|
||||
groups = removeUserGroups(groups, principal);
|
||||
SortHelper.sortByGroupType(groups);
|
||||
|
||||
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<Group> 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<Group> removeUserGroups(List<Group> groups, String principal) {
|
||||
return groups.stream()
|
||||
.filter(group -> !group.isMember(principal))
|
||||
|
@ -3,13 +3,24 @@ 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;
|
||||
|
||||
//TODO: sinnvolles format
|
||||
@Log4j2
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class APIHelper {
|
||||
|
||||
/*public static GroupRequestWrapper wrap(long status, List<Group> groupList) {
|
||||
return new GroupRequestWrapper(status, groupList);
|
||||
}*/
|
||||
public static GroupRequestWrapper wrap(long status, List<Group> groupList) {
|
||||
return new GroupRequestWrapper(status, wrap(groupList));
|
||||
}
|
||||
|
||||
public static List<GroupWrapper> wrap(List<Group> groups) {
|
||||
return groups.stream()
|
||||
.map(GroupWrapper::new)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,9 @@ 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)
|
||||
@ -13,4 +15,10 @@ public final class CommonHelper {
|
||||
public static boolean uuidIsEmpty(UUID uuid) {
|
||||
return "00000000-0000-0000-0000-000000000000".equals(uuid.toString());
|
||||
}
|
||||
|
||||
public static List<UUID> stringsToUUID(List<String> changedGroupIds) {
|
||||
return changedGroupIds.stream()
|
||||
.map(UUID::fromString)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
package mops.gruppen2.domain.service.helper;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
|
||||
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.domain.exception.EventException;
|
||||
import mops.gruppen2.domain.exception.WrongFileException;
|
||||
import mops.gruppen2.domain.model.group.User;
|
||||
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 CsvHelper {
|
||||
|
||||
public static List<User> readCsvFile(MultipartFile file) throws EventException {
|
||||
if (file == null || file.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
try {
|
||||
List<User> userList = read(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<User> 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.<User>readValues(stream).readAll();
|
||||
}
|
||||
}
|
@ -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<User> readCsvFile(MultipartFile file) throws EventException {
|
||||
if (file == null || file.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
try {
|
||||
List<User> 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<User> 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.<User>readValues(stream).readAll();
|
||||
}
|
||||
|
||||
public static String writeCsvUserList(List<User> 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<String> 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<EventDTO> 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 #######################################
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package mops.gruppen2.domain.service.helper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.domain.event.Event;
|
||||
|
||||
/**
|
||||
* Übersetzt JSON-Event-Payloads zu Java-Event-Repräsentationen und zurück.
|
||||
*/
|
||||
@Log4j2
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class JsonHelper {
|
||||
|
||||
/**
|
||||
* Ü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 serializeEvent(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 deserializeEvent(String json) throws JsonProcessingException {
|
||||
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||
Event event = mapper.readValue(json, Event.class);
|
||||
log.trace(event);
|
||||
return event;
|
||||
}
|
||||
}
|
@ -7,6 +7,9 @@ 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;
|
||||
@ -19,6 +22,21 @@ import java.util.UUID;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class ProjectionHelper {
|
||||
|
||||
public static List<Group> project(List<Event> events) {
|
||||
Map<UUID, Group> 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<UUID, Group> groups, List<Event> events, GroupCache cache) {
|
||||
if (events.isEmpty()) {
|
||||
return;
|
||||
|
@ -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<Membership> sortByMemberRole(List<Membership> 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;
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ 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.UserAlreadyExistsException;
|
||||
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;
|
||||
@ -39,10 +39,10 @@ public final class ValidationHelper {
|
||||
// ######################################## THROW ############################################
|
||||
|
||||
|
||||
public static void throwIfMember(Group group, String userid) throws UserAlreadyExistsException {
|
||||
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 UserAlreadyExistsException(userid);
|
||||
throw new UserExistsException(userid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ 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;
|
||||
@ -17,7 +19,15 @@ 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
|
||||
@ -28,7 +38,7 @@ public class GroupCache {
|
||||
|
||||
private final Map<UUID, Group> groups = new HashMap<>();
|
||||
private final Map<String, Group> links = new HashMap<>();
|
||||
private final Map<String, List<Group>> users = new HashMap<>();
|
||||
private final Map<String, List<Group>> users = new HashMap<>(); // Wird vielleicht zu groß?
|
||||
private final Map<Type, List<Group>> types = new EnumMap<>(Type.class);
|
||||
|
||||
|
||||
@ -59,6 +69,14 @@ public class GroupCache {
|
||||
return links.get(link);
|
||||
}
|
||||
|
||||
public List<Group> groups() {
|
||||
if (groups.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return List.copyOf(groups.values());
|
||||
}
|
||||
|
||||
public List<Group> userGroups(String userid) {
|
||||
if (!users.containsKey(userid)) {
|
||||
return Collections.emptyList();
|
||||
@ -67,6 +85,24 @@ public class GroupCache {
|
||||
return Collections.unmodifiableList(users.get(userid));
|
||||
}
|
||||
|
||||
public List<Group> userLectures(String userid) {
|
||||
return userGroups(userid).stream()
|
||||
.filter(Group::isLecture)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
public List<Group> userPublics(String userid) {
|
||||
return userGroups(userid).stream()
|
||||
.filter(Group::isPublic)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
public List<Group> userPrivates(String userid) {
|
||||
return userGroups(userid).stream()
|
||||
.filter(Group::isPrivate)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
public List<Group> publics() {
|
||||
if (!types.containsKey(Type.PUBLIC)) {
|
||||
return Collections.emptyList();
|
||||
@ -96,6 +132,9 @@ public class GroupCache {
|
||||
|
||||
|
||||
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.");
|
||||
@ -113,18 +152,37 @@ public class GroupCache {
|
||||
}
|
||||
|
||||
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(Group group) {
|
||||
groups.remove(group.getId());
|
||||
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);
|
||||
}
|
||||
|
||||
@ -133,15 +191,18 @@ public class GroupCache {
|
||||
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(Group group) {
|
||||
if (!types.containsKey(group.getType())) {
|
||||
public void typesRemove(Type type, Group group) {
|
||||
if (!types.containsKey(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
types.get(group.getType()).remove(group);
|
||||
types.get(type).remove(group);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
package mops.gruppen2.infrastructure.api;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Kombiniert den Status und die Gruppenliste zur ausgabe über die API.
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class GroupRequestWrapper {
|
||||
|
||||
|
@ -1,4 +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<User> admins;
|
||||
List<User> 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();
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,27 @@
|
||||
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.
|
||||
*/
|
||||
@ -18,8 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping("/gruppen2/api")
|
||||
public class APIController {
|
||||
|
||||
//TODO: redo api
|
||||
|
||||
private final GroupCache cache;
|
||||
private final EventStoreService eventStoreService;
|
||||
|
||||
/**
|
||||
@ -28,38 +41,43 @@ public class APIController {
|
||||
*
|
||||
* @param eventId Die Event-ID, welche der Anfragesteller beim letzten Aufruf erhalten hat
|
||||
*/
|
||||
/*@GetMapping("/update/{id}")
|
||||
//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.projectChangedGroups(eventId));
|
||||
}*/
|
||||
ProjectionHelper.project(eventStoreService.findGroupEvents(eventStoreService.findChangedGroups(eventId))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Gruppen-IDs von Gruppen, in welchen der übergebene Nutzer teilnimmt, zurück.
|
||||
*/
|
||||
/*@GetMapping("/usergroups/{id}")
|
||||
@GetMapping("/usergroups/{id}")
|
||||
@Secured("ROLE_api_user")
|
||||
@ApiOperation("Gibt Gruppen zurück, in welchen ein Nutzer teilnimmt")
|
||||
public List<String> getApiUserGroups(@ApiParam("Nutzer-Id")
|
||||
@PathVariable("id") String userId) {
|
||||
|
||||
return CommonHelper.uuidsToString(eventStoreService.findExistingUserGroups(userId));
|
||||
}*/
|
||||
return cache.userGroups(userId).stream()
|
||||
.map(Group::getId)
|
||||
.map(UUID::toString)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Konstruiert eine einzelne, vollständige Gruppe.
|
||||
*/
|
||||
/*@GetMapping("/group/{id}")
|
||||
@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 projectionHelper.projectGroupById(UUID.fromString(groupId));
|
||||
}*/
|
||||
return cache.group(UUID.fromString(groupId));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ 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.CsvHelper;
|
||||
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;
|
||||
@ -67,7 +67,7 @@ public class GroupCreationController {
|
||||
|
||||
// ROLE_studentin kann kein CSV importieren
|
||||
if (token.getAccount().getRoles().contains("orga")) {
|
||||
groupService.addUsersToGroup(group, principal, CsvHelper.readCsvFile(file));
|
||||
groupService.addUsersToGroup(group, principal, FileHelper.readCsvFile(file));
|
||||
}
|
||||
|
||||
return "redirect:/gruppen2/details/" + group.getId();
|
||||
|
@ -8,11 +8,13 @@ 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.CsvHelper;
|
||||
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;
|
||||
@ -24,7 +26,9 @@ 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")
|
||||
@ -37,6 +41,7 @@ public class GroupDetailsController {
|
||||
|
||||
private final GroupCache groupCache;
|
||||
private final GroupService groupService;
|
||||
private final EventStoreService eventStoreService;
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@GetMapping("/details/{id}")
|
||||
@ -94,6 +99,77 @@ public class GroupDetailsController {
|
||||
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,
|
||||
@ -127,8 +203,6 @@ public class GroupDetailsController {
|
||||
String principal = token.getName();
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
System.out.println(group);
|
||||
|
||||
groupService.setTitle(group, principal, title);
|
||||
groupService.setDescription(group, principal, description);
|
||||
|
||||
@ -157,7 +231,7 @@ public class GroupDetailsController {
|
||||
String principal = token.getName();
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
groupService.addUsersToGroup(group, principal, CsvHelper.readCsvFile(file));
|
||||
groupService.addUsersToGroup(group, principal, FileHelper.readCsvFile(file));
|
||||
|
||||
return "redirect:/gruppen2/details/" + groupId + "/edit";
|
||||
}
|
||||
@ -172,6 +246,9 @@ public class GroupDetailsController {
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
ValidationHelper.throwIfNoAdmin(group, principal);
|
||||
if (target.equals(principal)) {
|
||||
ValidationHelper.throwIfLastAdmin(group, principal);
|
||||
}
|
||||
|
||||
groupService.toggleMemberRole(group, principal, target);
|
||||
|
||||
|
@ -33,7 +33,10 @@ public class GruppenfindungController {
|
||||
@GetMapping("/gruppen2")
|
||||
public String getIndexPage(KeycloakAuthenticationToken token,
|
||||
Model model) {
|
||||
model.addAttribute("groups", groupCache.userGroups(token.getName()));
|
||||
|
||||
model.addAttribute("lectures", groupCache.userLectures(token.getName()));
|
||||
model.addAttribute("publics", groupCache.userPublics(token.getName()));
|
||||
model.addAttribute("privates", groupCache.userPrivates(token.getName()));
|
||||
|
||||
return "index";
|
||||
}
|
||||
|
@ -41,13 +41,40 @@ public class SearchAndInviteController {
|
||||
}
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/search")
|
||||
public String postSearch(KeycloakAuthenticationToken token,
|
||||
Model model,
|
||||
@RequestParam("string") String search) {
|
||||
@PostMapping("/search/string")
|
||||
public String postSearchString(KeycloakAuthenticationToken token,
|
||||
Model model,
|
||||
@RequestParam("string") String search) {
|
||||
|
||||
String principal = token.getName();
|
||||
List<Group> groups = searchService.search(search, principal);
|
||||
List<Group> 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<Group> 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<Group> groups = searchService.searchType(type, principal);
|
||||
|
||||
model.addAttribute("groups", groups);
|
||||
|
||||
|
@ -3,6 +3,7 @@ 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;
|
||||
@ -16,4 +17,16 @@ public interface EventRepository extends CrudRepository<EventDTO, Long> {
|
||||
|
||||
@Query("SELECT * FROM event")
|
||||
List<EventDTO> findAllEvents();
|
||||
|
||||
@Query("SELECT * FROM event WHERE group_id = :groupid")
|
||||
List<EventDTO> findGroupEvents(@Param("groupid") String groupId);
|
||||
|
||||
@Query("SELECT event_payload FROM event WHERE group_id = :groupid")
|
||||
List<String> 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<String> findChangedGroupIds(@Param("eventid") long eventid);
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ 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
|
||||
@ -19,6 +21,6 @@ public class EventDTO {
|
||||
String exec_id;
|
||||
String target_id;
|
||||
|
||||
String event_type;
|
||||
Timestamp event_date;
|
||||
String event_payload;
|
||||
}
|
||||
|
@ -11,12 +11,12 @@ spring.profiles.active = dev
|
||||
#keycloak.use-resource-role-mappings = true
|
||||
#keycloak.autodetect-bearer-only = true
|
||||
#keycloak.confidential-port = 443
|
||||
keycloak.auth-server-url = https://gruppenkeycloak.herokuapp.com/auth
|
||||
hhu_keycloak.token-uri = https://gruppenkeycloak.herokuapp.com/auth/realms/master/protocol/openid-connect/token
|
||||
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 = master
|
||||
keycloak.realm = gruppen
|
||||
keycloak.resource = gruppen-app
|
||||
keycloak.credentials.secret = f73354fd-614e-4e24-b801-a8d0f4abf531
|
||||
keycloak.credentials.secret = 2e2e5770-c454-4d31-be99-9d8c34c93089
|
||||
keycloak.verify-token-audience = true
|
||||
keycloak.use-resource-role-mappings = true
|
||||
keycloak.autodetect-bearer-only = true
|
||||
|
27
src/main/resources/data.sql
Normal file
27
src/main/resources/data.sql
Normal file
@ -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]}');
|
@ -7,6 +7,6 @@ CREATE TABLE event
|
||||
group_version INT NOT NULL,
|
||||
exec_id VARCHAR(50) NOT NULL,
|
||||
target_id VARCHAR(50),
|
||||
event_type VARCHAR(32) NOT NULL,
|
||||
event_date DATETIME NOT NULL,
|
||||
event_payload VARCHAR(2500) NOT NULL
|
||||
);
|
||||
|
@ -3,34 +3,15 @@
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/*Buttons*/
|
||||
.edit {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.btn-bar {
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
/*Badges*/
|
||||
.badge-pill {
|
||||
align-self: start;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.members .badge {
|
||||
align-self: start;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/*Member List*/
|
||||
.members {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
max-height: calc(100vh - 250px);
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.members li span {
|
||||
li span {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
@ -1,19 +1,16 @@
|
||||
/*Grouplist Hover Effect*/
|
||||
.content {
|
||||
padding-right: 20px;
|
||||
background: #e6f4ff;
|
||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
|
||||
}
|
||||
|
||||
.content:hover {
|
||||
padding-right: 10px;
|
||||
background: #d4ecff;
|
||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
|
||||
}
|
||||
|
||||
.content:hover .content-heading {
|
||||
padding-bottom: 10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.content-text-in {
|
||||
@ -26,6 +23,5 @@
|
||||
|
||||
/*Badges*/
|
||||
.badge-pill {
|
||||
margin-left: 10px;
|
||||
align-self: start;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
@ -23,5 +23,5 @@
|
||||
.badge-pill {
|
||||
align-self: start;
|
||||
margin-top: 2px;
|
||||
margin-right: 5px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
@ -16,6 +16,9 @@
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
|
||||
transition: 100ms;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/*Content Heading*/
|
||||
@ -33,6 +36,12 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
h1, h3 {
|
||||
cursor: default;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/*Content Paragraph*/
|
||||
.content-text {
|
||||
margin-bottom: 15px;
|
||||
@ -65,10 +74,19 @@
|
||||
color: #4fa4ff;
|
||||
}
|
||||
|
||||
/*Button*/
|
||||
.btn {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.btn-spacer {
|
||||
}
|
||||
|
||||
/*Badges*/
|
||||
.badge-pill {
|
||||
cursor: default;
|
||||
color: whitesmoke;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.lecture {
|
||||
@ -87,18 +105,31 @@
|
||||
background: var(--warning);
|
||||
}
|
||||
|
||||
/*Grid System*/
|
||||
.row {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
/*Input*/
|
||||
.input-group {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.col {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
.input-group-append {
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/*Miscellanous*/
|
||||
.def-cursor {
|
||||
cursor: default;
|
||||
.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;
|
||||
}
|
||||
|
@ -9,37 +9,35 @@
|
||||
<body>
|
||||
|
||||
<main th:fragment="bodycontent">
|
||||
<div class="container">
|
||||
<h1>Neue Gruppe</h1>
|
||||
|
||||
<h1 class="def-cursor">Neue Gruppe</h1>
|
||||
<form enctype="multipart/form-data" method="post" th:action="@{/gruppen2/create}">
|
||||
<div class="content px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||
<h3>Eigenschaften:</h3>
|
||||
|
||||
<form enctype="multipart/form-data" method="post" th:action="@{/gruppen2/create}">
|
||||
<div class="content">
|
||||
<h3 class="def-cursor">Eigenschaften:</h3>
|
||||
<!--Titel + Beschreibung-->
|
||||
<div class="content-text" th:insert="~{fragments/forms :: meta}"></div>
|
||||
|
||||
<!--Titel + Beschreibung-->
|
||||
<div class="content-text" th:insert="~{fragments/forms :: meta}"></div>
|
||||
<!--TODO: Enter AsciiDoc Description-->
|
||||
|
||||
<!--TODO: Enter AsciiDoc Description-->
|
||||
<div class="content-text-in">
|
||||
<!--Gruppentyp-->
|
||||
<div th:insert="~{fragments/forms :: grouptype}"></div>
|
||||
|
||||
<div class="content-text-in">
|
||||
<!--Gruppentyp-->
|
||||
<div th:replace="~{fragments/forms :: grouptype}"></div>
|
||||
|
||||
<!--Benutzerlimit-->
|
||||
<div th:replace="~{fragments/forms :: userlimit}"></div>
|
||||
</div>
|
||||
|
||||
<!--CSV Import-->
|
||||
<div class="content-text mb-0" th:insert="~{fragments/forms :: csvimport}"></div>
|
||||
<!--Benutzerlimit-->
|
||||
<div class="mt-2" th:insert="~{fragments/forms :: userlimit}"></div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<!--Submit-->
|
||||
<button class="btn btn-primary btn-block" type="submit">Gruppe Erstellen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!--CSV Import-->
|
||||
<div class="content-text mb-0" th:insert="~{fragments/forms :: csvimport}"></div>
|
||||
</div>
|
||||
|
||||
<div class="content d-flex flex-row flex-wrap px-1 px-sm-3">
|
||||
<!--Submit-->
|
||||
<button class="btn btn-primary btn-block ml-auto" type="submit">Gruppe Erstellen
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
|
@ -9,60 +9,198 @@
|
||||
<body>
|
||||
|
||||
<main th:fragment="bodycontent">
|
||||
<div class="container-fluid">
|
||||
<h1 th:text="${group.getTitle()}"></h1>
|
||||
|
||||
<h1 class="def-cursor" th:text="${group.getTitle()}"></h1>
|
||||
<div class="d-flex flex-row flex-wrap mr-n4 mt-n2">
|
||||
<!--Gruppendetails-->
|
||||
<div class="flex-grow-1 mr-4 mt-2" style="flex-basis: 65%;">
|
||||
|
||||
<div class="row">
|
||||
<!--Gruppendetails-->
|
||||
<div class="col-9 px-0">
|
||||
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0"
|
||||
th:insert="~{fragments/groups :: groupcontent}"></div>
|
||||
|
||||
<div class="content" th:insert="~{fragments/groups :: groupcontent}"></div>
|
||||
|
||||
<div class="content">
|
||||
<!--Button-Bar-->
|
||||
<div class="row">
|
||||
<a class="btn btn-primary" href="/gruppen2">Fertig</a>
|
||||
<!--Dummy Integrationen, der Inhalt kommt natürlich aus der Gruppe bzw. von anderen Systemen-->
|
||||
<div class="d-flex flex-row flex-wrap mr-n2 mt-n2">
|
||||
<!--Materialsammlung-->
|
||||
<div th:if="${group.hasMaterial()}" class="content flex-grow-1 mr-2 mt-2 py-2 px-1 px-sm-3">
|
||||
<div class="content-heading">
|
||||
<span>Gruppenmaterialien</span>
|
||||
</div>
|
||||
|
||||
<!--Spacer-->
|
||||
<span class="col"></span>
|
||||
<div class="content-text-in">
|
||||
<h3>Neue Materialien:</h3>
|
||||
<ul>
|
||||
<li><a href="/">Blatt 3.pdf</a></li>
|
||||
<li><a href="/">Vorlesung 5.pdf</a></li>
|
||||
<li><a href="/">Wikipedia.de/blabla</a></li>
|
||||
</ul>
|
||||
<h3>Angepinnt:</h3>
|
||||
<ul>
|
||||
<li><a href="/">Sicherheitsregeln.pdf</a></li>
|
||||
<li><a href="/">Bewertungskriterien.pdf</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content-text d-flex flex-row flex-wrap mt-n2 mr-n2">
|
||||
<a class="btn btn-success flex-grow-1 mt-2 mr-2" href="/">Neuer
|
||||
Upload.</a>
|
||||
<a class="btn btn-info ml-auto flex-grow-1 mt-2 mr-2" href="/">
|
||||
Zur Materialsammlung.</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Foren-->
|
||||
<div th:if="${group.hasForums()}" class="content flex-grow-1 mr-2 mt-2 py-2 px-1 px-sm-3">
|
||||
<div class="content-heading">
|
||||
<span>Forum</span>
|
||||
</div>
|
||||
|
||||
<div class="content-text-in">
|
||||
<h3>Letzte Aktivität:</h3>
|
||||
<ul>
|
||||
<li><a href="/">"Re: Ey schick lösung"</a></li>
|
||||
<li><a href="/">"Re: Aufgabe 2"</a></li>
|
||||
<li><a href="/">"Neu: Ankündigung"</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content-text d-flex flex-row flex-wrap mt-n2 mr-n2">
|
||||
<a class="btn btn-success flex-grow-1 mt-2 mr-2" href="/">
|
||||
Frage stellen.</a>
|
||||
<a class="btn btn-info flex-grow-1 ml-auto mt-2 mr-2" href="/">
|
||||
Zum Forum.</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Termine-->
|
||||
<div th:if="${group.hasCalendar()}" class="content flex-grow-1 mr-2 mt-2 py-2 px-1 px-sm-3">
|
||||
<div class="content-heading">
|
||||
<span>Gruppentermine</span>
|
||||
</div>
|
||||
|
||||
<div class="content-text-in">
|
||||
<h3>Nächste Fristen:</h3>
|
||||
<ul>
|
||||
<li><a href="/">"Abgabe Übungsblatt 3"</a></li>
|
||||
<li><a href="/">"Feedback VL 5"</a></li>
|
||||
<li><a href="/">"Übungsgruppe belegen"</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content-text d-flex flex-row flex-wrap mt-n2 mr-n2">
|
||||
<a class="btn btn-success flex-grow-1 mt-2 mr-2" href="/">
|
||||
Abstimmung starten.</a>
|
||||
<a class="btn btn-info flex-grow-1 ml-auto mt-2 mr-2" href="/">
|
||||
Zur Terminfindung.</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Portfolios-->
|
||||
<div th:if="${group.hasPortfolios()}" class="content flex-grow-1 mr-2 mt-2 py-2 px-1 px-sm-3">
|
||||
<div class="content-heading">
|
||||
<span>Gruppenportfolio</span>
|
||||
</div>
|
||||
|
||||
<div class="content-text-in">
|
||||
<h3>Neueste Einträge:</h3>
|
||||
<ul>
|
||||
<li><a href="/">"Praktikum Tag 5"</a></li>
|
||||
<li><a href="/">"Praktikum Tag 4"</a></li>
|
||||
<li><a href="/">"Nacharbeit Tag 3"</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content-text d-flex flex-row flex-wrap mt-n2 mr-n2">
|
||||
<a class="btn btn-success flex-grow-1 mt-2 mr-2" href="/">
|
||||
Neue Seite.</a>
|
||||
<a class="btn btn-info flex-grow-1 ml-auto mt-2 mr-2" href="/">
|
||||
Zum Portfolio.</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Modulhandbuch-->
|
||||
<div th:if="${group.hasModules()}" class="content flex-grow-1 mr-2 mt-2 py-2 px-1 px-sm-3">
|
||||
<div class="content-heading">
|
||||
<span>Modulhandbuch</span>
|
||||
</div>
|
||||
|
||||
<div class="content-text-in">
|
||||
<h3>Veranstaltungsinfo:</h3>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Grundlegende Begriffe der Informatik</li>
|
||||
<li>Primitive Datentypen und Variablen</li>
|
||||
<li>Kontrollstrukturen</li>
|
||||
<li>Eigene Datentypen (Klassen) und Arrays</li>
|
||||
<li>Programmstrukturen im Speicher (Heap, Stack)</li>
|
||||
<li>Konzepte der Objektorientierung (Polymorphie, Schnittstellen)
|
||||
</li>
|
||||
<li>Rekursion</li>
|
||||
<li>Fehlerbehandlung</li>
|
||||
<li>Dynamische Datenstrukturen (Listen, Binärbäume, Hashing)</li>
|
||||
<li>Suchen und Sortieren (ausgewählte Algorithmen, u.a. binäre
|
||||
Suche, BubbleSort, QuickSort)
|
||||
</li>
|
||||
<li>Datenströme (Standard-Eingabe und -Ausgabe, einfache 2D-Grafik,
|
||||
Dateien)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="content-text d-flex flex-row flex-wrap mt-n2 mr-n2">
|
||||
<a class="btn btn-info flex-grow-1 ml-auto mt-2 mr-2" href="/">
|
||||
Zum Modulhandbuch.</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content py-2 px-1 px-sm-3">
|
||||
<!--Button-Bar-->
|
||||
<div class="d-flex flex-row flex-wrap mr-n2 mt-n2">
|
||||
<a class="btn btn-primary flex-grow-1 mr-2 mt-2" href="/gruppen2">Fertig</a>
|
||||
|
||||
<div class="ml-auto mr-2 mt-2 flex-grow-1 btn-spacer ml-auto">
|
||||
<form method="post" th:action="@{/gruppen2/details/{id}/leave(id=${group.getId()})}">
|
||||
<button class="btn btn-danger btn-bar" type="submit">Gruppe verlassen
|
||||
<button class="btn btn-danger w-100" type="submit">
|
||||
Gruppe verlassen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Teilnehmerliste-->
|
||||
<div class="col-3 def-cursor">
|
||||
<!--Anzahl Text-->
|
||||
<div class="mb-2">
|
||||
<span>Teilnehmer: </span>
|
||||
<span th:text="${group.size() + ' von ' + group.getLimit()}"></span>
|
||||
</div>
|
||||
|
||||
<!--Bearbeiten-Button-->
|
||||
<div class="mb-2" th:if="${group.isAdmin(principal.getId())}">
|
||||
<form method="get"
|
||||
th:action="@{/gruppen2/details/{id}/edit(id=${group.getId()})}">
|
||||
<button class="btn btn-secondary btn-block">Gruppe verwalten</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!--Liste-->
|
||||
<div class="members">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between"
|
||||
th:each="member : ${group.getMembers()}">
|
||||
<span th:text="${member.format()}"></span>
|
||||
<span th:replace="~{fragments/groups :: userbadges}"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!--Teilnehmerliste-->
|
||||
<div class="def-cursor flex-grow-1 mr-4 mt-2 mw-100 overflow-hidden py-2 px-1 px-sm-3">
|
||||
<!--Anzahl Text-->
|
||||
<div class="mb-2">
|
||||
<span>Teilnehmer: </span>
|
||||
<span th:text="${group.size() + ' von ' + group.getLimit()}"></span>
|
||||
</div>
|
||||
|
||||
<!--Bearbeiten-Button-->
|
||||
<div class="mb-2" th:if="${group.isAdmin(principal.getId())}">
|
||||
<form method="get"
|
||||
th:action="@{/gruppen2/details/{id}/edit(id=${group.getId()})}">
|
||||
<button class="btn btn-secondary btn-block">Gruppe verwalten</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!--Liste-->
|
||||
<div class="members">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between"
|
||||
th:each="member : ${group.getMembers()}">
|
||||
<span th:text="${member.format()}"></span>
|
||||
<span th:replace="~{fragments/groups :: userbadges}"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
@ -9,113 +9,148 @@
|
||||
<body>
|
||||
|
||||
<main th:fragment="bodycontent">
|
||||
<div class="container-fluid">
|
||||
<h1 class="def-cursor" th:text="${group.getTitle()}"></h1>
|
||||
<h1 th:text="${group.getTitle()}"></h1>
|
||||
|
||||
<!--Fertig oder löschen-->
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<form method="get" th:action="@{/gruppen2/details/{id}(id=${group.getId()})}">
|
||||
<button class="btn btn-primary">Fertig</button>
|
||||
</form>
|
||||
|
||||
<!--Spacer-->
|
||||
<span class="col"></span>
|
||||
<!--Fertig oder löschen-->
|
||||
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||
<div class="d-flex flex-row flex-wrap mt-n2 mr-n2">
|
||||
<a class="btn btn-primary flex-grow-1 mt-2 mr-2" style="max-width: 250px;"
|
||||
th:href="@{/gruppen2/details/{id}(id=${group.getId()})}">Fertig</a>
|
||||
|
||||
<div class="mt-2 mr-2 flex-grow-1 ml-auto btn-spacer">
|
||||
<form method="post" th:action="@{/gruppen2/details/{id}/edit/destroy(id=${group.getId()})}">
|
||||
<button class="btn btn-danger btn-bar" type="submit">Gruppe löschen
|
||||
<button class="btn btn-danger w-100" type="submit">Gruppe löschen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Invite Link-->
|
||||
<div class="content input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Einladungslink:</span>
|
||||
</div>
|
||||
<input class="form-control" id="linkview" readonly th:value="${link}" type="text">
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-secondary"
|
||||
onclick="copyLink()">Link kopieren
|
||||
</button>
|
||||
</div>
|
||||
<!--Invite Link-->
|
||||
<div class="content input-group py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Einladungslink:</span>
|
||||
</div>
|
||||
|
||||
<!--Meta-->
|
||||
<div class="content">
|
||||
<div class="content-heading">
|
||||
<span>Eigenschaften</span>
|
||||
</div>
|
||||
|
||||
<!--Beschreibung + Titel-->
|
||||
<div class="content-text">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/meta(id=${group.getId()})}"
|
||||
method="post">
|
||||
|
||||
<div th:replace="~{fragments/forms :: meta}"></div>
|
||||
<div class="row">
|
||||
<span class="col"></span>
|
||||
<button type="submit" class="btn btn-secondary mt-2">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!--Userlimit-->
|
||||
<div class="content-text-in">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/userlimit(id=${group.getId()})}"
|
||||
method="post">
|
||||
|
||||
<div th:replace="~{fragments/forms :: userlimit}"></div>
|
||||
<div class="row">
|
||||
<span class="col"></span>
|
||||
<button type="submit" class="btn btn-secondary mt-2">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!--CSV Import-->
|
||||
<div class="content-text mb-0">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/csv(id=${group.getId()})}"
|
||||
th:if="${account.getRoles().contains('orga')}"
|
||||
enctype="multipart/form-data" method="post">
|
||||
|
||||
<div th:replace="~{fragments/forms :: csvimport}"></div>
|
||||
<div class="row">
|
||||
<span class="col"></span>
|
||||
<button type="submit" class="btn btn-secondary mt-2">Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Teilnehmerliste-->
|
||||
<div class="content members">
|
||||
<div class="content-heading">
|
||||
<span>Teilnehmer</span>
|
||||
</div>
|
||||
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between" th:each="member : ${group.getMembers()}">
|
||||
<div>
|
||||
<span th:text="${member.format()}"></span>
|
||||
<span th:replace="~{fragments/groups :: userbadges}"></span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/delete/{userid}(id=${group.getId()}, userid=${member.getId()})}"
|
||||
th:unless="${member.getId() == account.getName()}"
|
||||
method="post">
|
||||
<button type="submit" class="btn btn-danger mr-2">Entfernen</button>
|
||||
</form>
|
||||
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/role/{userid}(id=${group.getId()}, userid=${member.getId()})}"
|
||||
method="post">
|
||||
<button type="submit" class="btn btn-warning">Rolle ändern</button>
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<input class="form-control" id="linkview" readonly th:value="${link}" type="text">
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-secondary" onclick="copyLink()">Link kopieren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Meta-->
|
||||
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||
<div class="content-heading">
|
||||
<span>Eigenschaften</span>
|
||||
</div>
|
||||
|
||||
<!--Beschreibung + Titel-->
|
||||
<div class="content-text">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/meta(id=${group.getId()})}"
|
||||
method="post">
|
||||
|
||||
<div th:replace="~{fragments/forms :: meta}"></div>
|
||||
|
||||
<div class="d-flex flex-row flex-wrap">
|
||||
<button type="submit" class="btn btn-secondary mt-2 ml-auto">Speichern
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!--Userlimit-->
|
||||
<div class="content-text-in px-1 px-sm-3">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/userlimit(id=${group.getId()})}"
|
||||
method="post">
|
||||
|
||||
<div th:replace="~{fragments/forms :: userlimit}"></div>
|
||||
|
||||
<div class="d-flex flex-row flex-wrap">
|
||||
<button type="submit" class="btn btn-secondary mt-2 ml-auto">Speichern
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!--CSV Import-->
|
||||
<div class="content-text mb-0">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/csv(id=${group.getId()})}"
|
||||
th:if="${account.getRoles().contains('orga')}"
|
||||
enctype="multipart/form-data" method="post">
|
||||
|
||||
<div th:replace="~{fragments/forms :: csvimport}"></div>
|
||||
|
||||
<div class="d-flex flex-row flex-wrap">
|
||||
<button type="submit" class="btn btn-secondary mt-2 ml-auto">Speichern
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Export + Log-->
|
||||
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||
<div class="content-heading">
|
||||
<span>Event-Historie</span>
|
||||
</div>
|
||||
<div class="d-flex flex-row flex-wrap mt-n2 mr-n2">
|
||||
<a class="btn btn-primary mt-2 mr-2 flex-grow-1"
|
||||
th:href="@{/gruppen2/details/{id}/history(id=${group.getId()})}">Event-Log</a>
|
||||
|
||||
<a class="btn btn-info flex-grow-1 mt-2 mr-2 ml-auto"
|
||||
th:href="@{/gruppen2/details/{id}/export/history/plain(id=${group.getId()})}"
|
||||
title="Exportiert die gesamte Event-Historie dieser Gruppe. Kann beim erstellen importiert werden.">
|
||||
Event-Log exportieren (TXT)
|
||||
</a>
|
||||
|
||||
<a class="btn btn-info flex-grow-1 mt-2 mr-2"
|
||||
th:href="@{/gruppen2/details/{id}/export/history/sql(id=${group.getId()})}"
|
||||
title="Exportiert die gesamte Event-Historie dieser Gruppe. Kann als data.sql verwendet werden.">
|
||||
Event-Log exportieren (SQL)
|
||||
</a>
|
||||
|
||||
<a class="btn btn-info flex-grow-1 mt-2 mr-2"
|
||||
th:href="@{/gruppen2/details/{id}/export/members(id=${group.getId()})}"
|
||||
title="Exportiert die Teilnehmerliste. Kann beim erstellen (oder nachträglich) importiert werden.">
|
||||
Teilnehmer exportieren
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Teilnehmerliste-->
|
||||
<div class="content members py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||
<div class="content-heading">
|
||||
<span>Teilnehmer</span>
|
||||
</div>
|
||||
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex flex-row flex-wrap" th:each="member : ${group.getMembers()}">
|
||||
<div class="overflow-hidden ml-n2" style="max-width: 50%; text-overflow: ellipsis;">
|
||||
<span class="overflow-hidden ml-2" th:text="${member.format()}"></span>
|
||||
<span th:replace="~{fragments/groups :: userbadges}"></span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-row flex-wrap mt-n2 mr-n2 ml-auto" style="max-width: 50%;">
|
||||
<div class="flex-grow-1 mt-2 mr-2"
|
||||
th:unless="${member.getId() == account.getName()}">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/delete/{userid}(id=${group.getId()}, userid=${member.getId()})}"
|
||||
method="post">
|
||||
<button type="submit" class="btn btn-danger w-100">
|
||||
Entfernen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="flex-grow-1 mt-2 mr-2">
|
||||
<form th:action="@{/gruppen2/details/{id}/edit/role/{userid}(id=${group.getId()}, userid=${member.getId()})}"
|
||||
method="post">
|
||||
<button type="submit" class="btn btn-warning w-100">
|
||||
Rolle ändern
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</main>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<main th:fragment="bodycontent">
|
||||
<div class="container">
|
||||
|
||||
<h1 class="display-3 def-cursor">UPSI</h1>
|
||||
<h1 class="display-3">UPSI</h1>
|
||||
|
||||
<div class="content">
|
||||
<p class="lead def-cursor">Da ist wohl etwas schiefgelaufen :(</p>
|
||||
|
@ -13,7 +13,7 @@
|
||||
<div class="input-group mb-2"
|
||||
title="Ein Gruppentitel zwischen 4 und 128 Zeichen. Der Titel ist öffentlich.">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text text-monospace">Gruppentitel:</span>
|
||||
<span class="input-group-text">Gruppentitel:</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="title" minlength="4" maxlength="128"
|
||||
th:value="${group?.getTitle()}" required>
|
||||
@ -24,7 +24,7 @@
|
||||
<div class="input-group"
|
||||
title="Eine kurze Gruppenbeschreibung zwischen 4 und 512 Zeichen. Die Beschreibung ist öffentlich.">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text text-monospace">Beschreibung:</span>
|
||||
<span class="input-group-text">Beschreibung:</span>
|
||||
</div>
|
||||
<textarea class="form-control" name="description" minlength="4" maxlength="512"
|
||||
th:text="${group?.getDescription()}" required></textarea>
|
||||
@ -34,8 +34,8 @@
|
||||
<!--Gruppentyp-->
|
||||
<th:block th:fragment="grouptype">
|
||||
<label for="grouptype">Gruppentyp:</label>
|
||||
<div class="btn-toolbar row mb-2 mx-0" id="grouptype">
|
||||
<div class="btn-group btn-group-toggle col-sm-4 px-0" data-toggle="buttons">
|
||||
<div class="btn-toolbar mt-n2 mr-n2 d-flex flex-row flex-wrap overflow-hidden" id="grouptype">
|
||||
<div class="btn-group btn-group-toggle flex-grow-1 mt-2 mr-2" style="flex-basis: 10%;" data-toggle="buttons">
|
||||
<label class="btn btn-secondary active" onclick="enable('#parentselect'); disable('#parentdummy')">
|
||||
<input type="radio" name="type" value="PRIVATE" checked> Privat
|
||||
</label>
|
||||
@ -48,10 +48,10 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="input-group col-sm-8 pr-0"
|
||||
<div class="input-group flex-grow-1 mt-2 mr-2"
|
||||
title="Optional kann eine Veranstaltungszugehörigkeit festgelegt werden.">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text text-monospace">Gehört zu:</span>
|
||||
<span class="input-group-text">Gehört zu:</span>
|
||||
</div>
|
||||
<input type="hidden" id="parentdummy" name="parent" value="00000000-0000-0000-0000-000000000000" disabled>
|
||||
<select class="custom-select" id="parentselect" name="parent">
|
||||
@ -66,10 +66,10 @@
|
||||
<!--Userlimit-->
|
||||
<th:block th:fragment="userlimit">
|
||||
<label for="userlimit">Teilnehmeranzahl:</label>
|
||||
<div class="btn-toolbar row mx-0" id="userlimit">
|
||||
<div class="btn-toolbar mt-n2 mr-n2 d-flex flex-row flex-wrap flex-grow-1" id="userlimit">
|
||||
<input type="hidden" name="limit" id="limit" value="999999"
|
||||
th:disabled="${group != null && group.getLimit() < 999999} ? 'disabled' : 'false'">
|
||||
<div class="btn-group btn-group-toggle col-sm-4 px-0" data-toggle="buttons">
|
||||
<div class="btn-group btn-group-toggle flex-grow-1 mt-2 mr-2" style="flex-basis: 10%;" data-toggle="buttons">
|
||||
<label class="btn btn-secondary active" onclick="disable('#limitselect'); enable('#limit')">
|
||||
<input type="radio"
|
||||
th:checked="${group != null && group.getLimit() < 999999} ? 'false' : 'checked'">
|
||||
@ -82,17 +82,17 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="input-group col-sm-8 pr-0"
|
||||
<div class="input-group flex-grow-1 mt-2 mr-2"
|
||||
title="999999 ist die maximal zulässige Teilnehmerzahl. Ist diese Obergrenze erreicht, gilt die Gruppe als unbegrenzt.">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text text-monospace">Limit:</span>
|
||||
<div class="input-group-prepend" style="max-width: 25%">
|
||||
<span class="input-group-text">Limit:</span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="limit"
|
||||
th:value="${group != null} ? ${group.getLimit()} : '999999'"
|
||||
min="1" max="999999" id="limitselect" required
|
||||
th:disabled="${group != null && group.getLimit() < 999999} ? 'false' : 'disabled'">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text text-monospace">Teilnehmer</span>
|
||||
<div class="input-group-append" style="max-width: 25%">
|
||||
<span class="input-group-text">Teilnehmer</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -102,7 +102,7 @@
|
||||
<div th:fragment="csvimport" class="input-group" th:if="${account.getRoles().contains('orga')}"
|
||||
title="Das CSV folgt dem Format id,givenname,familyname,email.">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text text-monospace">CSV:</span>
|
||||
<span class="input-group-text">CSV:</span>
|
||||
</div>
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="file" name="file">
|
||||
|
@ -7,7 +7,6 @@
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
|
||||
<!--<script src="https://kit.fontawesome.com/22c0caaa8a.js" crossorigin="anonymous"></script>-->
|
||||
|
||||
<script type="text/javascript" th:src="@{/js/script.js}"></script>
|
||||
|
||||
|
@ -7,17 +7,17 @@
|
||||
|
||||
<!--Grouptype Badges-->
|
||||
<th:block th:fragment="badges">
|
||||
<span class="badge badge-pill private"
|
||||
<span class="badge badge-pill private align-self-start"
|
||||
title="Kann nicht über die Suche gefunden werden, beitritt ist per Einladungslink möglich."
|
||||
th:if='${group.isPrivate()}'>Privat</span>
|
||||
<span class="badge badge-pill public"
|
||||
<span class="badge badge-pill public align-self-start"
|
||||
title="Kann über die Suche gefunden werden, jeder kann beitreten."
|
||||
th:if="${group.isPublic()}">Öffentlich</span>
|
||||
<span class="badge badge-pill lecture"
|
||||
<span class="badge badge-pill lecture align-self-start"
|
||||
title="Offizielle Veranstaltung"
|
||||
th:if='${group.isLecture()}'>Veranstaltung</span>
|
||||
|
||||
<span class="badge badge-pill parent"
|
||||
<span class="badge badge-pill parent align-self-start"
|
||||
th:if="${parent?.exists()}"
|
||||
th:title="${'Die Gruppe gehört zur Veranstaltung ' + parent.getTitle() + '.'}"
|
||||
th:text="${parent.getTitle()}">Parent</span>
|
||||
@ -36,7 +36,7 @@
|
||||
|
||||
<th:block th:fragment="groupcontent">
|
||||
<!--Badges-->
|
||||
<div class="content-heading">
|
||||
<div class="content-heading overflow-hidden">
|
||||
<span th:replace="~{fragments/groups :: badges}"></span>
|
||||
</div>
|
||||
|
||||
@ -48,6 +48,19 @@
|
||||
<!--<div class="body-text-in" th:if="${group.getMembers().contains(user.getId())}"></div>-->
|
||||
</th:block>
|
||||
|
||||
<th:block th:fragment="groupcontentlink">
|
||||
<div class="content-heading row overflow-hidden">
|
||||
<a class="link col" th:href="@{/gruppen2/details/{id}(id=${group.getId()})}"
|
||||
th:text="${group.getTitle()}"></a>
|
||||
|
||||
<span th:replace="~{fragments/groups :: badges}"></span>
|
||||
</div>
|
||||
|
||||
<div class="content-text-in overflow-hidden" style="text-overflow: ellipsis;">
|
||||
<span th:text="${group.getDescription()}"></span>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<!--Buttonbar zum Gruppe beitreten-->
|
||||
<th:block th:fragment="joingroup">
|
||||
<div class="content-heading">
|
||||
@ -59,15 +72,13 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="d-flex flex-row flex-wrap">
|
||||
<form method="post" th:action="@{/gruppen2/details/{id}/join(id = ${group.getId()})}"
|
||||
th:unless="${group.isFull()}">
|
||||
<button class="btn btn-success" type="submit">Gruppe beitreten.</button>
|
||||
</form>
|
||||
|
||||
<div class="col" th:unless="${group.isFull()}"></div>
|
||||
|
||||
<a class="btn btn-primary" href="/gruppen2"
|
||||
<a class="btn btn-primary ml-auto" href="/gruppen2"
|
||||
type="submit">Startseite.</a>
|
||||
</div>
|
||||
</th:block>
|
||||
|
@ -9,23 +9,26 @@
|
||||
<body>
|
||||
|
||||
<main th:fragment="bodycontent">
|
||||
<div class="container-fluid">
|
||||
<h1>Meine Gruppen</h1>
|
||||
|
||||
<h1 class="def-cursor">Meine Gruppen</h1>
|
||||
<!--Gruppenliste belegte Gruppen-->
|
||||
<div class="mx-n2 mx-sm-0" th:unless="${lectures.isEmpty()}">
|
||||
<h3>Veranstaltungen</h3>
|
||||
|
||||
<!--Gruppenliste belegte Gruppen-->
|
||||
<div class="content" th:each="group: ${groups}">
|
||||
<div class="content-heading row">
|
||||
<a class="link col" th:href="@{/gruppen2/details/{id}(id=${group.getId()})}"
|
||||
th:text="${group.getTitle()}"></a>
|
||||
<div class="content px-1 px-sm-3" th:each="group: ${lectures}"
|
||||
th:insert="fragments/groups :: groupcontentlink"></div>
|
||||
</div>
|
||||
|
||||
<span th:replace="~{fragments/groups :: badges}"></span>
|
||||
</div>
|
||||
<div class="content-text-in">
|
||||
<span th:text="${group.getDescription()}"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mx-n2 mx-sm-0" th:unless="${publics.isEmpty()}">
|
||||
<h3>Öffentliche Gruppen</h3>
|
||||
<div class="content px-1 px-sm-3" th:each="group: ${publics}"
|
||||
th:insert="fragments/groups :: groupcontentlink"></div>
|
||||
</div>
|
||||
|
||||
<div class="mx-n2 mx-sm-0" th:unless="${privates.isEmpty()}">
|
||||
<h3>Private Gruppen</h3>
|
||||
<div class="content px-1 px-sm-3" th:each="group: ${privates}"
|
||||
th:insert="fragments/groups :: groupcontentlink"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
<main th:fragment="bodycontent">
|
||||
<div class="container-fluid">
|
||||
<h1 class="def-cursor" th:text="${group.getTitle()}"></h1>
|
||||
<h1 th:text="${group.getTitle()}"></h1>
|
||||
|
||||
<div class="content" th:insert="~{fragments/groups :: groupcontent}"></div>
|
||||
|
||||
|
31
src/main/resources/templates/log.html
Normal file
31
src/main/resources/templates/log.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de" xmlns:th="http://www.thymeleaf.org" th:replace="~{mopslayout :: html(
|
||||
name='Gruppenfindung',
|
||||
title='Event-Log',
|
||||
headcontent=~{fragments/general :: headcontent('none')},
|
||||
navigation=~{fragments/general :: nav('none')},
|
||||
bodycontent=~{:: bodycontent})}">
|
||||
|
||||
<body>
|
||||
|
||||
<main th:fragment="bodycontent">
|
||||
<h1>Event-Log</h1>
|
||||
|
||||
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0" th:each="event : ${events}">
|
||||
<div class="content-heading d-flex flex-row flex-wrap">
|
||||
<span th:text="${event.type()}"></span>
|
||||
|
||||
<span class="ml-auto">Datum: </span>
|
||||
<span th:text="${event.getDate()}"></span>
|
||||
</div>
|
||||
|
||||
<div class="content-text-in px-1 px-sm-3">
|
||||
<span th:text="${'User:' + event.getExec()}"></span>
|
||||
|
||||
<span th:text="${'>>>' + event.format()}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -10,17 +10,15 @@
|
||||
|
||||
<main th:fragment="bodycontent">
|
||||
<div class="container-fluid">
|
||||
<h1 class="def-cursor" th:text="${group.getTitle()}"></h1>
|
||||
<h1 th:text="${group.getTitle()}"></h1>
|
||||
|
||||
<div class="content" th:insert="~{fragments/groups :: groupcontent}"></div>
|
||||
|
||||
<div class="content" th:unless="${group.isPrivate()}"
|
||||
th:insert="~{fragments/groups :: joingroup}"></div>
|
||||
|
||||
<div class="content row" th:if="${group.isPrivate()}">
|
||||
<span class="col"></span>
|
||||
|
||||
<a class="btn btn-primary" href="/gruppen2">Startseite.</a>
|
||||
<div class="content d-flex flex-row flex-wrap" th:if="${group.isPrivate()}">
|
||||
<a class="btn btn-primary ml-auto" href="/gruppen2">Startseite.</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
@ -8,38 +8,44 @@
|
||||
|
||||
<body>
|
||||
|
||||
<!--/*@thymesVar id="LECTURE" type="mops.gruppen2.domain.model.group.Type"*/-->
|
||||
<!--/*@thymesVar id="PUBLIC" type="mops.gruppen2.domain.model.group.Type"*/-->
|
||||
|
||||
<main th:fragment="bodycontent">
|
||||
<div class="container-fluid">
|
||||
<h1>Suchen</h1>
|
||||
|
||||
<h1>Suchen</h1>
|
||||
|
||||
<!--Suchfilter-->
|
||||
<div class="content top">
|
||||
<form method="post" th:action="@{/gruppen2/search}">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text text-monospace">Suchbegriff:</span>
|
||||
<!--Suchfilter-->
|
||||
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||
<form method="post" th:action="@{/gruppen2/search/string}">
|
||||
<div class="d-flex flex-row flex-wrap mr-n2 mt-n2">
|
||||
<div class="input-group mr-2 mt-2 flex-grow-1" style="flex-basis: 75%;">
|
||||
<div class="input-group-prepend" style="max-width: 50%;">
|
||||
<span class="input-group-text text-monospace overflow-hidden"
|
||||
style="text-overflow: ellipsis">Suchbegriff:</span>
|
||||
</div>
|
||||
<input class="form-control" name="string" type="text">
|
||||
<input class="form-control" required minlength="1" name="string" type="text">
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">Suchen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!--Ergebnisliste-->
|
||||
<div class="content" th:each="group: ${groups}">
|
||||
<div class="content-heading row">
|
||||
<span th:replace="~{fragments/groups :: badges}"></span>
|
||||
|
||||
<a class="link col" th:href="@{/gruppen2/details/{id}(id=${group.getId()})}"
|
||||
th:text="${group.getTitle()}"></a>
|
||||
<button class="btn btn-primary btn-block mr-2 mt-2 flex-grow-1" type="submit">
|
||||
Suchen
|
||||
</button>
|
||||
</div>
|
||||
<div class="content-text-in">
|
||||
<span th:text="${group.getDescription()}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="d-flex flex-row flex-wrap mt-1 mr-n2">
|
||||
<a class="btn btn-info mt-2 mr-2 flex-grow-1"
|
||||
th:href="@{/gruppen2/search/all}">Alle Anzeigen</a>
|
||||
|
||||
<a class="btn btn-info mt-2 mr-2 flex-grow-1 ml-auto"
|
||||
th:href="@{/gruppen2/search/type/{type}(type=${LECTURE})}">Vorlesungen</a>
|
||||
<a class="btn btn-info mt-2 mr-2 flex-grow-1"
|
||||
th:href="@{/gruppen2/search/type/{type}(type=${PUBLIC})}">Öffentliche Gruppen</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Ergebnisliste-->
|
||||
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0" th:each="group: ${groups}"
|
||||
th:insert="fragments/groups :: groupcontentlink"></div>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
|
154
src/test/java/mops/gruppen2/GroupBuilder.java
Normal file
154
src/test/java/mops/gruppen2/GroupBuilder.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -1,297 +0,0 @@
|
||||
package mops.gruppen2;
|
||||
|
||||
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<Event> completePublicGroups(int count, int membercount) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> completePublicGroup(membercount))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> completePrivateGroups(int count, int membercount) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> completePrivateGroup(membercount))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> completePublicGroup(int membercount) {
|
||||
List<Event> eventList = new ArrayList<>();
|
||||
UUID groupId = UUID.randomUUID();
|
||||
|
||||
eventList.add(createPublicGroupEvent(groupId));
|
||||
eventList.add(updateGroupTitleEvent(groupId));
|
||||
eventList.add(updateGroupDescriptionEvent(groupId));
|
||||
eventList.add(new SetLimitEvent(groupId, "fgsadggas", new Limit(Long.MAX_VALUE)));
|
||||
eventList.addAll(addUserEvents(membercount, groupId));
|
||||
|
||||
return eventList;
|
||||
}
|
||||
|
||||
public static List<Event> completePrivateGroup(int membercount) {
|
||||
List<Event> eventList = new ArrayList<>();
|
||||
UUID groupId = UUID.randomUUID();
|
||||
|
||||
eventList.add(createPrivateGroupEvent(groupId));
|
||||
eventList.add(updateGroupTitleEvent(groupId));
|
||||
eventList.add(updateGroupDescriptionEvent(groupId));
|
||||
eventList.add(new SetLimitEvent(groupId, "fgsadggas", new Limit(Long.MAX_VALUE)));
|
||||
eventList.addAll(addUserEvents(membercount, groupId));
|
||||
|
||||
return eventList;
|
||||
}
|
||||
|
||||
public static List<Event> completePublicGroup() {
|
||||
return completePublicGroup(100);
|
||||
}
|
||||
|
||||
public static List<Event> completePrivateGroup() {
|
||||
return completePrivateGroup(100);
|
||||
}
|
||||
|
||||
*//**
|
||||
* Generiert mehrere CreateGroupEvents, 1 <= groupId <= count.
|
||||
*
|
||||
* @param count Anzahl der verschiedenen Gruppen
|
||||
*
|
||||
* @return Eventliste
|
||||
*//*
|
||||
public static List<Event> createPublicGroupEvents(int count) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> createPublicGroupEvent())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> createPrivateGroupEvents(int count) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> createPublicGroupEvent())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> 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 List<Event> createPrivateGroupEvents(UUID groupId) {
|
||||
return (new ArrayList<>()).addAll(createGroupEvent(groupId)),
|
||||
new SetTypeEvent(groupId);
|
||||
}
|
||||
|
||||
public static Event createPrivateGroupEvent() {
|
||||
return createPrivateGroupEvent(UUID.randomUUID());
|
||||
}
|
||||
|
||||
public static Event createPublicGroupEvent(UUID groupId) {
|
||||
return createGroupEvent(groupId, Type.PUBLIC);
|
||||
}
|
||||
|
||||
public static Event createPublicGroupEvent() {
|
||||
return createPublicGroupEvent(UUID.randomUUID());
|
||||
}
|
||||
|
||||
public static Event createGroupEvent(UUID groupId) {
|
||||
return new CreateGroupEvent(groupId,
|
||||
faker.random().hex(),
|
||||
LocalDateTime.now());
|
||||
}
|
||||
|
||||
public static Event createLectureEvent() {
|
||||
return createLectureEvent(UUID.randomUUID());
|
||||
}
|
||||
|
||||
public static Event createLectureEvent(UUID groupId) {
|
||||
return new CreateGroupEvent(
|
||||
groupId,
|
||||
faker.random().hex(),
|
||||
null,
|
||||
Type.LECTURE
|
||||
);
|
||||
}
|
||||
|
||||
*//**
|
||||
* 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<Event> 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 AddMemberEvent(
|
||||
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<Event> deleteUserEvents(int count, List<Event> eventList) {
|
||||
List<Event> removeEvents = new ArrayList<>();
|
||||
List<Event> shuffle = eventList.parallelStream()
|
||||
.filter(event -> event instanceof AddMemberEvent)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Collections.shuffle(shuffle);
|
||||
|
||||
for (Event event : shuffle) {
|
||||
removeEvents.add(new KickMemberEvent(event.getGroupid(), event.getTarget()));
|
||||
|
||||
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<Event> deleteUserEvents(Group group) {
|
||||
return group.getMemberships().parallelStream()
|
||||
.map(user -> deleteUserEvent(group.getGroupid(), user.getUserId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static Event deleteUserEvent(UUID groupId, String userId) {
|
||||
return new KickMemberEvent(
|
||||
groupId,
|
||||
userId
|
||||
);
|
||||
}
|
||||
|
||||
public static Event updateGroupDescriptionEvent(UUID groupId) {
|
||||
return updateGroupDescriptionEvent(groupId, quote());
|
||||
}
|
||||
|
||||
public static Event updateGroupDescriptionEvent(UUID groupId, String description) {
|
||||
return new SetDescriptionEvent(
|
||||
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 SetTitleEvent(
|
||||
groupId,
|
||||
faker.random().hex(),
|
||||
title
|
||||
);
|
||||
}
|
||||
|
||||
public static Event updateUserLimitMaxEvent(UUID groupId) {
|
||||
return new SetLimitEvent(groupId, firstname(), Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
public static Event updateRoleEvent(UUID groupId, String userId, Role role) {
|
||||
return new UpdateRoleEvent(
|
||||
groupId,
|
||||
userId,
|
||||
role
|
||||
);
|
||||
}
|
||||
|
||||
public static Event deleteGroupEvent(UUID groupId) {
|
||||
return new DestroyGroupEvent(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("['\";,]", "");
|
||||
}*/
|
||||
}
|
24
src/test/java/mops/gruppen2/TestHelper.java
Normal file
24
src/test/java/mops/gruppen2/TestHelper.java
Normal file
@ -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<Event> events) {
|
||||
for (int i = 1; i <= events.size(); i++) {
|
||||
events.get(i - 1).init(i);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package mops.gruppen2.domain.event;
|
||||
|
||||
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 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 apply() {
|
||||
Group group = Group.EMPTY();
|
||||
Event add = new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now());
|
||||
add.init(1);
|
||||
|
||||
assertThat(group.exists()).isFalse();
|
||||
add.apply(group);
|
||||
assertThat(group.exists()).isTrue();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
76
src/test/java/mops/gruppen2/domain/event/EventTest.java
Normal file
76
src/test/java/mops/gruppen2/domain/event/EventTest.java
Normal file
@ -0,0 +1,76 @@
|
||||
package mops.gruppen2.domain.event;
|
||||
|
||||
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.TestHelper.uuid;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class EventTest {
|
||||
|
||||
@Test
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
267
src/test/java/mops/gruppen2/domain/service/GroupServiceTest.java
Normal file
267
src/test/java/mops/gruppen2/domain/service/GroupServiceTest.java
Normal file
@ -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());
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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<Event> events = Arrays.asList(
|
||||
new CreateGroupEvent(uuid(1), "TEST", LocalDateTime.now()));
|
||||
|
||||
initEvents(events);
|
||||
|
||||
assertThat(project(events)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void project_nocache_multipleCreate() {
|
||||
List<Event> 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<Event> 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<Group> 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<Event> 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<Event> 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<Event> 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<Event> 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<Event> events = new ArrayList<>();
|
||||
events.addAll(eventsA);
|
||||
events.addAll(eventsB);
|
||||
events.addAll(eventsC);
|
||||
events.addAll(eventsD);
|
||||
|
||||
List<Group> 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<UUID, Group> groups = new HashMap<>();
|
||||
|
||||
project(groups, Collections.emptyList(), mock(GroupCache.class));
|
||||
|
||||
assertThat(groups).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void project_cache_oneCreate() {
|
||||
Map<UUID, Group> groups = new HashMap<>();
|
||||
List<Event> 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<UUID, Group> groups = new HashMap<>();
|
||||
List<Event> 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<UUID, Group> groups = new HashMap<>();
|
||||
List<Event> 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<Event> 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<Event> 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<Event> 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<Event> 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);
|
||||
}
|
||||
}
|
312
src/test/java/mops/gruppen2/infrastructure/GroupCacheTest.java
Normal file
312
src/test/java/mops/gruppen2/infrastructure/GroupCacheTest.java
Normal file
@ -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() {}
|
||||
}
|
@ -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() {
|
||||
}
|
||||
}
|
@ -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() {
|
||||
}
|
||||
}
|
@ -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() {
|
||||
}
|
||||
}
|
@ -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() {
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user