@ -5,6 +5,6 @@ CREATE TABLE event
|
|||||||
group_version INT NOT NULL,
|
group_version INT NOT NULL,
|
||||||
exec_id VARCHAR(32) NOT NULL,
|
exec_id VARCHAR(32) NOT NULL,
|
||||||
target_id VARCHAR(32),
|
target_id VARCHAR(32),
|
||||||
event_type VARCHAR(16) NOT NULL,
|
event_date DATETIME NOT NULL,
|
||||||
event_payload JSON NOT NULL
|
event_payload JSON NOT NULL
|
||||||
);
|
);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
DROP TABLE IF EXISTS event;
|
||||||
|
|
||||||
CREATE TABLE event
|
CREATE TABLE event
|
||||||
(
|
(
|
||||||
event_id INT PRIMARY KEY AUTO_INCREMENT,
|
event_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
@ -5,6 +7,6 @@ CREATE TABLE event
|
|||||||
group_version INT NOT NULL,
|
group_version INT NOT NULL,
|
||||||
exec_id VARCHAR(32) NOT NULL,
|
exec_id VARCHAR(32) NOT NULL,
|
||||||
target_id VARCHAR(32),
|
target_id VARCHAR(32),
|
||||||
event_type VARCHAR(16) NOT NULL,
|
event_date DATETIME NOT NULL,
|
||||||
event_payload TEXT NOT NULL
|
event_payload TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
@ -22,10 +22,10 @@ public class KeycloakConfig {
|
|||||||
@Value("${keycloak.resource}")
|
@Value("${keycloak.resource}")
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
@Value("f73354fd-614e-4e24-b801-a8d0f4abf531")
|
@Value("2e2e5770-c454-4d31-be99-9d8c34c93089")
|
||||||
private String clientSecret;
|
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;
|
private String tokenUri;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -6,7 +6,7 @@ import lombok.Value;
|
|||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import mops.gruppen2.domain.exception.GroupFullException;
|
import mops.gruppen2.domain.exception.GroupFullException;
|
||||||
import mops.gruppen2.domain.exception.IdMismatchException;
|
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.Group;
|
||||||
import mops.gruppen2.domain.model.group.User;
|
import mops.gruppen2.domain.model.group.User;
|
||||||
import mops.gruppen2.infrastructure.GroupCache;
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
@ -39,12 +39,17 @@ public class AddMemberEvent extends Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyEvent(Group group) throws UserAlreadyExistsException, GroupFullException {
|
protected void applyEvent(Group group) throws UserExistsException, GroupFullException {
|
||||||
group.addMember(target, user);
|
group.addMember(target, user);
|
||||||
|
|
||||||
log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
|
log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Benutzer hinzugefügt: " + target + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.ADDMEMBER.toString();
|
return EventType.ADDMEMBER.toString();
|
||||||
|
@ -39,6 +39,11 @@ public class CreateGroupEvent extends Event {
|
|||||||
log.trace("\t\t\t\t\tNeue Gruppe: {}", group.toString());
|
log.trace("\t\t\t\t\tNeue Gruppe: {}", group.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Gruppe erstellt.";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.CREATEGROUP.toString();
|
return EventType.CREATEGROUP.toString();
|
||||||
|
@ -20,7 +20,7 @@ public class DestroyGroupEvent extends Event {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateCache(GroupCache cache, Group group) {
|
protected void updateCache(GroupCache cache, Group group) {
|
||||||
cache.groupsRemove(group);
|
cache.groupsRemove(groupid, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -30,6 +30,11 @@ public class DestroyGroupEvent extends Event {
|
|||||||
log.trace("\t\t\t\t\tGelöschte Gruppe: {}", group.toString());
|
log.trace("\t\t\t\t\tGelöschte Gruppe: {}", group.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Gruppe gelöscht.";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.DESTROYGROUP.toString();
|
return EventType.DESTROYGROUP.toString();
|
||||||
|
@ -13,21 +13,26 @@ import mops.gruppen2.domain.exception.IdMismatchException;
|
|||||||
import mops.gruppen2.domain.model.group.Group;
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
import mops.gruppen2.infrastructure.GroupCache;
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.util.UUID;
|
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
|
@Log4j2
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "class")
|
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "class")
|
||||||
@JsonSubTypes({@JsonSubTypes.Type(value = AddMemberEvent.class, name = "ADDMEMBER"),
|
@JsonSubTypes({@Type(value = AddMemberEvent.class, name = "ADDMEMBER"),
|
||||||
@JsonSubTypes.Type(value = CreateGroupEvent.class, name = "CREATEGROUP"),
|
@Type(value = CreateGroupEvent.class, name = "CREATEGROUP"),
|
||||||
@JsonSubTypes.Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"),
|
@Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"),
|
||||||
@JsonSubTypes.Type(value = KickMemberEvent.class, name = "KICKMEMBER"),
|
@Type(value = KickMemberEvent.class, name = "KICKMEMBER"),
|
||||||
@JsonSubTypes.Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"),
|
@Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"),
|
||||||
@JsonSubTypes.Type(value = SetInviteLinkEvent.class, name = "SETLINK"),
|
@Type(value = SetInviteLinkEvent.class, name = "SETLINK"),
|
||||||
@JsonSubTypes.Type(value = SetLimitEvent.class, name = "SETLIMIT"),
|
@Type(value = SetLimitEvent.class, name = "SETLIMIT"),
|
||||||
@JsonSubTypes.Type(value = SetParentEvent.class, name = "SETPARENT"),
|
@Type(value = SetParentEvent.class, name = "SETPARENT"),
|
||||||
@JsonSubTypes.Type(value = SetTitleEvent.class, name = "SETTITLE"),
|
@Type(value = SetTitleEvent.class, name = "SETTITLE"),
|
||||||
@JsonSubTypes.Type(value = SetTypeEvent.class, name = "SETTYPE"),
|
@Type(value = SetTypeEvent.class, name = "SETTYPE"),
|
||||||
@JsonSubTypes.Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")})
|
@Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")})
|
||||||
@Getter
|
@Getter
|
||||||
@NoArgsConstructor // Lombok needs a default constructor in the base class
|
@NoArgsConstructor // Lombok needs a default constructor in the base class
|
||||||
public abstract class Event {
|
public abstract class Event {
|
||||||
@ -44,6 +49,10 @@ public abstract class Event {
|
|||||||
@JsonProperty("target")
|
@JsonProperty("target")
|
||||||
protected String 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) {
|
public Event(UUID groupid, String exec, String target) {
|
||||||
this.groupid = groupid;
|
this.groupid = groupid;
|
||||||
this.exec = exec;
|
this.exec = exec;
|
||||||
@ -54,6 +63,7 @@ public abstract class Event {
|
|||||||
if (this.version != 0) {
|
if (this.version != 0) {
|
||||||
throw new BadArgumentException("Event wurde schon initialisiert. (" + type() + ")");
|
throw new BadArgumentException("Event wurde schon initialisiert. (" + type() + ")");
|
||||||
}
|
}
|
||||||
|
date = LocalDateTime.now();
|
||||||
|
|
||||||
log.trace("Event wurde initialisiert. (" + type() + "," + version + ")");
|
log.trace("Event wurde initialisiert. (" + type() + "," + version + ")");
|
||||||
|
|
||||||
@ -68,9 +78,22 @@ public abstract class Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkGroupIdMatch(group.getId());
|
checkGroupIdMatch(group.getId());
|
||||||
updateCache(cache, group);
|
|
||||||
group.updateVersion(version);
|
group.updateVersion(version);
|
||||||
applyEvent(group);
|
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 {
|
private void checkGroupIdMatch(UUID groupid) throws IdMismatchException {
|
||||||
@ -88,6 +111,9 @@ public abstract class Event {
|
|||||||
|
|
||||||
protected abstract void applyEvent(Group group) throws EventException;
|
protected abstract void applyEvent(Group group) throws EventException;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public abstract String format();
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public abstract String type();
|
public abstract String type();
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,11 @@ public class KickMemberEvent extends Event {
|
|||||||
log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
|
log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Mitglied entfernt: " + target + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.KICKMEMBER.toString();
|
return EventType.KICKMEMBER.toString();
|
||||||
|
@ -38,6 +38,11 @@ public class SetDescriptionEvent extends Event {
|
|||||||
log.trace("\t\t\t\t\tNeue Beschreibung: {}", group.getDescription());
|
log.trace("\t\t\t\t\tNeue Beschreibung: {}", group.getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Beschreibung gesetzt: " + description + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.SETDESCRIPTION.toString();
|
return EventType.SETDESCRIPTION.toString();
|
||||||
|
@ -38,6 +38,11 @@ public class SetInviteLinkEvent extends Event {
|
|||||||
log.trace("\t\t\t\t\tNeuer Link: {}", group.getLink());
|
log.trace("\t\t\t\t\tNeuer Link: {}", group.getLink());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Einladungslink gesetzt: " + link + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.SETLINK.toString();
|
return EventType.SETLINK.toString();
|
||||||
|
@ -36,6 +36,11 @@ public class SetLimitEvent extends Event {
|
|||||||
log.trace("\t\t\t\t\tNeues UserLimit: {}", group.getLimit());
|
log.trace("\t\t\t\t\tNeues UserLimit: {}", group.getLimit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Benutzerlimit gesetzt: " + limit + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.SETLIMIT.toString();
|
return EventType.SETLIMIT.toString();
|
||||||
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import mops.gruppen2.domain.exception.BadArgumentException;
|
||||||
import mops.gruppen2.domain.exception.NoAccessException;
|
import mops.gruppen2.domain.exception.NoAccessException;
|
||||||
import mops.gruppen2.domain.model.group.Group;
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||||
@ -29,12 +30,17 @@ public class SetParentEvent extends Event {
|
|||||||
protected void updateCache(GroupCache cache, Group group) {}
|
protected void updateCache(GroupCache cache, Group group) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyEvent(Group group) throws NoAccessException {
|
protected void applyEvent(Group group) throws NoAccessException, BadArgumentException {
|
||||||
group.setParent(exec, parent);
|
group.setParent(exec, parent);
|
||||||
|
|
||||||
log.trace("\t\t\t\t\tNeues Parent: {}", group.getParent());
|
log.trace("\t\t\t\t\tNeues Parent: {}", group.getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Veranstaltungszugehörigkeit gesetzt: " + parent.getValue() + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.SETPARENT.toString();
|
return EventType.SETPARENT.toString();
|
||||||
|
@ -38,6 +38,11 @@ public class SetTitleEvent extends Event {
|
|||||||
log.trace("\t\t\t\t\tNeuer Titel: {}", group.getTitle());
|
log.trace("\t\t\t\t\tNeuer Titel: {}", group.getTitle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Titel gesetzt: " + title + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.SETTITLE.toString();
|
return EventType.SETTITLE.toString();
|
||||||
|
@ -3,6 +3,7 @@ package mops.gruppen2.domain.event;
|
|||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
import lombok.experimental.NonFinal;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import mops.gruppen2.domain.exception.EventException;
|
import mops.gruppen2.domain.exception.EventException;
|
||||||
import mops.gruppen2.domain.model.group.Group;
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
@ -20,6 +21,12 @@ public class SetTypeEvent extends Event {
|
|||||||
@JsonProperty("type")
|
@JsonProperty("type")
|
||||||
Type 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) {
|
public SetTypeEvent(UUID groupId, String exec, @Valid Type type) {
|
||||||
super(groupId, exec, null);
|
super(groupId, exec, null);
|
||||||
|
|
||||||
@ -28,15 +35,21 @@ public class SetTypeEvent extends Event {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateCache(GroupCache cache, Group group) {
|
protected void updateCache(GroupCache cache, Group group) {
|
||||||
cache.typesRemove(group);
|
cache.typesRemove(oldType, group);
|
||||||
cache.typesPut(type, group);
|
cache.typesPut(type, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void applyEvent(Group group) throws EventException {
|
protected void applyEvent(Group group) throws EventException {
|
||||||
|
oldType = group.getType();
|
||||||
group.setType(exec, type);
|
group.setType(exec, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Gruppentype gesetzt: " + type + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.SETTYPE.toString();
|
return EventType.SETTYPE.toString();
|
||||||
|
@ -38,6 +38,11 @@ public class UpdateRoleEvent extends Event {
|
|||||||
log.trace("\t\t\t\t\tNeue Admin: {}", group.getAdmins());
|
log.trace("\t\t\t\t\tNeue Admin: {}", group.getAdmins());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format() {
|
||||||
|
return "Mitgliedsrolle gesetzt: " + target + ": " + role + ".";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return EventType.UPDATEROLE.toString();
|
return EventType.UPDATEROLE.toString();
|
||||||
|
@ -2,11 +2,11 @@ package mops.gruppen2.domain.exception;
|
|||||||
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
public class UserAlreadyExistsException extends EventException {
|
public class UserExistsException extends EventException {
|
||||||
|
|
||||||
private static final long serialVersionUID = -8150634358760194625L;
|
private static final long serialVersionUID = -8150634358760194625L;
|
||||||
|
|
||||||
public UserAlreadyExistsException(String info) {
|
public UserExistsException(String info) {
|
||||||
super(HttpStatus.INTERNAL_SERVER_ERROR, "User existiert bereits.", 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.IdMismatchException;
|
||||||
import mops.gruppen2.domain.exception.LastAdminException;
|
import mops.gruppen2.domain.exception.LastAdminException;
|
||||||
import mops.gruppen2.domain.exception.NoAccessException;
|
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.exception.UserNotFoundException;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Body;
|
import mops.gruppen2.domain.model.group.wrapper.Body;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Description;
|
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.Parent;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Title;
|
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||||
import mops.gruppen2.domain.service.helper.CommonHelper;
|
import mops.gruppen2.domain.service.helper.CommonHelper;
|
||||||
|
import mops.gruppen2.domain.service.helper.SortHelper;
|
||||||
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
@ -56,19 +57,21 @@ public class Group {
|
|||||||
|
|
||||||
private GroupMeta meta = GroupMeta.EMPTY();
|
private GroupMeta meta = GroupMeta.EMPTY();
|
||||||
|
|
||||||
private GroupOptions options = GroupOptions.DEFAULT();
|
//TODO: UI set + use for options
|
||||||
|
private final GroupOptions options = GroupOptions.DEFAULT();
|
||||||
|
|
||||||
// Inhalt
|
// Inhalt
|
||||||
private Title title = Title.EMPTY();
|
private Title title = Title.EMPTY();
|
||||||
|
|
||||||
private Description description = Description.EMPTY();
|
private Description description = Description.EMPTY();
|
||||||
|
|
||||||
|
//TODO: Asciidoc description
|
||||||
private Body body;
|
private Body body;
|
||||||
|
|
||||||
// Integrationen
|
// Integrationen
|
||||||
|
|
||||||
// Teilnehmer
|
// Teilnehmer
|
||||||
private Map<String, Membership> memberships = new HashMap<>();
|
private final Map<String, Membership> memberships = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
// ####################################### Members ###########################################
|
// ####################################### Members ###########################################
|
||||||
@ -98,7 +101,7 @@ public class Group {
|
|||||||
return memberships.get(userid).getRole();
|
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.throwIfMember(this, target);
|
||||||
ValidationHelper.throwIfGroupFull(this);
|
ValidationHelper.throwIfGroupFull(this);
|
||||||
|
|
||||||
@ -215,6 +218,26 @@ public class Group {
|
|||||||
return !parent.isEmpty();
|
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 ##########################################
|
// ######################################## Setters ##########################################
|
||||||
|
|
||||||
@ -255,14 +278,20 @@ public class Group {
|
|||||||
this.limit = limit;
|
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);
|
ValidationHelper.throwIfNoAdmin(this, exec);
|
||||||
|
if (parent.getValue().equals(groupid)) {
|
||||||
|
throw new BadArgumentException("Die Gruppe kann nicht zu sich selbst gehören!");
|
||||||
|
}
|
||||||
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLink(String exec, @Valid Link link) throws NoAccessException {
|
public void setLink(String exec, @Valid Link link) throws NoAccessException {
|
||||||
ValidationHelper.throwIfNoAdmin(this, exec);
|
ValidationHelper.throwIfNoAdmin(this, exec);
|
||||||
|
if (link.getValue().equals(groupid.toString())) {
|
||||||
|
throw new BadArgumentException("Link kann nicht der GruppenID entsprechen.");
|
||||||
|
}
|
||||||
|
|
||||||
this.link = link;
|
this.link = link;
|
||||||
}
|
}
|
||||||
@ -289,7 +318,9 @@ public class Group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
groupid = null;
|
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;
|
parent = null;
|
||||||
limit = null;
|
limit = null;
|
||||||
link = null;
|
link = null;
|
||||||
@ -298,11 +329,11 @@ public class Group {
|
|||||||
title = null;
|
title = null;
|
||||||
description = null;
|
description = null;
|
||||||
body = null;
|
body = null;
|
||||||
memberships = null;
|
memberships = null;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
public String format() {
|
public String format() {
|
||||||
return title + " " + description;
|
return title + " - " + description;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -319,4 +350,8 @@ public class Group {
|
|||||||
public static Group EMPTY() {
|
public static Group EMPTY() {
|
||||||
return new Group();
|
return new Group();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getVersion() {
|
||||||
|
return meta.getVersion();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ class GroupMeta {
|
|||||||
if (this.version >= version) {
|
if (this.version >= version) {
|
||||||
throw new IdMismatchException("Die Gruppe ist bereits auf einem neueren Stand.");
|
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);
|
return new GroupMeta(version, creator, creationDate);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ class GroupOptions {
|
|||||||
boolean hasMaterialIntegration;
|
boolean hasMaterialIntegration;
|
||||||
boolean hasTermineIntegration;
|
boolean hasTermineIntegration;
|
||||||
boolean hasPortfolioIntegration;
|
boolean hasPortfolioIntegration;
|
||||||
|
boolean hasForumsIntegration;
|
||||||
|
boolean hasModulesIntegration;
|
||||||
|
|
||||||
static GroupOptions DEFAULT() {
|
static GroupOptions DEFAULT() {
|
||||||
return new GroupOptions(true,
|
return new GroupOptions(true,
|
||||||
@ -31,6 +33,8 @@ class GroupOptions {
|
|||||||
null,
|
null,
|
||||||
true,
|
true,
|
||||||
true,
|
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
|
@Log4j2
|
||||||
@Value
|
@Value
|
||||||
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class User {
|
public class User {
|
||||||
|
|
||||||
|
@ -4,18 +4,24 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
import lombok.Value;
|
import lombok.Value;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Value
|
@Value
|
||||||
public class Link {
|
public class Link {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Size(min = 36, max = 36)
|
|
||||||
@JsonProperty("value")
|
@JsonProperty("value")
|
||||||
String value;
|
UUID value;
|
||||||
|
|
||||||
|
public Link(String value) {
|
||||||
|
this.value = UUID.fromString(value);
|
||||||
|
}
|
||||||
|
|
||||||
public static Link RANDOM() {
|
public static Link RANDOM() {
|
||||||
return new Link(UUID.randomUUID().toString());
|
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 lombok.extern.log4j.Log4j2;
|
||||||
import mops.gruppen2.domain.event.Event;
|
import mops.gruppen2.domain.event.Event;
|
||||||
import mops.gruppen2.domain.exception.BadPayloadException;
|
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.EventRepository;
|
||||||
import mops.gruppen2.persistance.dto.EventDTO;
|
import mops.gruppen2.persistance.dto.EventDTO;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@ -52,13 +56,13 @@ public class EventStoreService {
|
|||||||
*/
|
*/
|
||||||
private static EventDTO getDTOFromEvent(Event event) {
|
private static EventDTO getDTOFromEvent(Event event) {
|
||||||
try {
|
try {
|
||||||
String payload = JsonHelper.serializeEvent(event);
|
String payload = FileHelper.serializeEventJson(event);
|
||||||
return new EventDTO(null,
|
return new EventDTO(null,
|
||||||
event.getGroupid().toString(),
|
event.getGroupid().toString(),
|
||||||
event.getVersion(),
|
event.getVersion(),
|
||||||
event.getExec(),
|
event.getExec(),
|
||||||
event.getTarget(),
|
event.getTarget(),
|
||||||
event.type(),
|
Timestamp.valueOf(event.getDate()),
|
||||||
payload);
|
payload);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
log.error("Event ({}) konnte nicht serialisiert werden!", event, e);
|
log.error("Event ({}) konnte nicht serialisiert werden!", event, e);
|
||||||
@ -81,7 +85,7 @@ public class EventStoreService {
|
|||||||
|
|
||||||
private static Event getEventFromDTO(EventDTO dto) {
|
private static Event getEventFromDTO(EventDTO dto) {
|
||||||
try {
|
try {
|
||||||
return JsonHelper.deserializeEvent(dto.getEvent_payload());
|
return FileHelper.deserializeEventJson(dto.getEvent_payload());
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
log.error("Payload {} konnte nicht deserialisiert werden!", dto.getEvent_payload(), e);
|
log.error("Payload {} konnte nicht deserialisiert werden!", dto.getEvent_payload(), e);
|
||||||
throw new BadPayloadException(EventStoreService.class.toString());
|
throw new BadPayloadException(EventStoreService.class.toString());
|
||||||
@ -95,4 +99,32 @@ public class EventStoreService {
|
|||||||
public List<Event> findAllEvents() {
|
public List<Event> findAllEvents() {
|
||||||
return getEventsFromDTOs(eventStore.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.Link;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Title;
|
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||||
|
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||||
import mops.gruppen2.infrastructure.GroupCache;
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Behandelt Aufgaben, welche sich auf eine Gruppe beziehen.
|
* Behandelt Aufgaben, welche sich auf eine Gruppe beziehen.
|
||||||
@ -94,9 +97,11 @@ public class GroupService {
|
|||||||
* @param exec Ausführender User
|
* @param exec Ausführender User
|
||||||
*/
|
*/
|
||||||
public void addUsersToGroup(Group group, String exec, List<User> newUsers) {
|
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
|
* @throws EventException Falls der User nicht gefunden wird
|
||||||
*/
|
*/
|
||||||
public void toggleMemberRole(Group group, String exec, String target) {
|
public void toggleMemberRole(Group group, String exec, String target) {
|
||||||
|
ValidationHelper.throwIfNoMember(group, target);
|
||||||
|
|
||||||
updateRole(group, exec, target, group.getRole(target).toggle());
|
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.
|
* Prüft, ob der Nutzer Admin ist und ob der Titel valide ist.
|
||||||
* Bei keiner Änderung wird nichts erzeugt.
|
* 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())) {
|
if (group.getTitle().equals(title.getValue())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -205,7 +212,7 @@ public class GroupService {
|
|||||||
* Prüft, ob der Nutzer Admin ist und ob die Beschreibung valide ist.
|
* Prüft, ob der Nutzer Admin ist und ob die Beschreibung valide ist.
|
||||||
* Bei keiner Änderung wird nichts erzeugt.
|
* 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())) {
|
if (group.getDescription().equals(description.getValue())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -231,7 +238,7 @@ public class GroupService {
|
|||||||
* Prüft, ob der Nutzer Admin ist und ob das Limit valide ist.
|
* Prüft, ob der Nutzer Admin ist und ob das Limit valide ist.
|
||||||
* Bei keiner Änderung wird nichts erzeugt.
|
* 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()) {
|
if (userLimit.getValue() == group.getLimit()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -247,7 +254,8 @@ public class GroupService {
|
|||||||
applyAndSave(group, new SetParentEvent(group.getId(), exec, parent));
|
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())) {
|
if (group.getLink().equals(link.getValue())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,12 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import mops.gruppen2.domain.exception.EventException;
|
import mops.gruppen2.domain.exception.EventException;
|
||||||
import mops.gruppen2.domain.model.group.Group;
|
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 mops.gruppen2.infrastructure.GroupCache;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -30,25 +31,35 @@ public class SearchService {
|
|||||||
*
|
*
|
||||||
* @throws EventException Projektionsfehler
|
* @throws EventException Projektionsfehler
|
||||||
*/
|
*/
|
||||||
//TODO: search in lectures
|
public List<Group> searchString(String search, String principal) {
|
||||||
public List<Group> search(String search, String principal) {
|
|
||||||
List<Group> groups = new ArrayList<>();
|
List<Group> groups = new ArrayList<>();
|
||||||
groups.addAll(groupCache.publics());
|
groups.addAll(groupCache.publics());
|
||||||
groups.addAll(groupCache.lectures());
|
groups.addAll(groupCache.lectures());
|
||||||
groups = removeUserGroups(groups, principal);
|
groups = removeUserGroups(groups, principal);
|
||||||
SortHelper.sortByGroupType(groups);
|
|
||||||
|
|
||||||
if (search.isEmpty()) {
|
if (search.isEmpty()) {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Es wurde gesucht nach: {}", search);
|
log.debug("Es wurde gesucht nach: {}", search);
|
||||||
|
|
||||||
return groups.stream()
|
return groups.stream()
|
||||||
.filter(group -> group.format().toLowerCase().contains(search.toLowerCase()))
|
.filter(group -> group.format().toLowerCase().contains(search.toLowerCase()))
|
||||||
.collect(Collectors.toList());
|
.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) {
|
private static List<Group> removeUserGroups(List<Group> groups, String principal) {
|
||||||
return groups.stream()
|
return groups.stream()
|
||||||
.filter(group -> !group.isMember(principal))
|
.filter(group -> !group.isMember(principal))
|
||||||
|
@ -3,13 +3,24 @@ package mops.gruppen2.domain.service.helper;
|
|||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
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
|
@Log4j2
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public final class APIHelper {
|
public final class APIHelper {
|
||||||
|
|
||||||
/*public static GroupRequestWrapper wrap(long status, List<Group> groupList) {
|
public static GroupRequestWrapper wrap(long status, List<Group> groupList) {
|
||||||
return new GroupRequestWrapper(status, 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.NoArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
@ -13,4 +15,10 @@ public final class CommonHelper {
|
|||||||
public static boolean uuidIsEmpty(UUID uuid) {
|
public static boolean uuidIsEmpty(UUID uuid) {
|
||||||
return "00000000-0000-0000-0000-000000000000".equals(uuid.toString());
|
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.domain.model.group.Group;
|
||||||
import mops.gruppen2.infrastructure.GroupCache;
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -19,6 +22,21 @@ import java.util.UUID;
|
|||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public final class ProjectionHelper {
|
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) {
|
public static void project(Map<UUID, Group> groups, List<Event> events, GroupCache cache) {
|
||||||
if (events.isEmpty()) {
|
if (events.isEmpty()) {
|
||||||
return;
|
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.GroupFullException;
|
||||||
import mops.gruppen2.domain.exception.LastAdminException;
|
import mops.gruppen2.domain.exception.LastAdminException;
|
||||||
import mops.gruppen2.domain.exception.NoAccessException;
|
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.exception.UserNotFoundException;
|
||||||
import mops.gruppen2.domain.model.group.Group;
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
import mops.gruppen2.domain.model.group.Type;
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
@ -39,10 +39,10 @@ public final class ValidationHelper {
|
|||||||
// ######################################## THROW ############################################
|
// ######################################## 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)) {
|
if (group.isMember(userid)) {
|
||||||
log.error("Benutzer {} ist schon in Gruppe {}", userid, group);
|
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.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import mops.gruppen2.domain.exception.GroupNotFoundException;
|
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.Group;
|
||||||
import mops.gruppen2.domain.model.group.Type;
|
import mops.gruppen2.domain.model.group.Type;
|
||||||
import mops.gruppen2.domain.service.EventStoreService;
|
import mops.gruppen2.domain.service.EventStoreService;
|
||||||
@ -17,7 +19,15 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
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
|
@Log4j2
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Component
|
@Component
|
||||||
@ -28,7 +38,7 @@ public class GroupCache {
|
|||||||
|
|
||||||
private final Map<UUID, Group> groups = new HashMap<>();
|
private final Map<UUID, Group> groups = new HashMap<>();
|
||||||
private final Map<String, Group> links = 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);
|
private final Map<Type, List<Group>> types = new EnumMap<>(Type.class);
|
||||||
|
|
||||||
|
|
||||||
@ -59,6 +69,14 @@ public class GroupCache {
|
|||||||
return links.get(link);
|
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) {
|
public List<Group> userGroups(String userid) {
|
||||||
if (!users.containsKey(userid)) {
|
if (!users.containsKey(userid)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@ -67,6 +85,24 @@ public class GroupCache {
|
|||||||
return Collections.unmodifiableList(users.get(userid));
|
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() {
|
public List<Group> publics() {
|
||||||
if (!types.containsKey(Type.PUBLIC)) {
|
if (!types.containsKey(Type.PUBLIC)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@ -96,6 +132,9 @@ public class GroupCache {
|
|||||||
|
|
||||||
|
|
||||||
public void usersPut(String userid, Group group) {
|
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)) {
|
if (!users.containsKey(userid)) {
|
||||||
users.put(userid, new ArrayList<>());
|
users.put(userid, new ArrayList<>());
|
||||||
log.debug("Ein User wurde dem Cache hinzugefügt.");
|
log.debug("Ein User wurde dem Cache hinzugefügt.");
|
||||||
@ -113,18 +152,37 @@ public class GroupCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void groupsPut(UUID groupid, Group group) {
|
public void groupsPut(UUID groupid, Group group) {
|
||||||
|
if (group.getId() != groupid) {
|
||||||
|
throw new IdMismatchException("ID passt nicht zu Gruppe, Gruppe nicht gecached.");
|
||||||
|
}
|
||||||
|
|
||||||
groups.put(groupid, group);
|
groups.put(groupid, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void groupsRemove(Group group) {
|
public void groupsRemove(UUID groupid, Group group) {
|
||||||
groups.remove(group.getId());
|
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) {
|
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);
|
links.put(link, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void linksRemove(String link) {
|
public void linksRemove(String link) {
|
||||||
|
if (!links.containsKey(link)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
links.remove(link);
|
links.remove(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,15 +191,18 @@ public class GroupCache {
|
|||||||
types.put(type, new ArrayList<>());
|
types.put(type, new ArrayList<>());
|
||||||
log.debug("Ein Typ wurde dem Cache hinzugefügt.");
|
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);
|
types.get(type).add(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void typesRemove(Group group) {
|
public void typesRemove(Type type, Group group) {
|
||||||
if (!types.containsKey(group.getType())) {
|
if (!types.containsKey(type)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
types.get(group.getType()).remove(group);
|
types.get(type).remove(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package mops.gruppen2.infrastructure.api;
|
package mops.gruppen2.infrastructure.api;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kombiniert den Status und die Gruppenliste zur ausgabe über die API.
|
* Kombiniert den Status und die Gruppenliste zur ausgabe über die API.
|
||||||
*/
|
*/
|
||||||
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class GroupRequestWrapper {
|
public class GroupRequestWrapper {
|
||||||
|
|
||||||
|
@ -1,4 +1,31 @@
|
|||||||
package mops.gruppen2.infrastructure.api;
|
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 {
|
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;
|
package mops.gruppen2.infrastructure.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||||
|
import mops.gruppen2.domain.model.group.Group;
|
||||||
import mops.gruppen2.domain.service.EventStoreService;
|
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Api zum Datenabgleich.
|
* Api zum Datenabgleich.
|
||||||
*/
|
*/
|
||||||
@ -18,8 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RequestMapping("/gruppen2/api")
|
@RequestMapping("/gruppen2/api")
|
||||||
public class APIController {
|
public class APIController {
|
||||||
|
|
||||||
//TODO: redo api
|
private final GroupCache cache;
|
||||||
|
|
||||||
private final EventStoreService eventStoreService;
|
private final EventStoreService eventStoreService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,38 +41,43 @@ public class APIController {
|
|||||||
*
|
*
|
||||||
* @param eventId Die Event-ID, welche der Anfragesteller beim letzten Aufruf erhalten hat
|
* @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")
|
@Secured("ROLE_api_user")
|
||||||
@ApiOperation("Gibt veränderte Gruppen zurück")
|
@ApiOperation("Gibt veränderte Gruppen zurück")
|
||||||
public GroupRequestWrapper getApiUpdate(@ApiParam("Letzte gespeicherte EventId des Anfragestellers")
|
public GroupRequestWrapper getApiUpdate(@ApiParam("Letzte gespeicherte EventId des Anfragestellers")
|
||||||
@PathVariable("id") long eventId) {
|
@PathVariable("id") long eventId) {
|
||||||
|
|
||||||
return APIHelper.wrap(eventStoreService.findMaxEventId(),
|
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.
|
* Gibt die Gruppen-IDs von Gruppen, in welchen der übergebene Nutzer teilnimmt, zurück.
|
||||||
*/
|
*/
|
||||||
/*@GetMapping("/usergroups/{id}")
|
@GetMapping("/usergroups/{id}")
|
||||||
@Secured("ROLE_api_user")
|
@Secured("ROLE_api_user")
|
||||||
@ApiOperation("Gibt Gruppen zurück, in welchen ein Nutzer teilnimmt")
|
@ApiOperation("Gibt Gruppen zurück, in welchen ein Nutzer teilnimmt")
|
||||||
public List<String> getApiUserGroups(@ApiParam("Nutzer-Id")
|
public List<String> getApiUserGroups(@ApiParam("Nutzer-Id")
|
||||||
@PathVariable("id") String userId) {
|
@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.
|
* Konstruiert eine einzelne, vollständige Gruppe.
|
||||||
*/
|
*/
|
||||||
/*@GetMapping("/group/{id}")
|
@GetMapping("/group/{id}")
|
||||||
@Secured("ROLE_api_user")
|
@Secured("ROLE_api_user")
|
||||||
@ApiOperation("Gibt die Gruppe mit der als Parameter mitgegebenden groupId zurück")
|
@ApiOperation("Gibt die Gruppe mit der als Parameter mitgegebenden groupId zurück")
|
||||||
public Group getApiGroup(@ApiParam("Gruppen-Id der gefordeten Gruppe")
|
public Group getApiGroup(@ApiParam("Gruppen-Id der gefordeten Gruppe")
|
||||||
@PathVariable("id") String groupId) {
|
@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.Parent;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Title;
|
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||||
import mops.gruppen2.domain.service.GroupService;
|
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.domain.service.helper.ValidationHelper;
|
||||||
import mops.gruppen2.infrastructure.GroupCache;
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
@ -67,7 +67,7 @@ public class GroupCreationController {
|
|||||||
|
|
||||||
// ROLE_studentin kann kein CSV importieren
|
// ROLE_studentin kann kein CSV importieren
|
||||||
if (token.getAccount().getRoles().contains("orga")) {
|
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();
|
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.Description;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||||
import mops.gruppen2.domain.model.group.wrapper.Title;
|
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.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.domain.service.helper.ValidationHelper;
|
||||||
import mops.gruppen2.infrastructure.GroupCache;
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -24,7 +26,9 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
import javax.annotation.security.RolesAllowed;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@SuppressWarnings("SameReturnValue")
|
@SuppressWarnings("SameReturnValue")
|
||||||
@ -37,6 +41,7 @@ public class GroupDetailsController {
|
|||||||
|
|
||||||
private final GroupCache groupCache;
|
private final GroupCache groupCache;
|
||||||
private final GroupService groupService;
|
private final GroupService groupService;
|
||||||
|
private final EventStoreService eventStoreService;
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
@GetMapping("/details/{id}")
|
@GetMapping("/details/{id}")
|
||||||
@ -94,6 +99,77 @@ public class GroupDetailsController {
|
|||||||
return "redirect:/gruppen2";
|
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"})
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
@GetMapping("/details/{id}/edit")
|
@GetMapping("/details/{id}/edit")
|
||||||
public String getDetailsEdit(KeycloakAuthenticationToken token,
|
public String getDetailsEdit(KeycloakAuthenticationToken token,
|
||||||
@ -127,8 +203,6 @@ public class GroupDetailsController {
|
|||||||
String principal = token.getName();
|
String principal = token.getName();
|
||||||
Group group = groupCache.group(UUID.fromString(groupId));
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
System.out.println(group);
|
|
||||||
|
|
||||||
groupService.setTitle(group, principal, title);
|
groupService.setTitle(group, principal, title);
|
||||||
groupService.setDescription(group, principal, description);
|
groupService.setDescription(group, principal, description);
|
||||||
|
|
||||||
@ -157,7 +231,7 @@ public class GroupDetailsController {
|
|||||||
String principal = token.getName();
|
String principal = token.getName();
|
||||||
Group group = groupCache.group(UUID.fromString(groupId));
|
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";
|
return "redirect:/gruppen2/details/" + groupId + "/edit";
|
||||||
}
|
}
|
||||||
@ -172,6 +246,9 @@ public class GroupDetailsController {
|
|||||||
Group group = groupCache.group(UUID.fromString(groupId));
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
ValidationHelper.throwIfNoAdmin(group, principal);
|
ValidationHelper.throwIfNoAdmin(group, principal);
|
||||||
|
if (target.equals(principal)) {
|
||||||
|
ValidationHelper.throwIfLastAdmin(group, principal);
|
||||||
|
}
|
||||||
|
|
||||||
groupService.toggleMemberRole(group, principal, target);
|
groupService.toggleMemberRole(group, principal, target);
|
||||||
|
|
||||||
|
@ -33,7 +33,10 @@ public class GruppenfindungController {
|
|||||||
@GetMapping("/gruppen2")
|
@GetMapping("/gruppen2")
|
||||||
public String getIndexPage(KeycloakAuthenticationToken token,
|
public String getIndexPage(KeycloakAuthenticationToken token,
|
||||||
Model model) {
|
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";
|
return "index";
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,40 @@ public class SearchAndInviteController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
@PostMapping("/search")
|
@PostMapping("/search/string")
|
||||||
public String postSearch(KeycloakAuthenticationToken token,
|
public String postSearchString(KeycloakAuthenticationToken token,
|
||||||
Model model,
|
Model model,
|
||||||
@RequestParam("string") String search) {
|
@RequestParam("string") String search) {
|
||||||
|
|
||||||
String principal = token.getName();
|
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);
|
model.addAttribute("groups", groups);
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package mops.gruppen2.persistance;
|
|||||||
import mops.gruppen2.persistance.dto.EventDTO;
|
import mops.gruppen2.persistance.dto.EventDTO;
|
||||||
import org.springframework.data.jdbc.repository.query.Query;
|
import org.springframework.data.jdbc.repository.query.Query;
|
||||||
import org.springframework.data.repository.CrudRepository;
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -16,4 +17,16 @@ public interface EventRepository extends CrudRepository<EventDTO, Long> {
|
|||||||
|
|
||||||
@Query("SELECT * FROM event")
|
@Query("SELECT * FROM event")
|
||||||
List<EventDTO> findAllEvents();
|
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.annotation.Id;
|
||||||
import org.springframework.data.relational.core.mapping.Table;
|
import org.springframework.data.relational.core.mapping.Table;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
@Table("event")
|
@Table("event")
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@ -19,6 +21,6 @@ public class EventDTO {
|
|||||||
String exec_id;
|
String exec_id;
|
||||||
String target_id;
|
String target_id;
|
||||||
|
|
||||||
String event_type;
|
Timestamp event_date;
|
||||||
String event_payload;
|
String event_payload;
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,12 @@ spring.profiles.active = dev
|
|||||||
#keycloak.use-resource-role-mappings = true
|
#keycloak.use-resource-role-mappings = true
|
||||||
#keycloak.autodetect-bearer-only = true
|
#keycloak.autodetect-bearer-only = true
|
||||||
#keycloak.confidential-port = 443
|
#keycloak.confidential-port = 443
|
||||||
keycloak.auth-server-url = https://gruppenkeycloak.herokuapp.com/auth
|
keycloak.auth-server-url = https://churl-keycloak.herokuapp.com/auth
|
||||||
hhu_keycloak.token-uri = https://gruppenkeycloak.herokuapp.com/auth/realms/master/protocol/openid-connect/token
|
hhu_keycloak.token-uri = https://churl-keycloak.herokuapp.com/auth/realms/gruppen/protocol/openid-connect/token
|
||||||
keycloak.principal-attribute = preferred_username
|
keycloak.principal-attribute = preferred_username
|
||||||
keycloak.realm = master
|
keycloak.realm = gruppen
|
||||||
keycloak.resource = gruppen-app
|
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.verify-token-audience = true
|
||||||
keycloak.use-resource-role-mappings = true
|
keycloak.use-resource-role-mappings = true
|
||||||
keycloak.autodetect-bearer-only = 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,
|
group_version INT NOT NULL,
|
||||||
exec_id VARCHAR(50) NOT NULL,
|
exec_id VARCHAR(50) NOT NULL,
|
||||||
target_id VARCHAR(50),
|
target_id VARCHAR(50),
|
||||||
event_type VARCHAR(32) NOT NULL,
|
event_date DATETIME NOT NULL,
|
||||||
event_payload VARCHAR(2500) NOT NULL
|
event_payload VARCHAR(2500) NOT NULL
|
||||||
);
|
);
|
||||||
|
@ -3,34 +3,15 @@
|
|||||||
margin-bottom: 15px;
|
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*/
|
/*Member List*/
|
||||||
.members {
|
.members {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
max-height: calc(100vh - 250px);
|
max-height: calc(100vh - 250px);
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.members li span {
|
li span {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
/*Grouplist Hover Effect*/
|
/*Grouplist Hover Effect*/
|
||||||
.content {
|
.content {
|
||||||
padding-right: 20px;
|
|
||||||
background: #e6f4ff;
|
background: #e6f4ff;
|
||||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
|
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content:hover {
|
.content:hover {
|
||||||
padding-right: 10px;
|
|
||||||
background: #d4ecff;
|
background: #d4ecff;
|
||||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
|
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content:hover .content-heading {
|
.content:hover .content-heading {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
padding-left: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-text-in {
|
.content-text-in {
|
||||||
@ -26,6 +23,5 @@
|
|||||||
|
|
||||||
/*Badges*/
|
/*Badges*/
|
||||||
.badge-pill {
|
.badge-pill {
|
||||||
margin-left: 10px;
|
margin-right: 15px;
|
||||||
align-self: start;
|
|
||||||
}
|
}
|
||||||
|
@ -23,5 +23,5 @@
|
|||||||
.badge-pill {
|
.badge-pill {
|
||||||
align-self: start;
|
align-self: start;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
margin-right: 5px;
|
margin-right: 15px;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
|
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .25);
|
||||||
transition: 100ms;
|
transition: 100ms;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Content Heading*/
|
/*Content Heading*/
|
||||||
@ -33,6 +36,12 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h1, h3 {
|
||||||
|
cursor: default;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
/*Content Paragraph*/
|
/*Content Paragraph*/
|
||||||
.content-text {
|
.content-text {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
@ -65,10 +74,19 @@
|
|||||||
color: #4fa4ff;
|
color: #4fa4ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*Button*/
|
||||||
|
.btn {
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-spacer {
|
||||||
|
}
|
||||||
|
|
||||||
/*Badges*/
|
/*Badges*/
|
||||||
.badge-pill {
|
.badge-pill {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
color: whitesmoke;
|
color: whitesmoke;
|
||||||
|
align-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lecture {
|
.lecture {
|
||||||
@ -87,18 +105,31 @@
|
|||||||
background: var(--warning);
|
background: var(--warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Grid System*/
|
/*Input*/
|
||||||
.row {
|
.input-group {
|
||||||
margin-left: 0;
|
width: auto;
|
||||||
margin-right: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.col {
|
.input-group-append {
|
||||||
padding-left: 0;
|
max-width: 50%;
|
||||||
padding-right: 0;
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Miscellanous*/
|
.input-group-append {
|
||||||
.def-cursor {
|
max-width: 50%;
|
||||||
cursor: default;
|
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>
|
<body>
|
||||||
|
|
||||||
<main th:fragment="bodycontent">
|
<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}">
|
<!--Titel + Beschreibung-->
|
||||||
<div class="content">
|
<div class="content-text" th:insert="~{fragments/forms :: meta}"></div>
|
||||||
<h3 class="def-cursor">Eigenschaften:</h3>
|
|
||||||
|
|
||||||
<!--Titel + Beschreibung-->
|
<!--TODO: Enter AsciiDoc Description-->
|
||||||
<div class="content-text" th:insert="~{fragments/forms :: meta}"></div>
|
|
||||||
|
|
||||||
<!--TODO: Enter AsciiDoc Description-->
|
<div class="content-text-in">
|
||||||
|
<!--Gruppentyp-->
|
||||||
|
<div th:insert="~{fragments/forms :: grouptype}"></div>
|
||||||
|
|
||||||
<div class="content-text-in">
|
<!--Benutzerlimit-->
|
||||||
<!--Gruppentyp-->
|
<div class="mt-2" th:insert="~{fragments/forms :: userlimit}"></div>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<!--CSV Import-->
|
||||||
<!--Submit-->
|
<div class="content-text mb-0" th:insert="~{fragments/forms :: csvimport}"></div>
|
||||||
<button class="btn btn-primary btn-block" type="submit">Gruppe Erstellen</button>
|
</div>
|
||||||
</div>
|
|
||||||
</form>
|
<div class="content d-flex flex-row flex-wrap px-1 px-sm-3">
|
||||||
</div>
|
<!--Submit-->
|
||||||
|
<button class="btn btn-primary btn-block ml-auto" type="submit">Gruppe Erstellen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@ -9,60 +9,198 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<main th:fragment="bodycontent">
|
<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">
|
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0"
|
||||||
<!--Gruppendetails-->
|
th:insert="~{fragments/groups :: groupcontent}"></div>
|
||||||
<div class="col-9 px-0">
|
|
||||||
|
|
||||||
<div class="content" th:insert="~{fragments/groups :: groupcontent}"></div>
|
|
||||||
|
|
||||||
<div class="content">
|
<!--Dummy Integrationen, der Inhalt kommt natürlich aus der Gruppe bzw. von anderen Systemen-->
|
||||||
<!--Button-Bar-->
|
<div class="d-flex flex-row flex-wrap mr-n2 mt-n2">
|
||||||
<div class="row">
|
<!--Materialsammlung-->
|
||||||
<a class="btn btn-primary" href="/gruppen2">Fertig</a>
|
<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-->
|
<div class="content-text-in">
|
||||||
<span class="col"></span>
|
<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()})}">
|
<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>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!--Teilnehmerliste-->
|
<!--Teilnehmerliste-->
|
||||||
<div class="col-3 def-cursor">
|
<div class="def-cursor flex-grow-1 mr-4 mt-2 mw-100 overflow-hidden py-2 px-1 px-sm-3">
|
||||||
<!--Anzahl Text-->
|
<!--Anzahl Text-->
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<span>Teilnehmer: </span>
|
<span>Teilnehmer: </span>
|
||||||
<span th:text="${group.size() + ' von ' + group.getLimit()}"></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>
|
||||||
|
|
||||||
|
<!--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>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -9,113 +9,148 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<main th:fragment="bodycontent">
|
<main th:fragment="bodycontent">
|
||||||
<div class="container-fluid">
|
<h1 th:text="${group.getTitle()}"></h1>
|
||||||
<h1 class="def-cursor" th:text="${group.getTitle()}"></h1>
|
|
||||||
|
|
||||||
<!--Fertig oder löschen-->
|
<!--Fertig oder löschen-->
|
||||||
<div class="content">
|
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||||
<div class="row">
|
<div class="d-flex flex-row flex-wrap mt-n2 mr-n2">
|
||||||
<form method="get" th:action="@{/gruppen2/details/{id}(id=${group.getId()})}">
|
<a class="btn btn-primary flex-grow-1 mt-2 mr-2" style="max-width: 250px;"
|
||||||
<button class="btn btn-primary">Fertig</button>
|
th:href="@{/gruppen2/details/{id}(id=${group.getId()})}">Fertig</a>
|
||||||
</form>
|
|
||||||
|
|
||||||
<!--Spacer-->
|
|
||||||
<span class="col"></span>
|
|
||||||
|
|
||||||
|
<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()})}">
|
<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>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!--Invite Link-->
|
<!--Invite Link-->
|
||||||
<div class="content input-group">
|
<div class="content input-group py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text">Einladungslink:</span>
|
<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>
|
|
||||||
</div>
|
</div>
|
||||||
|
<input class="form-control" id="linkview" readonly th:value="${link}" type="text">
|
||||||
<!--Meta-->
|
<div class="input-group-append">
|
||||||
<div class="content">
|
<button type="button" class="btn btn-secondary" onclick="copyLink()">Link kopieren
|
||||||
<div class="content-heading">
|
</button>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</main>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<main th:fragment="bodycontent">
|
<main th:fragment="bodycontent">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
<h1 class="display-3 def-cursor">UPSI</h1>
|
<h1 class="display-3">UPSI</h1>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p class="lead def-cursor">Da ist wohl etwas schiefgelaufen :(</p>
|
<p class="lead def-cursor">Da ist wohl etwas schiefgelaufen :(</p>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<div class="input-group mb-2"
|
<div class="input-group mb-2"
|
||||||
title="Ein Gruppentitel zwischen 4 und 128 Zeichen. Der Titel ist öffentlich.">
|
title="Ein Gruppentitel zwischen 4 und 128 Zeichen. Der Titel ist öffentlich.">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text text-monospace">Gruppentitel:</span>
|
<span class="input-group-text">Gruppentitel:</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" class="form-control" name="title" minlength="4" maxlength="128"
|
<input type="text" class="form-control" name="title" minlength="4" maxlength="128"
|
||||||
th:value="${group?.getTitle()}" required>
|
th:value="${group?.getTitle()}" required>
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<div class="input-group"
|
<div class="input-group"
|
||||||
title="Eine kurze Gruppenbeschreibung zwischen 4 und 512 Zeichen. Die Beschreibung ist öffentlich.">
|
title="Eine kurze Gruppenbeschreibung zwischen 4 und 512 Zeichen. Die Beschreibung ist öffentlich.">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text text-monospace">Beschreibung:</span>
|
<span class="input-group-text">Beschreibung:</span>
|
||||||
</div>
|
</div>
|
||||||
<textarea class="form-control" name="description" minlength="4" maxlength="512"
|
<textarea class="form-control" name="description" minlength="4" maxlength="512"
|
||||||
th:text="${group?.getDescription()}" required></textarea>
|
th:text="${group?.getDescription()}" required></textarea>
|
||||||
@ -34,8 +34,8 @@
|
|||||||
<!--Gruppentyp-->
|
<!--Gruppentyp-->
|
||||||
<th:block th:fragment="grouptype">
|
<th:block th:fragment="grouptype">
|
||||||
<label for="grouptype">Gruppentyp:</label>
|
<label for="grouptype">Gruppentyp:</label>
|
||||||
<div class="btn-toolbar row mb-2 mx-0" id="grouptype">
|
<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 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="enable('#parentselect'); disable('#parentdummy')">
|
<label class="btn btn-secondary active" onclick="enable('#parentselect'); disable('#parentdummy')">
|
||||||
<input type="radio" name="type" value="PRIVATE" checked> Privat
|
<input type="radio" name="type" value="PRIVATE" checked> Privat
|
||||||
</label>
|
</label>
|
||||||
@ -48,10 +48,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</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.">
|
title="Optional kann eine Veranstaltungszugehörigkeit festgelegt werden.">
|
||||||
<div class="input-group-prepend">
|
<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>
|
</div>
|
||||||
<input type="hidden" id="parentdummy" name="parent" value="00000000-0000-0000-0000-000000000000" disabled>
|
<input type="hidden" id="parentdummy" name="parent" value="00000000-0000-0000-0000-000000000000" disabled>
|
||||||
<select class="custom-select" id="parentselect" name="parent">
|
<select class="custom-select" id="parentselect" name="parent">
|
||||||
@ -66,10 +66,10 @@
|
|||||||
<!--Userlimit-->
|
<!--Userlimit-->
|
||||||
<th:block th:fragment="userlimit">
|
<th:block th:fragment="userlimit">
|
||||||
<label for="userlimit">Teilnehmeranzahl:</label>
|
<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"
|
<input type="hidden" name="limit" id="limit" value="999999"
|
||||||
th:disabled="${group != null && group.getLimit() < 999999} ? 'disabled' : 'false'">
|
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')">
|
<label class="btn btn-secondary active" onclick="disable('#limitselect'); enable('#limit')">
|
||||||
<input type="radio"
|
<input type="radio"
|
||||||
th:checked="${group != null && group.getLimit() < 999999} ? 'false' : 'checked'">
|
th:checked="${group != null && group.getLimit() < 999999} ? 'false' : 'checked'">
|
||||||
@ -82,17 +82,17 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</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.">
|
title="999999 ist die maximal zulässige Teilnehmerzahl. Ist diese Obergrenze erreicht, gilt die Gruppe als unbegrenzt.">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend" style="max-width: 25%">
|
||||||
<span class="input-group-text text-monospace">Limit:</span>
|
<span class="input-group-text">Limit:</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="number" class="form-control" name="limit"
|
<input type="number" class="form-control" name="limit"
|
||||||
th:value="${group != null} ? ${group.getLimit()} : '999999'"
|
th:value="${group != null} ? ${group.getLimit()} : '999999'"
|
||||||
min="1" max="999999" id="limitselect" required
|
min="1" max="999999" id="limitselect" required
|
||||||
th:disabled="${group != null && group.getLimit() < 999999} ? 'false' : 'disabled'">
|
th:disabled="${group != null && group.getLimit() < 999999} ? 'false' : 'disabled'">
|
||||||
<div class="input-group-append">
|
<div class="input-group-append" style="max-width: 25%">
|
||||||
<span class="input-group-text text-monospace">Teilnehmer</span>
|
<span class="input-group-text">Teilnehmer</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -102,7 +102,7 @@
|
|||||||
<div th:fragment="csvimport" class="input-group" th:if="${account.getRoles().contains('orga')}"
|
<div th:fragment="csvimport" class="input-group" th:if="${account.getRoles().contains('orga')}"
|
||||||
title="Das CSV folgt dem Format id,givenname,familyname,email.">
|
title="Das CSV folgt dem Format id,givenname,familyname,email.">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text text-monospace">CSV:</span>
|
<span class="input-group-text">CSV:</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="custom-file">
|
<div class="custom-file">
|
||||||
<input type="file" class="custom-file-input" id="file" name="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://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://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://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>
|
<script type="text/javascript" th:src="@{/js/script.js}"></script>
|
||||||
|
|
||||||
|
@ -7,17 +7,17 @@
|
|||||||
|
|
||||||
<!--Grouptype Badges-->
|
<!--Grouptype Badges-->
|
||||||
<th:block th:fragment="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."
|
title="Kann nicht über die Suche gefunden werden, beitritt ist per Einladungslink möglich."
|
||||||
th:if='${group.isPrivate()}'>Privat</span>
|
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."
|
title="Kann über die Suche gefunden werden, jeder kann beitreten."
|
||||||
th:if="${group.isPublic()}">Öffentlich</span>
|
th:if="${group.isPublic()}">Öffentlich</span>
|
||||||
<span class="badge badge-pill lecture"
|
<span class="badge badge-pill lecture align-self-start"
|
||||||
title="Offizielle Veranstaltung"
|
title="Offizielle Veranstaltung"
|
||||||
th:if='${group.isLecture()}'>Veranstaltung</span>
|
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:if="${parent?.exists()}"
|
||||||
th:title="${'Die Gruppe gehört zur Veranstaltung ' + parent.getTitle() + '.'}"
|
th:title="${'Die Gruppe gehört zur Veranstaltung ' + parent.getTitle() + '.'}"
|
||||||
th:text="${parent.getTitle()}">Parent</span>
|
th:text="${parent.getTitle()}">Parent</span>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
<th:block th:fragment="groupcontent">
|
<th:block th:fragment="groupcontent">
|
||||||
<!--Badges-->
|
<!--Badges-->
|
||||||
<div class="content-heading">
|
<div class="content-heading overflow-hidden">
|
||||||
<span th:replace="~{fragments/groups :: badges}"></span>
|
<span th:replace="~{fragments/groups :: badges}"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -48,6 +48,19 @@
|
|||||||
<!--<div class="body-text-in" th:if="${group.getMembers().contains(user.getId())}"></div>-->
|
<!--<div class="body-text-in" th:if="${group.getMembers().contains(user.getId())}"></div>-->
|
||||||
</th:block>
|
</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-->
|
<!--Buttonbar zum Gruppe beitreten-->
|
||||||
<th:block th:fragment="joingroup">
|
<th:block th:fragment="joingroup">
|
||||||
<div class="content-heading">
|
<div class="content-heading">
|
||||||
@ -59,15 +72,13 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="d-flex flex-row flex-wrap">
|
||||||
<form method="post" th:action="@{/gruppen2/details/{id}/join(id = ${group.getId()})}"
|
<form method="post" th:action="@{/gruppen2/details/{id}/join(id = ${group.getId()})}"
|
||||||
th:unless="${group.isFull()}">
|
th:unless="${group.isFull()}">
|
||||||
<button class="btn btn-success" type="submit">Gruppe beitreten.</button>
|
<button class="btn btn-success" type="submit">Gruppe beitreten.</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="col" th:unless="${group.isFull()}"></div>
|
<a class="btn btn-primary ml-auto" href="/gruppen2"
|
||||||
|
|
||||||
<a class="btn btn-primary" href="/gruppen2"
|
|
||||||
type="submit">Startseite.</a>
|
type="submit">Startseite.</a>
|
||||||
</div>
|
</div>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
@ -9,23 +9,26 @@
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<main th:fragment="bodycontent">
|
<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 px-1 px-sm-3" th:each="group: ${lectures}"
|
||||||
<div class="content" th:each="group: ${groups}">
|
th:insert="fragments/groups :: groupcontentlink"></div>
|
||||||
<div class="content-heading row">
|
</div>
|
||||||
<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 class="mx-n2 mx-sm-0" th:unless="${publics.isEmpty()}">
|
||||||
</div>
|
<h3>Öffentliche Gruppen</h3>
|
||||||
<div class="content-text-in">
|
<div class="content px-1 px-sm-3" th:each="group: ${publics}"
|
||||||
<span th:text="${group.getDescription()}"></span>
|
th:insert="fragments/groups :: groupcontentlink"></div>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<main th:fragment="bodycontent">
|
<main th:fragment="bodycontent">
|
||||||
<div class="container-fluid">
|
<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: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">
|
<main th:fragment="bodycontent">
|
||||||
<div class="container-fluid">
|
<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:insert="~{fragments/groups :: groupcontent}"></div>
|
||||||
|
|
||||||
<div class="content" th:unless="${group.isPrivate()}"
|
<div class="content" th:unless="${group.isPrivate()}"
|
||||||
th:insert="~{fragments/groups :: joingroup}"></div>
|
th:insert="~{fragments/groups :: joingroup}"></div>
|
||||||
|
|
||||||
<div class="content row" th:if="${group.isPrivate()}">
|
<div class="content d-flex flex-row flex-wrap" th:if="${group.isPrivate()}">
|
||||||
<span class="col"></span>
|
<a class="btn btn-primary ml-auto" href="/gruppen2">Startseite.</a>
|
||||||
|
|
||||||
<a class="btn btn-primary" href="/gruppen2">Startseite.</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -8,38 +8,44 @@
|
|||||||
|
|
||||||
<body>
|
<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">
|
<main th:fragment="bodycontent">
|
||||||
<div class="container-fluid">
|
<h1>Suchen</h1>
|
||||||
|
|
||||||
<h1>Suchen</h1>
|
<!--Suchfilter-->
|
||||||
|
<div class="content py-2 px-1 px-sm-3 mx-n2 mx-sm-0">
|
||||||
<!--Suchfilter-->
|
<form method="post" th:action="@{/gruppen2/search/string}">
|
||||||
<div class="content top">
|
<div class="d-flex flex-row flex-wrap mr-n2 mt-n2">
|
||||||
<form method="post" th:action="@{/gruppen2/search}">
|
<div class="input-group mr-2 mt-2 flex-grow-1" style="flex-basis: 75%;">
|
||||||
<div class="input-group mb-3">
|
<div class="input-group-prepend" style="max-width: 50%;">
|
||||||
<div class="input-group-prepend">
|
<span class="input-group-text text-monospace overflow-hidden"
|
||||||
<span class="input-group-text text-monospace">Suchbegriff:</span>
|
style="text-overflow: ellipsis">Suchbegriff:</span>
|
||||||
</div>
|
</div>
|
||||||
<input class="form-control" name="string" type="text">
|
<input class="form-control" required minlength="1" name="string" type="text">
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary" type="submit">Suchen</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--Ergebnisliste-->
|
<button class="btn btn-primary btn-block mr-2 mt-2 flex-grow-1" type="submit">
|
||||||
<div class="content" th:each="group: ${groups}">
|
Suchen
|
||||||
<div class="content-heading row">
|
</button>
|
||||||
<span th:replace="~{fragments/groups :: badges}"></span>
|
|
||||||
|
|
||||||
<a class="link col" th:href="@{/gruppen2/details/{id}(id=${group.getId()})}"
|
|
||||||
th:text="${group.getTitle()}"></a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="content-text-in">
|
</form>
|
||||||
<span th:text="${group.getDescription()}"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<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>
|
</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>
|
</main>
|
||||||
|
|
||||||
</body>
|
</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