1

Merge pull request #3 from ChUrl/REFACTOR-services

Refactor services
This commit is contained in:
Christoph
2020-04-08 21:24:45 +02:00
committed by GitHub
69 changed files with 2026 additions and 1642 deletions

View File

@ -223,7 +223,7 @@
<property name="braceAdjustment" value="0"/> <property name="braceAdjustment" value="0"/>
<property name="caseIndent" value="4"/> <property name="caseIndent" value="4"/>
<property name="throwsIndent" value="4"/> <property name="throwsIndent" value="4"/>
<property name="lineWrappingIndentation" value="8"/> <!--<property name="lineWrappingIndentation" value="8"/>-->
<property name="arrayInitIndent" value="4"/> <property name="arrayInitIndent" value="4"/>
</module> </module>
<!-- <module name="VariableDeclarationUsageDistance"/>--> <!-- <module name="VariableDeclarationUsageDistance"/>-->

View File

@ -1,7 +1,7 @@
version: "3.7" version: "3.7"
services: services:
dbmysql: dbmysql:
image: mysql:5.7 image: mysql:8.0
container_name: 'dbmysql' container_name: 'dbmysql'
environment: environment:
MYSQL_DATABASE: 'gruppen2' MYSQL_DATABASE: 'gruppen2'

View File

@ -3,14 +3,15 @@ package mops.gruppen2.controller;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.api.GroupRequestWrapper; import mops.gruppen2.domain.api.GroupRequestWrapper;
import mops.gruppen2.domain.event.Event;
import mops.gruppen2.domain.exception.EventException; import mops.gruppen2.domain.exception.EventException;
import mops.gruppen2.service.APIFormatterService; import mops.gruppen2.service.APIService;
import mops.gruppen2.service.EventService; import mops.gruppen2.service.EventStoreService;
import mops.gruppen2.service.GroupService; import mops.gruppen2.service.IdService;
import mops.gruppen2.service.UserService; import mops.gruppen2.service.ProjectionService;
import org.springframework.security.access.annotation.Secured; import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
@ -19,7 +20,6 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* Api zum Datenabgleich mit Gruppenfindung. * Api zum Datenabgleich mit Gruppenfindung.
@ -27,48 +27,43 @@ import java.util.stream.Collectors;
//TODO: API-Service? //TODO: API-Service?
@RestController @RestController
@RequestMapping("/gruppen2/api") @RequestMapping("/gruppen2/api")
@Log4j2
public class APIController { public class APIController {
private final EventService eventService; private final EventStoreService eventStoreService;
private final GroupService groupService; private final ProjectionService projectionService;
private final UserService userService;
public APIController(EventService eventService, GroupService groupService, UserService userService) { public APIController(EventStoreService eventStoreService, ProjectionService projectionService) {
this.eventService = eventService; this.eventStoreService = eventStoreService;
this.groupService = groupService; this.projectionService = projectionService;
this.userService = userService;
} }
@GetMapping("/updateGroups/{lastEventId}") @GetMapping("/updateGroups/{lastEventId}")
@Secured("ROLE_api_user") @Secured("ROLE_api_user")
@ApiOperation("Gibt alle Gruppen zurück, in denen sich etwas geändert hat") @ApiOperation("Gibt alle Gruppen zurück, in denen sich etwas geändert hat")
public GroupRequestWrapper updateGroups(@ApiParam("Letzter Status des Anfragestellers") @PathVariable Long lastEventId) throws EventException { public GroupRequestWrapper updateGroups(@ApiParam("Letzter Status des Anfragestellers")
List<Event> events = eventService.getNewEvents(lastEventId); @PathVariable long lastEventId) throws EventException {
log.info("ApiRequest to /updateGroups\n");
return APIFormatterService.wrap(eventService.getMaxEventId(), groupService.projectEventList(events)); return APIService.wrap(eventStoreService.findMaxEventId(),
projectionService.projectNewGroups(lastEventId));
} }
@GetMapping("/getGroupIdsOfUser/{userId}") @GetMapping("/getGroupIdsOfUser/{userId}")
@Secured("ROLE_api_user") @Secured("ROLE_api_user")
@ApiOperation("Gibt alle Gruppen zurück, in denen sich ein Teilnehmer befindet") @ApiOperation("Gibt alle Gruppen zurück, in denen sich ein Teilnehmer befindet")
public List<String> getGroupIdsOfUser(@ApiParam("Teilnehmer dessen groupIds zurückgegeben werden sollen") @PathVariable String userId) { public List<String> getGroupIdsOfUser(@ApiParam("Teilnehmer dessen groupIds zurückgegeben werden sollen")
return userService.getUserGroups(userId).stream() @PathVariable String userId) {
.map(group -> group.getId().toString()) log.info("ApiRequest to /getGroupIdsOfUser\n");
.collect(Collectors.toList()); return IdService.uuidsToString(eventStoreService.findExistingUserGroups(new User(userId)));
} }
@GetMapping("/getGroup/{groupId}") @GetMapping("/getGroup/{groupId}")
@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 getGroupById(@ApiParam("GruppenId der gefordeten Gruppe") @PathVariable String groupId) throws EventException { public Group getGroupById(@ApiParam("GruppenId der gefordeten Gruppe")
List<Event> eventList = eventService.getEventsOfGroup(UUID.fromString(groupId)); @PathVariable String groupId) throws EventException {
List<Group> groups = groupService.projectEventList(eventList); log.info("ApiRequest to /getGroup\n");
return projectionService.projectSingleGroup(UUID.fromString(groupId));
if (groups.isEmpty()) {
return null;
}
return groups.get(0);
} }
} }

View File

@ -1,9 +1,14 @@
package mops.gruppen2.controller; package mops.gruppen2.controller;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Account; import mops.gruppen2.domain.Account;
import mops.gruppen2.service.ControllerService; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.User;
import mops.gruppen2.service.CsvService;
import mops.gruppen2.service.GroupService; import mops.gruppen2.service.GroupService;
import mops.gruppen2.service.KeyCloakService; import mops.gruppen2.service.IdService;
import mops.gruppen2.service.ProjectionService;
import mops.gruppen2.service.ValidationService; import mops.gruppen2.service.ValidationService;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
@ -17,21 +22,25 @@ import org.springframework.web.context.annotation.SessionScope;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.security.RolesAllowed; import javax.annotation.security.RolesAllowed;
import java.util.UUID;
import static mops.gruppen2.service.ControllerService.getGroupType;
import static mops.gruppen2.service.ControllerService.getParent;
import static mops.gruppen2.service.ControllerService.getUserLimit;
import static mops.gruppen2.service.ControllerService.getVisibility;
@SuppressWarnings("SameReturnValue")
@Controller @Controller
@SessionScope @SessionScope
@RequestMapping("/gruppen2") @RequestMapping("/gruppen2")
@Log4j2
public class GroupCreationController { public class GroupCreationController {
private final GroupService groupService; private final GroupService groupService;
private final ControllerService controllerService; private final ProjectionService projectionService;
private final ValidationService validationService;
public GroupCreationController(GroupService groupService, ControllerService controllerService, ValidationService validationService) { public GroupCreationController(GroupService groupService, ProjectionService projectionService) {
this.groupService = groupService; this.groupService = groupService;
this.controllerService = controllerService; this.projectionService = projectionService;
this.validationService = validationService;
} }
@RolesAllowed({"ROLE_orga", "ROLE_actuator"}) @RolesAllowed({"ROLE_orga", "ROLE_actuator"})
@ -39,10 +48,10 @@ public class GroupCreationController {
public String createGroupAsOrga(KeycloakAuthenticationToken token, public String createGroupAsOrga(KeycloakAuthenticationToken token,
Model model) { Model model) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("GET to /createOrga\n");
model.addAttribute("account", account); model.addAttribute("account", new Account(token));
model.addAttribute("lectures", groupService.getAllLecturesWithVisibilityPublic()); model.addAttribute("lectures", projectionService.projectLectures());
return "createOrga"; return "createOrga";
} }
@ -53,28 +62,29 @@ public class GroupCreationController {
public String postCrateGroupAsOrga(KeycloakAuthenticationToken token, public String postCrateGroupAsOrga(KeycloakAuthenticationToken token,
@RequestParam("title") String title, @RequestParam("title") String title,
@RequestParam("description") String description, @RequestParam("description") String description,
@RequestParam(value = "visibility", required = false) Boolean visibility, @RequestParam("visibility") boolean isPrivate,
@RequestParam(value = "lecture", required = false) Boolean lecture, @RequestParam("lecture") boolean isLecture,
@RequestParam("userMaximum") Long userMaximum, @RequestParam("maxInfiniteUsers") boolean isInfinite,
@RequestParam(value = "maxInfiniteUsers", required = false) Boolean maxInfiniteUsers, @RequestParam("userMaximum") long userLimit,
@RequestParam(value = "parent", required = false) String parent, @RequestParam("parent") String parent,
@RequestParam(value = "file", required = false) MultipartFile file) { @RequestParam(value = "file", required = false) MultipartFile file) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /createOrga\n");
UUID parentUUID = controllerService.getUUID(parent);
validationService.checkFields(description, title, userMaximum, maxInfiniteUsers); Account account = new Account(token);
User user = new User(account);
controllerService.createGroupAsOrga(account, Group group = groupService.createGroup(user,
title, title,
description, description,
visibility, getVisibility(isPrivate),
lecture, getGroupType(isLecture),
maxInfiniteUsers, getUserLimit(isInfinite, userLimit),
userMaximum, getParent(parent, isLecture));
parentUUID,
file); groupService.addUsersToGroup(CsvService.readCsvFile(file), group, user);
return "redirect:/gruppen2";
return "redirect:/gruppen2/details/" + IdService.uuidToString(group.getId());
} }
@RolesAllowed("ROLE_studentin") @RolesAllowed("ROLE_studentin")
@ -82,10 +92,10 @@ public class GroupCreationController {
public String createGroupAsStudent(KeycloakAuthenticationToken token, public String createGroupAsStudent(KeycloakAuthenticationToken token,
Model model) { Model model) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("GET to /createStudent\n");
model.addAttribute("account", account); model.addAttribute("account", new Account(token));
model.addAttribute("lectures", groupService.getAllLecturesWithVisibilityPublic()); model.addAttribute("lectures", projectionService.projectLectures());
return "createStudent"; return "createStudent";
} }
@ -96,25 +106,26 @@ public class GroupCreationController {
public String postCreateGroupAsStudent(KeycloakAuthenticationToken token, public String postCreateGroupAsStudent(KeycloakAuthenticationToken token,
@RequestParam("title") String title, @RequestParam("title") String title,
@RequestParam("description") String description, @RequestParam("description") String description,
@RequestParam("userMaximum") Long userMaximum, @RequestParam("visibility") boolean isPrivate,
@RequestParam(value = "visibility", required = false) Boolean visibility, @RequestParam("maxInfiniteUsers") boolean isInfinite,
@RequestParam(value = "maxInfiniteUsers", required = false) Boolean maxInfiniteUsers, @RequestParam("userMaximum") long userLimit,
@RequestParam(value = "parent", required = false) String parent) { @RequestParam("parent") String parent) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /createStudent\n");
UUID parentUUID = controllerService.getUUID(parent);
validationService.checkFields(description, title, userMaximum, maxInfiniteUsers); ValidationService.validateTitle(title);
ValidationService.validateDescription(description);
controllerService.createGroup(account, Account account = new Account(token);
title, User user = new User(account);
description, Group group = groupService.createGroup(user,
visibility, title,
null, description,
maxInfiniteUsers, getVisibility(isPrivate),
userMaximum, GroupType.SIMPLE,
parentUUID); getUserLimit(isInfinite, userLimit),
getParent(parent, false));
return "redirect:/gruppen2"; return "redirect:/gruppen2/details/" + IdService.uuidToString(group.getId());
} }
} }

View File

@ -1,14 +1,16 @@
package mops.gruppen2.controller; package mops.gruppen2.controller;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Account; import mops.gruppen2.domain.Account;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.Role; import mops.gruppen2.domain.Role;
import mops.gruppen2.domain.User; import mops.gruppen2.domain.User;
import mops.gruppen2.domain.Visibility; import mops.gruppen2.domain.Visibility;
import mops.gruppen2.service.ControllerService; import mops.gruppen2.service.CsvService;
import mops.gruppen2.service.GroupService;
import mops.gruppen2.service.IdService;
import mops.gruppen2.service.InviteService; import mops.gruppen2.service.InviteService;
import mops.gruppen2.service.KeyCloakService; import mops.gruppen2.service.ProjectionService;
import mops.gruppen2.service.UserService;
import mops.gruppen2.service.ValidationService; import mops.gruppen2.service.ValidationService;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
@ -26,21 +28,21 @@ import javax.annotation.security.RolesAllowed;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.UUID; import java.util.UUID;
@SuppressWarnings("SameReturnValue")
@Controller @Controller
@SessionScope @SessionScope
@RequestMapping("/gruppen2") @RequestMapping("/gruppen2")
@Log4j2
public class GroupDetailsController { public class GroupDetailsController {
private final ControllerService controllerService;
private final UserService userService;
private final ValidationService validationService;
private final InviteService inviteService; private final InviteService inviteService;
private final GroupService groupService;
private final ProjectionService projectionService;
public GroupDetailsController(ControllerService controllerService, UserService userService, ValidationService validationService, InviteService inviteService) { public GroupDetailsController(InviteService inviteService, GroupService groupService, ProjectionService projectionService) {
this.controllerService = controllerService;
this.userService = userService;
this.validationService = validationService;
this.inviteService = inviteService; this.inviteService = inviteService;
this.groupService = groupService;
this.projectionService = projectionService;
} }
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"}) @RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
@ -50,36 +52,38 @@ public class GroupDetailsController {
HttpServletRequest request, HttpServletRequest request,
@PathVariable("id") String groupId) { @PathVariable("id") String groupId) {
Group group = userService.getGroupById(UUID.fromString(groupId)); log.info("GET to /details\n");
Account account = KeyCloakService.createAccountFromPrincipal(token);
User user = new User(account);
UUID parentId = group.getParent();
String actualURL = request.getRequestURL().toString();
String serverURL = actualURL.substring(0, actualURL.indexOf("gruppen2/"));
Group parent = controllerService.getParent(parentId);
validationService.throwIfGroupNotExisting(group.getTitle()); Account account = new Account(token);
User user = new User(account);
model.addAttribute("account", account); model.addAttribute("account", account);
if (!validationService.checkIfUserInGroup(group, user)) {
validationService.throwIfNoAccessToPrivate(group, user); Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
model.addAttribute("group", group); model.addAttribute("group", group);
model.addAttribute("parentId", parentId);
model.addAttribute("parent", parent); // Parent Badge
UUID parentId = group.getParent();
Group parent = projectionService.projectParent(parentId);
// Detailseite für private Gruppen
if (!ValidationService.checkIfGroupAccess(group, user)) {
return "detailsNoMember"; return "detailsNoMember";
} }
model.addAttribute("parentId", parentId);
model.addAttribute("parent", parent);
model.addAttribute("group", group);
model.addAttribute("roles", group.getRoles()); model.addAttribute("roles", group.getRoles());
model.addAttribute("user", user); model.addAttribute("user", user);
model.addAttribute("admin", Role.ADMIN); model.addAttribute("admin", Role.ADMIN);
model.addAttribute("public", Visibility.PUBLIC); model.addAttribute("public", Visibility.PUBLIC);
model.addAttribute("private", Visibility.PRIVATE); model.addAttribute("private", Visibility.PRIVATE);
model.addAttribute("parent", parent);
if (validationService.checkIfAdmin(group, user)) { // Invitelink Anzeige für Admins
model.addAttribute("link", serverURL + "gruppen2/acceptinvite/" + inviteService.getLinkByGroupId(group.getId())); if (ValidationService.checkIfAdmin(group, user)) {
String actualURL = request.getRequestURL().toString();
String serverURL = actualURL.substring(0, actualURL.indexOf("gruppen2/"));
model.addAttribute("link", serverURL + "gruppen2/acceptinvite/" + inviteService.getLinkByGroup(group));
} }
return "detailsMember"; return "detailsMember";
@ -91,11 +95,13 @@ public class GroupDetailsController {
Model model, Model model,
@PathVariable("id") String groupId) { @PathVariable("id") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("GET to /details/changeMetadata\n");
User user = new User(account);
Group group = userService.getGroupById(UUID.fromString(groupId));
validationService.throwIfNoAdmin(group, user); Account account = new Account(token);
User user = new User(account);
Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
ValidationService.throwIfNoAdmin(group, user);
model.addAttribute("account", account); model.addAttribute("account", account);
model.addAttribute("title", group.getTitle()); model.addAttribute("title", group.getTitle());
@ -116,14 +122,15 @@ public class GroupDetailsController {
@RequestParam("description") String description, @RequestParam("description") String description,
@RequestParam("groupId") String groupId) { @RequestParam("groupId") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /details/changeMetadata\n");
Account account = new Account(token);
User user = new User(account); User user = new User(account);
Group group = userService.getGroupById(UUID.fromString(groupId));
validationService.throwIfNoAdmin(group, user); Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
validationService.checkFields(title, description); ValidationService.throwIfNoAdmin(group, user);
groupService.updateTitle(user, group, title);
controllerService.changeMetaData(account, group, title, description); groupService.updateDescription(user, group, description);
return "redirect:/gruppen2/details/" + groupId; return "redirect:/gruppen2/details/" + groupId;
} }
@ -134,11 +141,13 @@ public class GroupDetailsController {
Model model, Model model,
@PathVariable("id") String groupId) { @PathVariable("id") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("GET to /details/members\n");
Group group = userService.getGroupById(UUID.fromString(groupId));
Account account = new Account(token);
User user = new User(account); User user = new User(account);
validationService.throwIfNoAdmin(group, user); Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
ValidationService.throwIfNoAdmin(group, user);
model.addAttribute("account", account); model.addAttribute("account", account);
model.addAttribute("members", group.getMembers()); model.addAttribute("members", group.getMembers());
@ -155,18 +164,17 @@ public class GroupDetailsController {
@RequestParam("group_id") String groupId, @RequestParam("group_id") String groupId,
@RequestParam("user_id") String userId) { @RequestParam("user_id") String userId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /details/members/changeRole\n");
Group group = userService.getGroupById(UUID.fromString(groupId));
User principle = new User(account);
User user = new User(userId, "", "", "");
validationService.throwIfNoAdmin(group, principle); Account account = new Account(token);
User user = new User(account);
//TODO: checkIfAdmin checkt nicht, dass die rolle geändert wurde. oder die rolle wird nicht geändert Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
ValidationService.throwIfNoAdmin(group, user);
groupService.toggleMemberRole(new User(userId), group);
controllerService.changeRole(account, user, group); // Falls sich der User selbst die Rechte genommen hat
if (!ValidationService.checkIfAdmin(group, user)) {
if (!validationService.checkIfAdmin(group, principle)) {
return "redirect:/gruppen2/details/" + groupId; return "redirect:/gruppen2/details/" + groupId;
} }
@ -177,15 +185,16 @@ public class GroupDetailsController {
@PostMapping("/details/members/changeMaximum") @PostMapping("/details/members/changeMaximum")
@CacheEvict(value = "groups", allEntries = true) @CacheEvict(value = "groups", allEntries = true)
public String changeMaxSize(KeycloakAuthenticationToken token, public String changeMaxSize(KeycloakAuthenticationToken token,
@RequestParam("maximum") Long maximum, @RequestParam("maximum") long userLimit,
@RequestParam("group_id") String groupId) { @RequestParam("group_id") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /details/members/changeMaximum\n");
Group group = userService.getGroupById(UUID.fromString(groupId));
validationService.throwIfNewMaximumIsValid(maximum, group); Account account = new Account(token);
User user = new User(account);
controllerService.updateMaxUser(account, UUID.fromString(groupId), maximum); Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
groupService.updateUserLimit(user, group, userLimit);
return "redirect:/gruppen2/details/members/" + groupId; return "redirect:/gruppen2/details/members/" + groupId;
} }
@ -197,17 +206,15 @@ public class GroupDetailsController {
@RequestParam("group_id") String groupId, @RequestParam("group_id") String groupId,
@RequestParam("user_id") String userId) { @RequestParam("user_id") String userId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /details/members/deleteUser\n");
User principle = new User(account);
User user = new User(userId, "", "", "");
Group group = userService.getGroupById(UUID.fromString(groupId));
validationService.throwIfNoAdmin(group, principle); Account account = new Account(token);
User user = new User(account);
controllerService.deleteUser(account, user, group); // Der eingeloggte User kann sich nicht selbst entfernen
if (!userId.equals(user.getId())) {
if (!validationService.checkIfUserInGroup(group, principle)) { Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
return "redirect:/gruppen2"; groupService.deleteUser(new User(userId), group);
} }
return "redirect:/gruppen2/details/members/" + groupId; return "redirect:/gruppen2/details/members/" + groupId;
@ -220,17 +227,16 @@ public class GroupDetailsController {
Model model, Model model,
@RequestParam("id") String groupId) { @RequestParam("id") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /detailsBeitreten\n");
Account account = new Account(token);
User user = new User(account); User user = new User(account);
Group group = userService.getGroupById(UUID.fromString(groupId));
validationService.throwIfUserAlreadyInGroup(group, user);
validationService.throwIfGroupFull(group);
controllerService.addUser(account, UUID.fromString(groupId));
model.addAttribute("account", account); model.addAttribute("account", account);
Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
groupService.addUser(user, group);
return "redirect:/gruppen2"; return "redirect:/gruppen2";
} }
@ -240,11 +246,13 @@ public class GroupDetailsController {
public String leaveGroup(KeycloakAuthenticationToken token, public String leaveGroup(KeycloakAuthenticationToken token,
@RequestParam("group_id") String groupId) { @RequestParam("group_id") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /leaveGroup\n");
User user = new User(account);
Group group = userService.getGroupById(UUID.fromString(groupId));
controllerService.deleteUser(account, user, group); Account account = new Account(token);
User user = new User(account);
Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
groupService.deleteUser(user, group);
return "redirect:/gruppen2"; return "redirect:/gruppen2";
} }
@ -255,13 +263,13 @@ public class GroupDetailsController {
public String deleteGroup(KeycloakAuthenticationToken token, public String deleteGroup(KeycloakAuthenticationToken token,
@RequestParam("group_id") String groupId) { @RequestParam("group_id") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /deleteGroup\n");
Account account = new Account(token);
User user = new User(account); User user = new User(account);
Group group = userService.getGroupById(UUID.fromString(groupId));
validationService.throwIfNoAdmin(group, user); Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
groupService.deleteGroup(user, group);
controllerService.deleteGroupEvent(user.getId(), UUID.fromString(groupId));
return "redirect:/gruppen2"; return "redirect:/gruppen2";
} }
@ -273,8 +281,13 @@ public class GroupDetailsController {
@RequestParam("group_id") String groupId, @RequestParam("group_id") String groupId,
@RequestParam(value = "file", required = false) MultipartFile file) { @RequestParam(value = "file", required = false) MultipartFile file) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /details/members/addUsersFromCsv\n");
controllerService.addUsersFromCsv(account, file, groupId);
Account account = new Account(token);
User user = new User(account);
Group group = projectionService.projectSingleGroup(IdService.stringToUUID(groupId));
groupService.addUsersToGroup(CsvService.readCsvFile(file), group, user);
return "redirect:/gruppen2/details/members/" + groupId; return "redirect:/gruppen2/details/members/" + groupId;
} }

View File

@ -1,10 +1,11 @@
package mops.gruppen2.controller; package mops.gruppen2.controller;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Account; import mops.gruppen2.domain.Account;
import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.User; import mops.gruppen2.domain.User;
import mops.gruppen2.domain.exception.PageNotFoundException; import mops.gruppen2.domain.exception.PageNotFoundException;
import mops.gruppen2.service.KeyCloakService; import mops.gruppen2.service.ProjectionService;
import mops.gruppen2.service.UserService;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -14,13 +15,15 @@ import javax.annotation.security.RolesAllowed;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@SuppressWarnings("SameReturnValue")
@Controller @Controller
@Log4j2
public class GruppenfindungController { public class GruppenfindungController {
private final UserService userService; private final ProjectionService projectionService;
public GruppenfindungController(UserService userService) { public GruppenfindungController(ProjectionService projectionService) {
this.userService = userService; this.projectionService = projectionService;
} }
@GetMapping("") @GetMapping("")
@ -33,12 +36,15 @@ public class GruppenfindungController {
public String index(KeycloakAuthenticationToken token, public String index(KeycloakAuthenticationToken token,
Model model) { Model model) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("GET to /gruppen2\n");
Account account = new Account(token);
User user = new User(account); User user = new User(account);
model.addAttribute("account", account); model.addAttribute("account", account);
model.addAttribute("gruppen", userService.getUserGroups(user)); model.addAttribute("gruppen", projectionService.projectUserGroups(user));
model.addAttribute("user", user); model.addAttribute("user", user);
model.addAttribute("lecture", GroupType.LECTURE);
return "index"; return "index";
} }

View File

@ -1,13 +1,15 @@
package mops.gruppen2.controller; package mops.gruppen2.controller;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Account; import mops.gruppen2.domain.Account;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.User; import mops.gruppen2.domain.User;
import mops.gruppen2.domain.Visibility; import mops.gruppen2.domain.Visibility;
import mops.gruppen2.service.ControllerService; import mops.gruppen2.service.GroupService;
import mops.gruppen2.service.InviteService; import mops.gruppen2.service.InviteService;
import mops.gruppen2.service.KeyCloakService; import mops.gruppen2.service.ProjectionService;
import mops.gruppen2.service.UserService; import mops.gruppen2.service.SearchService;
import mops.gruppen2.service.ValidationService; import mops.gruppen2.service.ValidationService;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
@ -21,40 +23,61 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.annotation.SessionScope; import org.springframework.web.context.annotation.SessionScope;
import javax.annotation.security.RolesAllowed; import javax.annotation.security.RolesAllowed;
import java.util.ArrayList; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@SuppressWarnings("SameReturnValue")
@Controller @Controller
@SessionScope @SessionScope
@RequestMapping("/gruppen2") @RequestMapping("/gruppen2")
@Log4j2
public class SearchAndInviteController { public class SearchAndInviteController {
private final ValidationService validationService;
private final InviteService inviteService; private final InviteService inviteService;
private final UserService userService; private final GroupService groupService;
private final ControllerService controllerService; private final ProjectionService projectionService;
private final SearchService searchService;
public SearchAndInviteController(ValidationService validationService, InviteService inviteService, UserService userService, ControllerService controllerService) { public SearchAndInviteController(InviteService inviteService, GroupService groupService, ProjectionService projectionService, SearchService searchService) {
this.validationService = validationService;
this.inviteService = inviteService; this.inviteService = inviteService;
this.userService = userService; this.groupService = groupService;
this.controllerService = controllerService; this.projectionService = projectionService;
this.searchService = searchService;
} }
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"}) @RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
@GetMapping("/findGroup") @GetMapping("/searchPage")
public String findGroup(KeycloakAuthenticationToken token, public String findGroup(KeycloakAuthenticationToken token,
Model model, Model model) {
@RequestParam(value = "suchbegriff", required = false) String search) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("GET to /searchPage\n");
List<Group> groups = new ArrayList<>();
groups = validationService.checkSearch(search, groups, account); Account account = new Account(token);
model.addAttribute("account", account);
model.addAttribute("gruppen", Collections.emptyList()); // TODO: verschönern
model.addAttribute("inviteService", inviteService); //TODO: don't inject service
return "search";
}
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator"})
@GetMapping("/search")
public String search(KeycloakAuthenticationToken token,
Model model,
@RequestParam("suchbegriff") String search) {
log.info("GET to /search\n");
Account account = new Account(token);
User user = new User(account);
List<Group> groups = searchService.searchPublicGroups(search, user);
model.addAttribute("account", account); model.addAttribute("account", account);
model.addAttribute("gruppen", groups); model.addAttribute("gruppen", groups);
model.addAttribute("inviteService", inviteService); model.addAttribute("inviteService", inviteService); //TODO: don't inject service
return "search"; return "search";
} }
@ -65,20 +88,26 @@ public class SearchAndInviteController {
Model model, Model model,
@RequestParam("id") String groupId) { @RequestParam("id") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("GET to /detailsSearch\n");
Group group = userService.getGroupById(UUID.fromString(groupId));
UUID parentId = group.getParent(); Account account = new Account(token);
Group parent = controllerService.getParent(parentId);
User user = new User(account); User user = new User(account);
Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
// Parent Badge
UUID parentId = group.getParent();
Group parent = projectionService.projectParent(parentId);
model.addAttribute("account", account); model.addAttribute("account", account);
if (validationService.checkIfUserInGroup(group, user)) { if (ValidationService.checkIfMember(group, user)) {
return "redirect:/gruppen2/details/" + groupId; return "redirect:/gruppen2/details/" + groupId;
} }
model.addAttribute("group", group); model.addAttribute("group", group);
model.addAttribute("parentId", parentId); model.addAttribute("parentId", parentId);
model.addAttribute("parent", parent); model.addAttribute("parent", parent);
model.addAttribute("lecture", GroupType.LECTURE);
return "detailsNoMember"; return "detailsNoMember";
} }
@ -89,17 +118,26 @@ public class SearchAndInviteController {
Model model, Model model,
@PathVariable("link") String link) { @PathVariable("link") String link) {
Group group = userService.getGroupById(inviteService.getGroupIdFromLink(link)); log.info("GET to /acceptInvite\n");
validationService.throwIfGroupNotExisting(group.getTitle()); Account account = new Account(token);
User user = new User(account);
model.addAttribute("account", KeyCloakService.createAccountFromPrincipal(token)); Group group = projectionService.projectSingleGroup(inviteService.getGroupIdFromLink(link));
model.addAttribute("account", account);
model.addAttribute("group", group); model.addAttribute("group", group);
// Gruppe öffentlich
if (group.getVisibility() == Visibility.PUBLIC) { if (group.getVisibility() == Visibility.PUBLIC) {
return "redirect:/gruppen2/details/" + group.getId(); return "redirect:/gruppen2/details/" + group.getId();
} }
// Bereits Mitglied
if (ValidationService.checkIfMember(group, user)) {
return "redirect:/gruppen2/details/" + group.getId();
}
return "joinprivate"; return "joinprivate";
} }
@ -109,14 +147,16 @@ public class SearchAndInviteController {
public String postAcceptInvite(KeycloakAuthenticationToken token, public String postAcceptInvite(KeycloakAuthenticationToken token,
@RequestParam("id") String groupId) { @RequestParam("id") String groupId) {
Account account = KeyCloakService.createAccountFromPrincipal(token); log.info("POST to /acceptInvite\n");
Account account = new Account(token);
User user = new User(account); User user = new User(account);
Group group = userService.getGroupById(UUID.fromString(groupId)); Group group = projectionService.projectSingleGroup(UUID.fromString(groupId));
validationService.throwIfUserAlreadyInGroup(group, user); ValidationService.throwIfMember(group, user);
validationService.throwIfGroupFull(group); ValidationService.throwIfGroupFull(group);
controllerService.addUser(account, UUID.fromString(groupId)); groupService.addUser(user, group);
return "redirect:/gruppen2/details/" + groupId; return "redirect:/gruppen2/details/" + groupId;
} }

View File

@ -1,10 +1,14 @@
package mops.gruppen2.domain; package mops.gruppen2.domain;
import lombok.AllArgsConstructor;
import lombok.Value; import lombok.Value;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import java.util.Set; import java.util.Set;
@Value @Value
@AllArgsConstructor
public class Account { public class Account {
String name; //user_id String name; //user_id
@ -13,4 +17,14 @@ public class Account {
String givenname; String givenname;
String familyname; String familyname;
Set<String> roles; Set<String> roles;
public Account(KeycloakAuthenticationToken token) {
KeycloakPrincipal principal = (KeycloakPrincipal) token.getPrincipal();
name = principal.getName();
email = principal.getKeycloakSecurityContext().getIdToken().getEmail();
image = null;
givenname = principal.getKeycloakSecurityContext().getIdToken().getGivenName();
familyname = principal.getKeycloakSecurityContext().getIdToken().getFamilyName();
roles = token.getAccount().getRoles();
}
} }

View File

@ -1,7 +1,9 @@
package mops.gruppen2.domain; package mops.gruppen2.domain;
import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -14,22 +16,30 @@ import java.util.UUID;
*/ */
@Getter @Getter
@Setter @Setter
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString
public class Group { public class Group {
//TODO: List to Hashmap @EqualsAndHashCode.Include
private final List<User> members;
private final Map<String, Role> roles;
private UUID id; private UUID id;
private String title;
private String description; @ToString.Exclude
private Long userMaximum;
private GroupType type;
private Visibility visibility;
private UUID parent; private UUID parent;
public Group() { //TODO: Single Type for Public/Private/Lecture?
members = new ArrayList<>(); private GroupType type;
roles = new HashMap<>(); private Visibility visibility;
}
private String title;
private String description;
// Default + Minimum: 1
@ToString.Exclude
private long userLimit = 1;
//TODO: List to Hashmap
@ToString.Exclude
private final List<User> members = new ArrayList<>();
@ToString.Exclude
private final Map<String, Role> roles = new HashMap<>();
} }

View File

@ -2,5 +2,9 @@ package mops.gruppen2.domain;
public enum Role { public enum Role {
ADMIN, ADMIN,
MEMBER MEMBER;
public Role toggle() {
return this == ADMIN ? MEMBER : ADMIN;
}
} }

View File

@ -4,16 +4,22 @@ import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor // Für Jackson: CSV-Import
@EqualsAndHashCode(exclude = {"givenname", "familyname", "email"}) @EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString
public class User { public class User {
@EqualsAndHashCode.Include
private String id; private String id;
private String givenname; private String givenname;
@ToString.Exclude
private String familyname; private String familyname;
@ToString.Exclude
private String email; private String email;
public User(Account account) { public User(Account account) {
@ -22,4 +28,16 @@ public class User {
familyname = account.getFamilyname(); familyname = account.getFamilyname();
email = account.getEmail(); email = account.getEmail();
} }
/**
* User identifizieren sich über die Id, mehr wird also manchmal nicht benötigt.
*
* @param userId Die User Id
*/
public User(String userId) {
id = userId;
givenname = "";
familyname = "";
email = "";
}
} }

View File

@ -13,6 +13,6 @@ import java.util.List;
@Getter @Getter
public class GroupRequestWrapper { public class GroupRequestWrapper {
private final Long status; private final long status;
private final List<Group> groupList; private final List<Group> groupList;
} }

View File

@ -2,6 +2,8 @@ package mops.gruppen2.domain.event;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.Role; import mops.gruppen2.domain.Role;
import mops.gruppen2.domain.User; import mops.gruppen2.domain.User;
@ -16,6 +18,8 @@ import java.util.UUID;
*/ */
@Getter @Getter
@NoArgsConstructor // For Jackson @NoArgsConstructor // For Jackson
@ToString
@Log4j2
public class AddUserEvent extends Event { public class AddUserEvent extends Event {
private String givenname; private String givenname;
@ -29,6 +33,13 @@ public class AddUserEvent extends Event {
this.email = email; this.email = email;
} }
public AddUserEvent(Group group, User user) {
super(group.getId(), user.getId());
givenname = user.getGivenname();
familyname = user.getFamilyname();
email = user.getEmail();
}
@Override @Override
protected void applyEvent(Group group) throws EventException { protected void applyEvent(Group group) throws EventException {
User user = new User(userId, givenname, familyname, email); User user = new User(userId, givenname, familyname, email);
@ -37,11 +48,14 @@ public class AddUserEvent extends Event {
throw new UserAlreadyExistsException(getClass().toString()); throw new UserAlreadyExistsException(getClass().toString());
} }
if (group.getMembers().size() >= group.getUserMaximum()) { if (group.getMembers().size() >= group.getUserLimit()) {
throw new GroupFullException(getClass().toString()); throw new GroupFullException(getClass().toString());
} }
group.getMembers().add(user); group.getMembers().add(user);
group.getRoles().put(userId, Role.MEMBER); group.getRoles().put(userId, Role.MEMBER);
log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
log.trace("\t\t\t\t\tNeue Rollen: {}", group.getRoles());
} }
} }

View File

@ -2,6 +2,8 @@ package mops.gruppen2.domain.event;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.GroupType; import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.Visibility; import mops.gruppen2.domain.Visibility;
@ -10,19 +12,19 @@ import java.util.UUID;
@Getter @Getter
@NoArgsConstructor // For Jackson @NoArgsConstructor // For Jackson
@ToString
@Log4j2
public class CreateGroupEvent extends Event { public class CreateGroupEvent extends Event {
private Visibility groupVisibility; private Visibility groupVisibility;
private UUID groupParent; private UUID groupParent;
private GroupType groupType; private GroupType groupType;
private Long groupUserMaximum;
public CreateGroupEvent(UUID groupId, String userId, UUID parent, GroupType type, Visibility visibility, Long userMaximum) { public CreateGroupEvent(UUID groupId, String userId, UUID parent, GroupType type, Visibility visibility) {
super(groupId, userId); super(groupId, userId);
groupParent = parent; groupParent = parent;
groupType = type; groupType = type;
groupVisibility = visibility; groupVisibility = visibility;
groupUserMaximum = userMaximum;
} }
@Override @Override
@ -31,6 +33,7 @@ public class CreateGroupEvent extends Event {
group.setParent(groupParent); group.setParent(groupParent);
group.setType(groupType); group.setType(groupType);
group.setVisibility(groupVisibility); group.setVisibility(groupVisibility);
group.setUserMaximum(groupUserMaximum);
log.trace("\t\t\t\t\tNeue Gruppe: {}", group.toString());
} }
} }

View File

@ -2,18 +2,27 @@ package mops.gruppen2.domain.event;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.User;
import java.util.UUID; import java.util.UUID;
@Getter @Getter
@NoArgsConstructor // For Jackson @NoArgsConstructor // For Jackson
@ToString
@Log4j2
public class DeleteGroupEvent extends Event { public class DeleteGroupEvent extends Event {
public DeleteGroupEvent(UUID groupId, String userId) { public DeleteGroupEvent(UUID groupId, String userId) {
super(groupId, userId); super(groupId, userId);
} }
public DeleteGroupEvent(Group group, User user) {
super(group.getId(), user.getId());
}
@Override @Override
protected void applyEvent(Group group) { protected void applyEvent(Group group) {
group.getRoles().clear(); group.getRoles().clear();
@ -23,6 +32,8 @@ public class DeleteGroupEvent extends Event {
group.setVisibility(null); group.setVisibility(null);
group.setType(null); group.setType(null);
group.setParent(null); group.setParent(null);
group.setUserMaximum(0L); group.setUserLimit(0L);
log.trace("\t\t\t\t\tGelöschte Gruppe: {}", group);
} }
} }

View File

@ -2,6 +2,8 @@ package mops.gruppen2.domain.event;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.User; import mops.gruppen2.domain.User;
import mops.gruppen2.domain.exception.EventException; import mops.gruppen2.domain.exception.EventException;
@ -14,21 +16,32 @@ import java.util.UUID;
*/ */
@Getter @Getter
@NoArgsConstructor // For Jackson @NoArgsConstructor // For Jackson
@ToString
@Log4j2
public class DeleteUserEvent extends Event { public class DeleteUserEvent extends Event {
public DeleteUserEvent(UUID groupId, String userId) { public DeleteUserEvent(UUID groupId, String userId) {
super(groupId, userId); super(groupId, userId);
} }
public DeleteUserEvent(Group group, User user) {
super(group.getId(), user.getId());
}
//TODO: what the fuck use List.remove
@Override @Override
protected void applyEvent(Group group) throws EventException { protected void applyEvent(Group group) throws EventException {
for (User user : group.getMembers()) { for (User user : group.getMembers()) {
if (user.getId().equals(this.userId)) { if (user.getId().equals(userId)) {
group.getMembers().remove(user); group.getMembers().remove(user);
group.getRoles().remove(user.getId()); group.getRoles().remove(user.getId());
log.trace("\t\t\t\t\tNeue Members: {}", group.getMembers());
log.trace("\t\t\t\t\tNeue Rollen: {}", group.getRoles());
return; return;
} }
} }
throw new UserNotFoundException(this.getClass().toString()); throw new UserNotFoundException(getClass().toString());
} }
} }

View File

@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.exception.EventException; import mops.gruppen2.domain.exception.EventException;
import mops.gruppen2.domain.exception.GroupIdMismatchException; import mops.gruppen2.domain.exception.GroupIdMismatchException;
@ -12,6 +13,7 @@ import mops.gruppen2.domain.exception.GroupIdMismatchException;
import java.util.UUID; import java.util.UUID;
@Log4j2
@JsonTypeInfo( @JsonTypeInfo(
use = JsonTypeInfo.Id.NAME, use = JsonTypeInfo.Id.NAME,
property = "type" property = "type"
@ -24,7 +26,7 @@ import java.util.UUID;
@JsonSubTypes.Type(value = UpdateGroupTitleEvent.class, name = "UpdateGroupTitleEvent"), @JsonSubTypes.Type(value = UpdateGroupTitleEvent.class, name = "UpdateGroupTitleEvent"),
@JsonSubTypes.Type(value = UpdateRoleEvent.class, name = "UpdateRoleEvent"), @JsonSubTypes.Type(value = UpdateRoleEvent.class, name = "UpdateRoleEvent"),
@JsonSubTypes.Type(value = DeleteGroupEvent.class, name = "DeleteGroupEvent"), @JsonSubTypes.Type(value = DeleteGroupEvent.class, name = "DeleteGroupEvent"),
@JsonSubTypes.Type(value = UpdateUserMaxEvent.class, name = "UpdateUserMaxEvent") @JsonSubTypes.Type(value = UpdateUserLimitEvent.class, name = "UpdateUserLimitEvent")
}) })
@Getter @Getter
@NoArgsConstructor @NoArgsConstructor
@ -34,17 +36,25 @@ public abstract class Event {
protected UUID groupId; protected UUID groupId;
protected String userId; protected String userId;
public void apply(Group group) throws EventException { public Group apply(Group group) throws EventException {
checkGroupIdMatch(group.getId()); checkGroupIdMatch(group.getId());
log.trace("Event angewendet:\t{}", this);
applyEvent(group); applyEvent(group);
return group;
} }
private void checkGroupIdMatch(UUID groupId) { private void checkGroupIdMatch(UUID groupId) {
if (groupId == null || this.groupId.equals(groupId)) { // CreateGroupEvents müssen die Id erst initialisieren
if (this instanceof CreateGroupEvent) {
return; return;
} }
throw new GroupIdMismatchException(getClass().toString()); if (!this.groupId.equals(groupId)) {
throw new GroupIdMismatchException(getClass().toString());
}
} }
protected abstract void applyEvent(Group group) throws EventException; protected abstract void applyEvent(Group group) throws EventException;

View File

@ -2,7 +2,10 @@ package mops.gruppen2.domain.event;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.exception.BadParameterException; import mops.gruppen2.domain.exception.BadParameterException;
import java.util.UUID; import java.util.UUID;
@ -12,6 +15,8 @@ import java.util.UUID;
*/ */
@Getter @Getter
@NoArgsConstructor // For Jackson @NoArgsConstructor // For Jackson
@ToString
@Log4j2
public class UpdateGroupDescriptionEvent extends Event { public class UpdateGroupDescriptionEvent extends Event {
private String newGroupDescription; private String newGroupDescription;
@ -21,6 +26,11 @@ public class UpdateGroupDescriptionEvent extends Event {
this.newGroupDescription = newGroupDescription.trim(); this.newGroupDescription = newGroupDescription.trim();
} }
public UpdateGroupDescriptionEvent(Group group, User user, String newGroupDescription) {
super(group.getId(), user.getId());
this.newGroupDescription = newGroupDescription.trim();
}
@Override @Override
protected void applyEvent(Group group) { protected void applyEvent(Group group) {
if (newGroupDescription.isEmpty()) { if (newGroupDescription.isEmpty()) {
@ -28,5 +38,7 @@ public class UpdateGroupDescriptionEvent extends Event {
} }
group.setDescription(newGroupDescription); group.setDescription(newGroupDescription);
log.trace("\t\t\t\t\tNeue Beschreibung: {}", group.getDescription());
} }
} }

View File

@ -2,7 +2,10 @@ package mops.gruppen2.domain.event;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.exception.BadParameterException; import mops.gruppen2.domain.exception.BadParameterException;
import java.util.UUID; import java.util.UUID;
@ -12,6 +15,8 @@ import java.util.UUID;
*/ */
@Getter @Getter
@NoArgsConstructor // For Jackson @NoArgsConstructor // For Jackson
@ToString
@Log4j2
public class UpdateGroupTitleEvent extends Event { public class UpdateGroupTitleEvent extends Event {
private String newGroupTitle; private String newGroupTitle;
@ -21,6 +26,11 @@ public class UpdateGroupTitleEvent extends Event {
this.newGroupTitle = newGroupTitle.trim(); this.newGroupTitle = newGroupTitle.trim();
} }
public UpdateGroupTitleEvent(Group group, User user, String newGroupTitle) {
super(group.getId(), user.getId());
this.newGroupTitle = newGroupTitle.trim();
}
@Override @Override
protected void applyEvent(Group group) { protected void applyEvent(Group group) {
if (newGroupTitle.isEmpty()) { if (newGroupTitle.isEmpty()) {
@ -28,6 +38,8 @@ public class UpdateGroupTitleEvent extends Event {
} }
group.setTitle(newGroupTitle); group.setTitle(newGroupTitle);
log.trace("\t\t\t\t\tNeuer Titel: {}", group.getTitle());
} }
} }

View File

@ -2,8 +2,11 @@ package mops.gruppen2.domain.event;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.Role; import mops.gruppen2.domain.Role;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.exception.UserNotFoundException; import mops.gruppen2.domain.exception.UserNotFoundException;
import java.util.UUID; import java.util.UUID;
@ -13,6 +16,8 @@ import java.util.UUID;
*/ */
@Getter @Getter
@NoArgsConstructor // For Jackson @NoArgsConstructor // For Jackson
@ToString
@Log4j2
public class UpdateRoleEvent extends Event { public class UpdateRoleEvent extends Event {
private Role newRole; private Role newRole;
@ -22,10 +27,18 @@ public class UpdateRoleEvent extends Event {
this.newRole = newRole; this.newRole = newRole;
} }
public UpdateRoleEvent(Group group, User user, Role newRole) {
super(group.getId(), user.getId());
this.newRole = newRole;
}
@Override @Override
protected void applyEvent(Group group) throws UserNotFoundException { protected void applyEvent(Group group) throws UserNotFoundException {
if (group.getRoles().containsKey(userId)) { if (group.getRoles().containsKey(userId)) {
group.getRoles().put(userId, newRole); group.getRoles().put(userId, newRole);
log.trace("\t\t\t\t\tNeue Rollen: {}", group.getRoles());
return; return;
} }

View File

@ -0,0 +1,42 @@
package mops.gruppen2.domain.event;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.exception.BadParameterException;
import mops.gruppen2.domain.exception.EventException;
import java.util.UUID;
@Getter
@NoArgsConstructor
@ToString
@Log4j2
public class UpdateUserLimitEvent extends Event {
private long userLimit;
public UpdateUserLimitEvent(UUID groupId, String userId, long userLimit) {
super(groupId, userId);
this.userLimit = userLimit;
}
public UpdateUserLimitEvent(Group group, User user, long userLimit) {
super(group.getId(), user.getId());
this.userLimit = userLimit;
}
@Override
protected void applyEvent(Group group) throws EventException {
if (userLimit <= 0 || userLimit < group.getMembers().size()) {
throw new BadParameterException("Usermaximum zu klein.");
}
group.setUserLimit(userLimit);
log.trace("\t\t\t\t\tNeues UserLimit: {}", group.getUserLimit());
}
}

View File

@ -1,30 +0,0 @@
package mops.gruppen2.domain.event;
import lombok.Getter;
import lombok.NoArgsConstructor;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.exception.BadParameterException;
import mops.gruppen2.domain.exception.EventException;
import java.util.UUID;
@Getter
@NoArgsConstructor
public class UpdateUserMaxEvent extends Event {
private Long userMaximum;
public UpdateUserMaxEvent(UUID groupId, String userId, Long userMaximum) {
super(groupId, userId);
this.userMaximum = userMaximum;
}
@Override
protected void applyEvent(Group group) throws EventException {
if (userMaximum <= 0 || userMaximum < group.getMembers().size()) {
throw new BadParameterException("Usermaximum zu klein.");
}
group.setUserMaximum(userMaximum);
}
}

View File

@ -0,0 +1,10 @@
package mops.gruppen2.domain.exception;
import org.springframework.http.HttpStatus;
public class BadPayloadException extends EventException {
public BadPayloadException(String info) {
super(HttpStatus.INTERNAL_SERVER_ERROR, "Die Payload konnte nicht übersetzt werden!", info);
}
}

View File

@ -5,6 +5,6 @@ import org.springframework.http.HttpStatus;
public class UserNotFoundException extends EventException { public class UserNotFoundException extends EventException {
public UserNotFoundException(String info) { public UserNotFoundException(String info) {
super(HttpStatus.NOT_FOUND, "Der User wurde nicht gefunden.", info); super(HttpStatus.NOT_FOUND, "Der User existiert nicht.", info);
} }
} }

View File

@ -11,30 +11,61 @@ import java.util.List;
@Repository @Repository
public interface EventRepository extends CrudRepository<EventDTO, Long> { public interface EventRepository extends CrudRepository<EventDTO, Long> {
@Query("SELECT distinct group_id FROM event WHERE user_id =:id AND event_type = :type") // ####################################### GROUP IDs #########################################
List<String> findGroupIdsWhereUserId(@Param("id") String userId, @Param("type") String type);
@Query("SELECT * from event WHERE group_id =:id") @Query("SELECT DISTINCT group_id FROM event"
List<EventDTO> findEventDTOByGroupId(@Param("id") String groupId); + " WHERE user_id = :userId AND event_type = :type")
List<String> findGroupIdsByUserAndType(@Param("userId") String userId,
@Param("type") String type);
@Query("SELECT DISTINCT group_id FROM event WHERE event_id > :status") @Query("SELECT DISTINCT group_id FROM event"
List<String> findNewEventSinceStatus(@Param("status") Long status); + " WHERE event_id > :status")
List<String> findGroupIdsWhereEventIdGreaterThanStatus(@Param("status") long status);
@Query("SELECT * FROM event WHERE group_id IN (:groupIds) ") // ####################################### EVENT DTOs ########################################
List<EventDTO> findAllEventsOfGroups(@Param("groupIds") List<String> groupIds);
@Query("SELECT * FROM event"
+ " WHERE group_id IN (:groupIds) ")
List<EventDTO> findEventDTOsByGroup(@Param("groupIds") List<String> groupIds);
@Query("SELECT * FROM event"
+ " WHERE group_id IN (:userIds) ")
List<EventDTO> findEventDTOsByUser(@Param("groupIds") List<String> userIds);
@Query("SELECT * FROM event"
+ " WHERE event_type IN (:types)")
List<EventDTO> findEventDTOsByType(@Param("types") List<String> types);
@Query("SELECT * FROM event"
+ " WHERE event_type IN (:types) AND group_id IN (:groupIds)")
List<EventDTO> findEventDTOsByGroupAndType(@Param("types") List<String> types,
@Param("groupIds") List<String> groupIds);
@Query("SELECT * FROM event"
+ " WHERE event_type IN (:types) AND user_id = :userId")
List<EventDTO> findEventDTOsByUserAndType(@Param("types") List<String> types,
@Param("userId") String userId);
// ################################ LATEST EVENT DTOs ########################################
@Query("WITH ranked_events AS ("
+ "SELECT *, ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY event_id DESC) AS rn"
+ " FROM event"
+ " WHERE user_id = :userId AND event_type IN ('AddUserEvent', 'DeleteUserEvent')"
+ ")"
+ "SELECT * FROM ranked_events WHERE rn = 1;")
List<EventDTO> findLatestEventDTOsPartitionedByGroupByUser(@Param("userId") String userId);
@Query("WITH ranked_events AS ("
+ "SELECT *, ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY event_id DESC) AS rn"
+ " FROM event"
+ " WHERE event_type IN (:types)"
+ ")"
+ "SELECT * FROM ranked_events WHERE rn = 1;")
List<EventDTO> findLatestEventDTOsPartitionedByGroupByType(@Param("types") List<String> types);
// ######################################### COUNT ###########################################
@Query("SELECT MAX(event_id) FROM event") @Query("SELECT MAX(event_id) FROM event")
Long getHighesEventID(); Long findMaxEventId();
@Query("SELECT * FROM event WHERE event_type = :type")
List<EventDTO> findAllEventsByType(@Param("type") String type);
@Query("SELECT * FROM event WHERE event_type = :type AND user_id = :userId")
List<EventDTO> findEventsByTypeAndUserId(@Param("type") String type, @Param("userId") String userId);
@Query("SELECT COUNT(*) FROM event WHERE event_type = :type AND group_id = :groupId")
Long countEventsByTypeAndGroupId(@Param("type") String type, @Param("groupId") String groupId);
@Query("SELECT COUNT(*) FROM event WHERE group_id = :groupId AND user_id = :userId AND event_type = :type")
Long countEventsByGroupIdAndUserIdAndEventType(@Param("groupId") String groupId, @Param("userId") String userId, @Param("type") String type);
} }

View File

@ -1,5 +1,6 @@
package mops.gruppen2.service; package mops.gruppen2.service;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.api.GroupRequestWrapper; import mops.gruppen2.domain.api.GroupRequestWrapper;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -7,9 +8,10 @@ import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
@Service @Service
public final class APIFormatterService { @Log4j2
public class APIService {
private APIFormatterService() {} private APIService() {}
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, groupList);

View File

@ -1,359 +1,44 @@
package mops.gruppen2.service; package mops.gruppen2.service;
import mops.gruppen2.domain.Account; import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.GroupType; import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.Role;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.Visibility; import mops.gruppen2.domain.Visibility;
import mops.gruppen2.domain.event.AddUserEvent;
import mops.gruppen2.domain.event.CreateGroupEvent;
import mops.gruppen2.domain.event.DeleteGroupEvent;
import mops.gruppen2.domain.event.DeleteUserEvent;
import mops.gruppen2.domain.event.UpdateGroupDescriptionEvent;
import mops.gruppen2.domain.event.UpdateGroupTitleEvent;
import mops.gruppen2.domain.event.UpdateRoleEvent;
import mops.gruppen2.domain.event.UpdateUserMaxEvent;
import mops.gruppen2.domain.exception.EventException;
import mops.gruppen2.domain.exception.WrongFileException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
import static mops.gruppen2.domain.Role.ADMIN;
@Service @Service
public class ControllerService { @Log4j2
public final class ControllerService {
private static final Logger LOG = LoggerFactory.getLogger("controllerServiceLogger"); private ControllerService() {}
private final EventService eventService;
private final UserService userService;
private final ValidationService validationService;
private final InviteService inviteService;
public ControllerService(EventService eventService, UserService userService, ValidationService validationService, InviteService inviteService) { public static Visibility getVisibility(boolean isPrivate) {
this.eventService = eventService; return isPrivate ? Visibility.PRIVATE : Visibility.PUBLIC;
this.userService = userService;
this.validationService = validationService;
this.inviteService = inviteService;
} }
private static User getVeteranMember(Account account, Group group) { public static GroupType getGroupType(boolean isLecture) {
List<User> members = group.getMembers(); return isLecture ? GroupType.LECTURE : GroupType.SIMPLE;
String newAdminId;
if (members.get(0).getId().equals(account.getName())) {
newAdminId = members.get(1).getId();
} else {
newAdminId = members.get(0).getId();
}
return new User(newAdminId, "", "", "");
} }
/** /**
* Wie createGroup, nur das hier die Gruppe auch als Veranstaltung gesetzt werden kann und CSV Dateien mit Nutzern * Wenn die maximale Useranzahl unendlich ist, wird das Maximum auf 100000 gesetzt.
* eingelesen werden können. * Praktisch gibt es also maximal 100000 Nutzer pro Gruppe.
* *
* @param account Der Nutzer der die Gruppe erstellt * @param isInfinite Gibt an, ob es unendlich viele User geben soll
* @param title Parameter für die neue Gruppe * @param userLimit Das Maximum an Usern, falls es eins gibt
* @param description Parameter für die neue Gruppe
* @param isVisibilityPrivate Parameter für die neue Gruppe
* @param isLecture Parameter für die neue Gruppe
* @param isMaximumInfinite Parameter für die neue Gruppe
* @param userMaximum Parameter für die neue Gruppe
* @param parent Parameter für die neue Gruppe
* @param file Parameter für die neue Gruppe
*/
public void createGroupAsOrga(Account account,
String title,
String description,
Boolean isVisibilityPrivate,
Boolean isLecture,
Boolean isMaximumInfinite,
Long userMaximum,
UUID parent,
MultipartFile file) {
userMaximum = checkInfiniteUsers(isMaximumInfinite, userMaximum);
List<User> newUsers = readCsvFile(file);
List<User> oldUsers = new ArrayList<>();
User user = new User(account);
oldUsers.add(user);
removeOldUsersFromNewUsers(oldUsers, newUsers);
userMaximum = adjustUserMaximum((long) newUsers.size(), 1L, userMaximum);
UUID groupId = createGroup(account,
title,
description,
isVisibilityPrivate,
isLecture,
isMaximumInfinite,
userMaximum, parent);
addUserList(newUsers, groupId);
}
/**
* Wenn die maximale Useranzahl unendlich ist, wird das Maximum auf 100000 gesetzt. Praktisch gibt es also Maximla 100000
* Nutzer pro Gruppe.
*
* @param isMaximumInfinite Gibt an ob es unendlich viele User geben soll
* @param userMaximum Das Maximum an Usern, falls es eins gibt
* *
* @return Maximum an Usern * @return Maximum an Usern
*/ */
private static Long checkInfiniteUsers(Boolean isMaximumInfinite, Long userMaximum) { public static long getUserLimit(boolean isInfinite, long userLimit) {
isMaximumInfinite = isMaximumInfinite != null; return isInfinite ? Long.MAX_VALUE : userLimit;
if (isMaximumInfinite) {
userMaximum = 100_000L;
}
return userMaximum;
} }
/** /**
* Erzeugt eine neue Gruppe, fügt den User, der die Gruppe erstellt hat, hinzu und setzt seine Rolle als Admin fest. * Ermittelt die UUID des Parents, falls vorhanden.
* Zudem wird der Gruppentitel und die Gruppenbeschreibung erzeugt, welche vorher der Methode übergeben wurden.
* Aus diesen Event-Objekten wird eine Liste erzeugt, welche daraufhin mithilfe des EventServices gesichert wird.
*
* @param account Keycloak-Account
* @param title Gruppentitel
* @param description Gruppenbeschreibung
*/ */
//TODO: remove booleans public static UUID getParent(String parent, boolean isLecture) {
public UUID createGroup(Account account, return isLecture ? IdService.emptyUUID() : IdService.stringToUUID(parent);
String title,
String description,
Boolean isVisibilityPrivate,
Boolean isLecture,
Boolean isMaximumInfinite,
Long userMaximum,
UUID parent) {
userMaximum = checkInfiniteUsers(isMaximumInfinite, userMaximum);
Visibility groupVisibility = setGroupVisibility(isVisibilityPrivate);
UUID groupId = UUID.randomUUID();
GroupType groupType = setGroupType(isLecture);
CreateGroupEvent createGroupEvent = new CreateGroupEvent(groupId,
account.getName(),
parent,
groupType,
groupVisibility,
userMaximum);
eventService.saveEvent(createGroupEvent);
inviteService.createLink(groupId);
User user = new User(account.getName(), "", "", "");
addUser(account, groupId);
updateTitle(account, groupId, title);
updateDescription(account, groupId, description);
updateRole(user, groupId);
return groupId;
} }
private static List<User> readCsvFile(MultipartFile file) throws EventException {
if (file == null) {
return new ArrayList<>();
}
if (!file.isEmpty()) {
try {
List<User> userList = CsvService.read(file.getInputStream());
return userList.stream().distinct().collect(Collectors.toList()); //filters duplicates from list
} catch (IOException ex) {
LOG.warn("File konnte nicht gelesen werden");
throw new WrongFileException(file.getOriginalFilename());
}
}
return new ArrayList<>();
}
private static void removeOldUsersFromNewUsers(List<User> oldUsers, List<User> newUsers) {
for (User oldUser : oldUsers) {
newUsers.remove(oldUser);
}
}
private static Long adjustUserMaximum(Long newUsers, Long oldUsers, Long maxUsers) {
if (oldUsers + newUsers > maxUsers) {
maxUsers = oldUsers + newUsers;
}
return maxUsers;
}
private void addUserList(List<User> newUsers, UUID groupId) {
for (User user : newUsers) {
Group group = userService.getGroupById(groupId);
if (group.getMembers().contains(user)) {
LOG.info("Benutzer {} ist bereits in Gruppe", user.getId());
} else {
AddUserEvent addUserEvent = new AddUserEvent(groupId, user.getId(), user.getGivenname(), user.getFamilyname(), user.getEmail());
eventService.saveEvent(addUserEvent);
}
}
}
private static Visibility setGroupVisibility(Boolean isVisibilityPrivate) {
isVisibilityPrivate = isVisibilityPrivate != null;
if (isVisibilityPrivate) {
return Visibility.PRIVATE;
} else {
return Visibility.PUBLIC;
}
}
private static GroupType setGroupType(Boolean isLecture) {
isLecture = isLecture != null;
if (isLecture) {
return GroupType.LECTURE;
} else {
return GroupType.SIMPLE;
}
}
public void addUser(Account account, UUID groupId) {
AddUserEvent addUserEvent = new AddUserEvent(groupId, account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail());
eventService.saveEvent(addUserEvent);
}
private void updateTitle(Account account, UUID groupId, String title) {
UpdateGroupTitleEvent updateGroupTitleEvent = new UpdateGroupTitleEvent(groupId, account.getName(), title);
eventService.saveEvent(updateGroupTitleEvent);
}
public void updateRole(User user, UUID groupId) throws EventException {
UpdateRoleEvent updateRoleEvent;
Group group = userService.getGroupById(groupId);
validationService.throwIfNotInGroup(group, user);
if (group.getRoles().get(user.getId()) == ADMIN) {
updateRoleEvent = new UpdateRoleEvent(group.getId(), user.getId(), Role.MEMBER);
} else {
updateRoleEvent = new UpdateRoleEvent(group.getId(), user.getId(), ADMIN);
}
eventService.saveEvent(updateRoleEvent);
}
private void updateDescription(Account account, UUID groupId, String description) {
UpdateGroupDescriptionEvent updateGroupDescriptionEvent = new UpdateGroupDescriptionEvent(groupId, account.getName(), description);
eventService.saveEvent(updateGroupDescriptionEvent);
}
public void addUsersFromCsv(Account account, MultipartFile file, String groupId) {
Group group = userService.getGroupById(UUID.fromString(groupId));
List<User> newUserList = readCsvFile(file);
removeOldUsersFromNewUsers(group.getMembers(), newUserList);
UUID groupUUID = getUUID(groupId);
Long newUserMaximum = adjustUserMaximum((long) newUserList.size(), (long) group.getMembers().size(), group.getUserMaximum());
if (newUserMaximum > group.getUserMaximum()) {
updateMaxUser(account, groupUUID, newUserMaximum);
}
addUserList(newUserList, groupUUID);
}
public UUID getUUID(String id) {
return UUID.fromString(Objects.requireNonNullElse(id, "00000000-0000-0000-0000-000000000000"));
}
public void updateMaxUser(Account account, UUID groupId, Long userMaximum) {
UpdateUserMaxEvent updateUserMaxEvent = new UpdateUserMaxEvent(groupId, account.getName(), userMaximum);
eventService.saveEvent(updateUserMaxEvent);
}
public void changeMetaData(Account account, Group group, String title, String description) {
if (!title.equals(group.getTitle())) {
updateTitle(account, group.getId(), title);
}
if (!description.equals(group.getDescription())) {
updateDescription(account, group.getId(), description);
}
}
public Group getParent(UUID parentId) {
Group parent = new Group();
if (!idIsEmpty(parentId)) {
parent = userService.getGroupById(parentId);
}
return parent;
}
public void deleteUser(Account account, User user, Group group) throws EventException {
changeRoleIfLastAdmin(account, group);
validationService.throwIfNotInGroup(group, user);
deleteUserEvent(user, group.getId());
if (validationService.checkIfGroupEmpty(group.getId())) {
deleteGroupEvent(user.getId(), group.getId());
}
}
private static boolean idIsEmpty(UUID id) {
if (id == null) {
return true;
}
return "00000000-0000-0000-0000-000000000000".equals(id.toString());
}
private void deleteUserEvent(User user, UUID groupId) {
DeleteUserEvent deleteUserEvent = new DeleteUserEvent(groupId, user.getId());
eventService.saveEvent(deleteUserEvent);
}
public void deleteGroupEvent(String userId, UUID groupId) {
DeleteGroupEvent deleteGroupEvent = new DeleteGroupEvent(groupId, userId);
inviteService.destroyLink(groupId);
eventService.saveEvent(deleteGroupEvent);
}
private void promoteVeteranMember(Account account, Group group) {
if (validationService.checkIfLastAdmin(account, group)) {
User newAdmin = getVeteranMember(account, group);
updateRole(newAdmin, group.getId());
}
}
public void changeRoleIfLastAdmin(Account account, Group group) {
if (group.getMembers().size() <= 1) {
return;
}
promoteVeteranMember(account, group);
}
public void changeRole(Account account, User user, Group group) {
if (user.getId().equals(account.getName())) {
if (group.getMembers().size() <= 1) {
validationService.throwIfLastAdmin(account, group);
}
promoteVeteranMember(account, group);
}
updateRole(user, group.getId());
}
} }

View File

@ -3,19 +3,42 @@ package mops.gruppen2.service;
import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.dataformat.csv.CsvMapper; import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema; import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.User; import mops.gruppen2.domain.User;
import mops.gruppen2.domain.exception.EventException;
import mops.gruppen2.domain.exception.WrongFileException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Service @Service
@Log4j2
public final class CsvService { public final class CsvService {
private CsvService() {} private CsvService() {}
static List<User> read(InputStream stream) throws IOException { 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(); CsvMapper mapper = new CsvMapper();
CsvSchema schema = mapper.schemaFor(User.class).withHeader().withColumnReordering(true); CsvSchema schema = mapper.schemaFor(User.class).withHeader().withColumnReordering(true);

View File

@ -1,168 +0,0 @@
package mops.gruppen2.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import mops.gruppen2.domain.dto.EventDTO;
import mops.gruppen2.domain.event.Event;
import mops.gruppen2.repository.EventRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
//TODO: Evtl aufsplitten in EventRepoService und EventService?
public class EventService {
private static final Logger LOG = LoggerFactory.getLogger(EventService.class);
private final EventRepository eventStore;
public EventService(EventRepository eventStore) {
this.eventStore = eventStore;
}
/**
* Erzeugt ein DTO aus einem Event und speicher es.
*
* @param event Event, welches gespeichert wird
*/
public void saveEvent(Event event) {
eventStore.save(getDTOFromEvent(event));
}
public void saveAll(Event... events) {
for (Event event : events) {
eventStore.save(getDTOFromEvent(event));
}
}
/**
* Erzeugt aus einem Event Objekt ein EventDTO Objekt.
*
* @param event Event, welches in DTO übersetzt wird
*
* @return EventDTO (Neues DTO)
*/
public EventDTO getDTOFromEvent(Event event) {
String payload = "";
try {
payload = JsonService.serializeEvent(event);
} catch (JsonProcessingException e) {
LOG.error("Event ({}) konnte nicht serialisiert werden!", event.getClass());
}
return new EventDTO(null, event.getGroupId().toString(), event.getUserId(), getEventType(event), payload);
}
/**
* Gibt den Eventtyp als String wieder.
*
* @param event Event dessen Typ abgefragt werden soll
*
* @return Der Name des Typs des Events
*/
private static String getEventType(Event event) {
int lastDot = event.getClass().getName().lastIndexOf('.');
return event.getClass().getName().substring(lastDot + 1);
}
/**
* Speichert alle Events aus der übergebenen Liste in der DB.
*
* @param events Liste an Events die gespeichert werden soll
*/
@SafeVarargs
public final void saveAll(List<Event>... events) {
for (List<Event> eventlist : events) {
for (Event event : eventlist) {
eventStore.save(getDTOFromEvent(event));
}
}
}
/**
* Findet alle Events welche ab dem neuen Status hinzugekommen sind.
* Sucht alle Events mit event_id > status
*
* @param status Die Id des zuletzt gespeicherten Events
*
* @return Liste von neueren Events
*/
public List<Event> getNewEvents(Long status) {
List<String> groupIdsThatChanged = eventStore.findNewEventSinceStatus(status);
List<EventDTO> groupEventDTOS = eventStore.findAllEventsOfGroups(groupIdsThatChanged);
return getEventsFromDTOs(groupEventDTOS);
}
/**
* Erzeugt aus einer Liste von eventDTOs eine Liste von Events.
*
* @param eventDTOS Liste von DTOs
*
* @return Liste von Events
*/
List<Event> getEventsFromDTOs(Iterable<EventDTO> eventDTOS) {
List<Event> events = new ArrayList<>();
for (EventDTO eventDTO : eventDTOS) {
try {
events.add(JsonService.deserializeEvent(eventDTO.getEvent_payload()));
} catch (JsonProcessingException e) {
LOG.error("Payload\n {}\n konnte nicht deserialisiert werden!", eventDTO.getEvent_payload());
}
}
return events;
}
public long getMaxEventId() {
long highestEvent = 0;
try {
highestEvent = eventStore.getHighesEventID();
} catch (NullPointerException e) {
LOG.debug("Eine maxId von 0 wurde zurückgegeben, da keine Events vorhanden sind.");
}
return highestEvent;
}
/**
* Gibt eine Liste mit allen Events zurück, die zu der Gruppe gehören.
*
* @param groupId Gruppe die betrachtet werden soll
*
* @return Liste aus Events
*/
public List<Event> getEventsOfGroup(UUID groupId) {
List<EventDTO> eventDTOList = eventStore.findEventDTOByGroupId(groupId.toString());
return getEventsFromDTOs(eventDTOList);
}
/**
* Gibt eine Liste aus GruppenIds zurück, in denen sich der User befindet.
*
* @param userId Die Id des Users
*
* @return Liste aus GruppenIds
*/
public List<UUID> findGroupIdsByUser(String userId) {
return eventStore.findGroupIdsWhereUserId(userId, "AddUserEvent").stream().map(UUID::fromString).collect(Collectors.toList());
}
/**
* Gibt true zurück, falls der User aktuell in der Gruppe ist, sonst false.
*
* @param groupId Id der Gruppe
* @param userId Id des zu überprüfenden Users
*
* @return true or false
*/
boolean userInGroup(UUID groupId, String userId) {
return eventStore.countEventsByGroupIdAndUserIdAndEventType(groupId.toString(), userId, "AddUserEvent") > eventStore.countEventsByGroupIdAndUserIdAndEventType(groupId.toString(), userId, "DeleteUserEvent");
}
}

View File

@ -0,0 +1,259 @@
package mops.gruppen2.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.dto.EventDTO;
import mops.gruppen2.domain.event.AddUserEvent;
import mops.gruppen2.domain.event.CreateGroupEvent;
import mops.gruppen2.domain.event.Event;
import mops.gruppen2.domain.exception.BadPayloadException;
import mops.gruppen2.repository.EventRepository;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@Log4j2
public class EventStoreService {
private final EventRepository eventStore;
public EventStoreService(EventRepository eventStore) {
this.eventStore = eventStore;
}
//########################################### SAVE ###########################################
/**
* Erzeugt ein DTO aus einem Event und speicher es.
*
* @param event Event, welches gespeichert wird
*/
public void saveEvent(Event event) {
eventStore.save(getDTOFromEvent(event));
}
public void saveAll(Event... events) {
for (Event event : events) {
eventStore.save(getDTOFromEvent(event));
}
}
/**
* Speichert alle Events aus der übergebenen Liste in der DB.
*
* @param events Liste an Events die gespeichert werden soll
*/
@SafeVarargs
public final void saveAll(List<Event>... events) {
for (List<Event> eventlist : events) {
for (Event event : eventlist) {
eventStore.save(getDTOFromEvent(event));
}
}
}
//########################################### DTOs ###########################################
static List<EventDTO> getDTOsFromEvents(List<Event> events) {
return events.stream()
.map(EventStoreService::getDTOFromEvent)
.collect(Collectors.toList());
}
/**
* Erzeugt aus einem Event Objekt ein EventDTO Objekt.
*
* @param event Event, welches in DTO übersetzt wird
*
* @return EventDTO (Neues DTO)
*/
static EventDTO getDTOFromEvent(Event event) {
try {
String payload = JsonService.serializeEvent(event);
return new EventDTO(null,
event.getGroupId().toString(),
event.getUserId(),
getEventType(event),
payload);
} catch (JsonProcessingException e) {
log.error("Event ({}) konnte nicht serialisiert werden!", event, e);
throw new BadPayloadException(EventStoreService.class.toString());
}
}
/**
* Erzeugt aus einer Liste von eventDTOs eine Liste von Events.
*
* @param eventDTOS Liste von DTOs
*
* @return Liste von Events
*/
private static List<Event> getEventsFromDTOs(List<EventDTO> eventDTOS) {
return eventDTOS.stream()
.map(EventStoreService::getEventFromDTO)
.collect(Collectors.toList());
}
private static Event getEventFromDTO(EventDTO dto) {
try {
return JsonService.deserializeEvent(dto.getEvent_payload());
} catch (JsonProcessingException e) {
log.error("Payload {} konnte nicht deserialisiert werden!", dto.getEvent_payload(), e);
throw new BadPayloadException(EventStoreService.class.toString());
}
}
/**
* Gibt den Eventtyp als String wieder.
*
* @param event Event dessen Typ abgefragt werden soll
*
* @return Der Name des Typs des Events
*/
private static String getEventType(Event event) {
int lastDot = event.getClass().getName().lastIndexOf('.');
return event.getClass().getName().substring(lastDot + 1);
}
// ######################################## QUERIES ##########################################
List<Event> findGroupEvents(UUID groupId) {
return getEventsFromDTOs(eventStore.findEventDTOsByGroup(Collections.singletonList(groupId.toString())));
}
/**
* Sucht alle Events, welche zu einer der übergebenen Gruppen gehören.
*
* @param groupIds Liste an IDs
*
* @return Liste an Events
*/
List<Event> findGroupEvents(List<UUID> groupIds) {
List<EventDTO> eventDTOS = new ArrayList<>();
for (UUID groupId : groupIds) {
eventDTOS.addAll(eventStore.findEventDTOsByGroup(Collections.singletonList(groupId.toString())));
}
return getEventsFromDTOs(eventDTOS);
}
/**
* Findet alle Events zu Gruppen, welche seit dem neuen Status verändert wurden.
*
* @param status Die Id des zuletzt gespeicherten Events
*
* @return Liste von neuen und alten Events
*/
List<Event> findChangedGroupEvents(long status) {
List<String> changedGroupIds = eventStore.findGroupIdsWhereEventIdGreaterThanStatus(status);
List<EventDTO> groupEventDTOS = eventStore.findEventDTOsByGroup(changedGroupIds);
log.debug("Seit Event {} haben sich {} Gruppen geändert!", status, changedGroupIds.size());
return getEventsFromDTOs(groupEventDTOS);
}
/**
* Liefert Gruppen-Ids von existierenden (ungelöschten) Gruppen.
*
* @return GruppenIds (UUID) als Liste
*/
List<UUID> findExistingGroupIds() {
List<Event> createEvents = findLatestEventsFromGroupsByType("CreateGroupEvent",
"DeleteGroupEvent");
return createEvents.stream()
.filter(event -> event instanceof CreateGroupEvent)
.map(Event::getGroupId)
.collect(Collectors.toList());
}
/**
* Liefert Gruppen-Ids von existierenden (ungelöschten) Gruppen, in welchen der User teilnimmt.
*
* @return GruppenIds (UUID) als Liste
*/
public List<UUID> findExistingUserGroups(User user) {
List<Event> userEvents = findLatestEventsFromGroupsByUser(user);
List<UUID> deletedIds = findLatestEventsFromGroupsByType("DeleteGroupEvent")
.stream()
.map(Event::getGroupId)
.collect(Collectors.toList());
userEvents.removeIf(event -> deletedIds.contains(event.getGroupId()));
return userEvents.stream()
.filter(event -> event instanceof AddUserEvent)
.map(Event::getGroupId)
.collect(Collectors.toList());
}
// #################################### SIMPLE QUERIES #######################################
/**
* Ermittelt die Id zuletzt gespeicherten Events.
*
* @return Letzte EventId
*/
public long findMaxEventId() {
try {
return eventStore.findMaxEventId();
} catch (NullPointerException e) {
log.debug("Keine Events vorhanden!");
return 0;
}
}
List<Event> findEventsByType(String... types) {
return getEventsFromDTOs(eventStore.findEventDTOsByType(Arrays.asList(types)));
}
List<Event> findEventsByType(String type) {
return getEventsFromDTOs(eventStore.findEventDTOsByType(Collections.singletonList(type)));
}
List<Event> findEventsByGroupAndType(List<UUID> groupIds, String... types) {
return getEventsFromDTOs(eventStore.findEventDTOsByGroupAndType(Arrays.asList(types),
IdService.uuidsToString(groupIds)));
}
/**
* Sucht zu jeder Gruppe das letzte Add- oder DeleteUserEvent heraus, welches den übergebenen User betrifft.
*
* @param user User, zu welchem die Events gesucht werden
*
* @return Eine Liste von einem Add- oder DeleteUserEvent pro Gruppe
*/
private List<Event> findLatestEventsFromGroupsByUser(User user) {
return getEventsFromDTOs(eventStore.findLatestEventDTOsPartitionedByGroupByUser(user.getId()));
}
/**
* Sucht zu jeder Gruppe das letzte Event des/der übergebenen Typen heraus.
*
* @param types Eventtyp, nach welchem gesucht wird
*
* @return Eine Liste von einem Event pro Gruppe
*/
private List<Event> findLatestEventsFromGroupsByType(String... types) {
return getEventsFromDTOs(eventStore.findLatestEventDTOsPartitionedByGroupByType(Arrays.asList(types)));
}
}

View File

@ -1,170 +1,235 @@
package mops.gruppen2.service; package mops.gruppen2.service;
import mops.gruppen2.domain.Account; import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.GroupType; import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.Role;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.Visibility; import mops.gruppen2.domain.Visibility;
import mops.gruppen2.domain.dto.EventDTO; import mops.gruppen2.domain.event.AddUserEvent;
import mops.gruppen2.domain.event.CreateGroupEvent;
import mops.gruppen2.domain.event.DeleteGroupEvent;
import mops.gruppen2.domain.event.DeleteUserEvent;
import mops.gruppen2.domain.event.Event; import mops.gruppen2.domain.event.Event;
import mops.gruppen2.domain.event.UpdateGroupDescriptionEvent;
import mops.gruppen2.domain.event.UpdateGroupTitleEvent;
import mops.gruppen2.domain.event.UpdateRoleEvent;
import mops.gruppen2.domain.event.UpdateUserLimitEvent;
import mops.gruppen2.domain.exception.EventException; import mops.gruppen2.domain.exception.EventException;
import mops.gruppen2.repository.EventRepository;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/**
* Behandelt Aufgaben, welche sich auf eine Gruppe beziehen.
* Es werden übergebene Gruppen bearbeitet und dementsprechend Events erzeugt und gespeichert.
*/
@Service @Service
@Log4j2
public class GroupService { public class GroupService {
private final EventService eventService; private final EventStoreService eventStoreService;
private final EventRepository eventRepository; private final InviteService inviteService;
public GroupService(EventService eventService, EventRepository eventRepository) { public GroupService(EventStoreService eventStoreService, InviteService inviteService) {
this.eventService = eventService; this.eventStoreService = eventStoreService;
this.eventRepository = eventRepository; this.inviteService = inviteService;
}
// ################################# GRUPPE ERSTELLEN ########################################
/**
* Erzeugt eine neue Gruppe und erzeugt nötige Events für die Initiale Setzung der Attribute.
*
* @param user Keycloak-Account
* @param title Gruppentitel
* @param description Gruppenbeschreibung
*/
public Group createGroup(User user,
String title,
String description,
Visibility visibility,
GroupType groupType,
long userLimit,
UUID parent) {
// Regeln:
// isPrivate -> !isLecture
// isLecture -> !isPrivate
ValidationService.validateFlags(visibility, groupType);
Group group = createGroup(user, parent, groupType, visibility);
// Die Reihenfolge ist wichtig, da der ausführende User Admin sein muss
addUser(user, group);
updateRole(user, group, Role.ADMIN);
updateTitle(user, group, title);
updateDescription(user, group, description);
updateUserLimit(user, group, userLimit);
inviteService.createLink(group);
return group;
}
// ################################### GRUPPEN ÄNDERN ########################################
/**
* Fügt eine Liste von Usern zu einer Gruppe hinzu.
* Duplikate werden übersprungen, die erzeugten Events werden gespeichert.
* Dabei wird das Teilnehmermaximum eventuell angehoben.
*
* @param newUsers Userliste
* @param group Gruppe
* @param user Ausführender User
*/
public void addUsersToGroup(List<User> newUsers, Group group, User user) {
updateUserLimit(user, group, getAdjustedUserLimit(newUsers, group));
newUsers.forEach(newUser -> addUserSilent(newUser, group));
} }
/** /**
* Sucht in der DB alle Zeilen raus welche eine der Gruppen_ids hat. * Ermittelt ein passendes Teilnehmermaximum.
* Wandelt die Zeilen in Events um und gibt davon eine Liste zurück. * Reicht das alte Maximum, wird dieses zurückgegeben.
* Ansonsten wird ein erhöhtes Maximum zurückgegeben.
* *
* @param groupIds Liste an IDs * @param newUsers Neue Teilnehmer
* @param group Bestehende Gruppe, welche verändert wird
* *
* @return Liste an Events * @return Das neue Teilnehmermaximum
*/ */
//TODO: Das vielleicht in den EventRepoService? private static long getAdjustedUserLimit(List<User> newUsers, Group group) {
public List<Event> getGroupEvents(List<UUID> groupIds) { return Math.max((long) group.getMembers().size() + newUsers.size(), group.getUserLimit());
List<EventDTO> eventDTOS = new ArrayList<>(); }
for (UUID groupId : groupIds) {
eventDTOS.addAll(eventRepository.findEventDTOByGroupId(groupId.toString())); /**
* Wechselt die Rolle eines Teilnehmers von Admin zu Member oder andersherum.
*
* @param user Teilnehmer, welcher geändert wird
* @param group Gruppe, in welcher sih der Teilnehmer befindet
*
* @throws EventException Falls der User nicht gefunden wird
*/
public void toggleMemberRole(User user, Group group) throws EventException {
ValidationService.throwIfNoMember(group, user);
ValidationService.throwIfLastAdmin(user, group);
Role role = group.getRoles().get(user.getId());
updateRole(user, group, role.toggle());
}
// ################################# SINGLE EVENTS ###########################################
// Spezifische Events werden erzeugt, validiert, auf die Gruppe angewandt und gespeichert
/**
* Erzeugt eine Gruppe, speichert diese und gibt diese zurück.
*/
private Group createGroup(User user, UUID parent, GroupType groupType, Visibility visibility) {
Event event = new CreateGroupEvent(UUID.randomUUID(),
user.getId(),
parent,
groupType,
visibility);
Group group = new Group();
event.apply(group);
eventStoreService.saveEvent(event);
return group;
}
public void addUser(User user, Group group) {
ValidationService.throwIfMember(group, user);
ValidationService.throwIfGroupFull(group);
Event event = new AddUserEvent(group, user);
event.apply(group);
eventStoreService.saveEvent(event);
}
/**
* Dasselbe wie addUser(), aber exceptions werden abgefangen und nicht geworfen.
*/
private void addUserSilent(User user, Group group) {
try {
addUser(user, group);
} catch (Exception e) {
log.debug("Doppelter User {} wurde nicht zu Gruppe {} hinzugefügt!", user, group);
} }
return eventService.getEventsFromDTOs(eventDTOS);
} }
/** public void deleteUser(User user, Group group) throws EventException {
* Wird verwendet beim Gruppe erstellen bei der Parent-Auswahl: nur Titel benötigt. ValidationService.throwIfNoMember(group, user);
* ValidationService.throwIfLastAdmin(user, group);
* @return List of groups
*/
@Cacheable("groups")
public List<Group> getAllLecturesWithVisibilityPublic() {
List<Event> createEvents = eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("CreateGroupEvent"));
createEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("DeleteGroupEvent")));
createEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("UpdateGroupTitleEvent")));
createEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("DeleteGroupEvent")));
List<Group> visibleGroups = projectEventList(createEvents); if (ValidationService.checkIfGroupEmpty(group)) {
deleteGroup(user, group);
} else {
Event event = new DeleteUserEvent(group, user);
event.apply(group);
return visibleGroups.stream() eventStoreService.saveEvent(event);
.filter(group -> group.getType() == GroupType.LECTURE) }
.filter(group -> group.getVisibility() == Visibility.PUBLIC)
.collect(Collectors.toList());
} }
/** public void deleteGroup(User user, Group group) {
* Erzeugt eine neue Map wo Gruppen aus den Events erzeugt und den Gruppen_ids zugeordnet werden. ValidationService.throwIfNoAdmin(group, user);
* Die Gruppen werden als Liste zurückgegeben.
*
* @param events Liste an Events
*
* @return Liste an Projizierten Gruppen
*
* @throws EventException Projektionsfehler
*/
public List<Group> projectEventList(List<Event> events) throws EventException {
Map<UUID, Group> groupMap = new HashMap<>();
events.parallelStream() Event event = new DeleteGroupEvent(group, user);
.forEachOrdered(event -> event.apply(getOrCreateGroup(groupMap, event.getGroupId()))); event.apply(group);
inviteService.destroyLink(group);
return new ArrayList<>(groupMap.values()); eventStoreService.saveEvent(event);
} }
/** public void updateTitle(User user, Group group, String title) {
* Gibt die Gruppe mit der richtigen Id aus der übergebenen Map wieder, existiert diese nicht ValidationService.throwIfNoAdmin(group, user);
* wird die Gruppe erstellt und der Map hizugefügt. ValidationService.validateTitle(title);
*
* @param groups Map aus GruppenIds und Gruppen Event event = new UpdateGroupTitleEvent(group, user, title);
* @param groupId Die Id der Gruppe, die zurückgegeben werden soll event.apply(group);
*
* @return Die gesuchte Gruppe eventStoreService.saveEvent(event);
*/ }
private static Group getOrCreateGroup(Map<UUID, Group> groups, UUID groupId) {
if (!groups.containsKey(groupId)) { public void updateDescription(User user, Group group, String description) {
groups.put(groupId, new Group()); ValidationService.throwIfNoAdmin(group, user);
ValidationService.validateDescription(description);
Event event = new UpdateGroupDescriptionEvent(group, user, description);
event.apply(group);
eventStoreService.saveEvent(event);
}
private void updateRole(User user, Group group, Role role) {
ValidationService.throwIfNoMember(group, user);
Event event = new UpdateRoleEvent(group, user, role);
event.apply(group);
eventStoreService.saveEvent(event);
}
public void updateUserLimit(User user, Group group, long userLimit) {
ValidationService.throwIfNoAdmin(group, user);
ValidationService.validateUserLimit(userLimit, group);
if (userLimit == group.getUserLimit()) {
return;
} }
return groups.get(groupId); Event event = new UpdateUserLimitEvent(group, user, userLimit);
} event.apply(group);
/** eventStoreService.saveEvent(event);
* Filtert alle öffentliche Gruppen nach dem Suchbegriff und gibt diese als Liste von Gruppen zurück.
* Groß und Kleinschreibung wird nicht beachtet.
*
* @param search Der Suchstring
*
* @return Liste von projizierten Gruppen
*
* @throws EventException Projektionsfehler
*/
//Todo Rename
@Cacheable("groups")
public List<Group> findGroupWith(String search, Account account) throws EventException {
if (search.isEmpty()) {
return getAllGroupWithVisibilityPublic(account.getName());
}
return getAllGroupWithVisibilityPublic(account.getName()).parallelStream().filter(group -> group.getTitle().toLowerCase().contains(search.toLowerCase()) || group.getDescription().toLowerCase().contains(search.toLowerCase())).collect(Collectors.toList());
}
/**
* Wird verwendet bei der Suche nach Gruppen: Titel, Beschreibung werden benötigt.
* Außerdem wird beachtet, ob der eingeloggte User bereits in entsprechenden Gruppen mitglied ist.
*
* @return Liste von projizierten Gruppen
*
* @throws EventException Projektionsfehler
*/
//TODO Rename
@Cacheable("groups")
public List<Group> getAllGroupWithVisibilityPublic(String userId) throws EventException {
List<Event> groupEvents = eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("CreateGroupEvent"));
groupEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("UpdateGroupDescriptionEvent")));
groupEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("UpdateGroupTitleEvent")));
groupEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("DeleteGroupEvent")));
groupEvents.addAll(eventService.getEventsFromDTOs(eventRepository.findAllEventsByType("UpdateUserMaxEvent")));
List<Group> visibleGroups = projectEventList(groupEvents);
sortByGroupType(visibleGroups);
return visibleGroups.stream()
.filter(group -> group.getType() != null)
.filter(group -> !eventService.userInGroup(group.getId(), userId))
.filter(group -> group.getVisibility() == Visibility.PUBLIC)
.collect(Collectors.toList());
}
/**
* Sortiert die übergebene Liste an Gruppen, sodass Veranstaltungen am Anfang der Liste sind.
*
* @param groups Die Liste von Gruppen die sortiert werden soll
*/
void sortByGroupType(List<Group> groups) {
groups.sort((Group g1, Group g2) -> {
if (g1.getType() == GroupType.LECTURE) {
return -1;
}
if (g2.getType() == GroupType.LECTURE) {
return 0;
}
return 1;
});
} }
} }

View File

@ -0,0 +1,51 @@
package mops.gruppen2.service;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@Log4j2
public final class IdService {
private IdService() {}
public static List<UUID> stringsToUUID(List<String> groupIds) {
return groupIds.stream()
.map(IdService::stringToUUID)
.collect(Collectors.toList());
}
/**
* Wandelt einen String in eine UUID um.
* Dabei wird eine "leere" UUID generiert, falls der String leer ist.
*
* @param groupId Id als String
*
* @return Id als UUID
*/
public static UUID stringToUUID(String groupId) {
return groupId.isEmpty() ? emptyUUID() : UUID.fromString(groupId);
}
public static List<String> uuidsToString(List<UUID> groupIds) {
return groupIds.stream()
.map(UUID::toString)
.collect(Collectors.toList());
}
public static String uuidToString(UUID groupId) {
return groupId.toString();
}
public static boolean isEmpty(UUID id) {
return id == null || emptyUUID().equals(id);
}
public static UUID emptyUUID() {
return UUID.fromString("00000000-0000-0000-0000-000000000000");
}
}

View File

@ -1,50 +1,54 @@
package mops.gruppen2.service; package mops.gruppen2.service;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.dto.InviteLinkDTO; import mops.gruppen2.domain.dto.InviteLinkDTO;
import mops.gruppen2.domain.exception.InvalidInviteException; import mops.gruppen2.domain.exception.InvalidInviteException;
import mops.gruppen2.domain.exception.NoInviteExistException; import mops.gruppen2.domain.exception.NoInviteExistException;
import mops.gruppen2.repository.InviteRepository; import mops.gruppen2.repository.InviteRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.UUID; import java.util.UUID;
@Service @Service
@Log4j2
public class InviteService { public class InviteService {
private static final Logger LOG = LoggerFactory.getLogger(InviteService.class);
private final InviteRepository inviteRepository; private final InviteRepository inviteRepository;
public InviteService(InviteRepository inviteRepository) { public InviteService(InviteRepository inviteRepository) {
this.inviteRepository = inviteRepository; this.inviteRepository = inviteRepository;
} }
void createLink(UUID groupId) { void createLink(Group group) {
inviteRepository.save(new InviteLinkDTO(null, groupId.toString(), UUID.randomUUID().toString())); inviteRepository.save(new InviteLinkDTO(null,
group.getId().toString(),
UUID.randomUUID().toString()));
log.debug("Link wurde erzeugt! (Gruppe: {})", group.getId());
} }
void destroyLink(UUID groupId) { void destroyLink(Group group) {
inviteRepository.deleteLinkOfGroup(groupId.toString()); inviteRepository.deleteLinkOfGroup(group.getId().toString());
log.debug("Link wurde zerstört! (Gruppe: {})", group.getId());
} }
public UUID getGroupIdFromLink(String link) { public UUID getGroupIdFromLink(String link) {
try { try {
return UUID.fromString(inviteRepository.findGroupIdByLink(link)); return UUID.fromString(inviteRepository.findGroupIdByLink(link));
} catch (Exception e) { } catch (Exception e) {
LOG.error("Gruppe zu Link ({}) konnte nicht gefunden werden!", link); log.error("Gruppe zu Link ({}) konnte nicht gefunden werden!", link, e);
throw new InvalidInviteException(link);
} }
throw new InvalidInviteException(link);
} }
public String getLinkByGroupId(UUID groupId) { public String getLinkByGroup(Group group) {
try { try {
return inviteRepository.findLinkByGroupId(groupId.toString()); return inviteRepository.findLinkByGroupId(group.getId().toString());
} catch (Exception e) { } catch (Exception e) {
LOG.error("Link zu Gruppe ({}) konnte nicht gefunden werden!", groupId); log.error("Link zu Gruppe ({}) konnte nicht gefunden werden!", group.getId(), e);
throw new NoInviteExistException(group.getId().toString());
} }
throw new NoInviteExistException(groupId.toString());
} }
} }

View File

@ -2,6 +2,7 @@ package mops.gruppen2.service;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.event.Event; import mops.gruppen2.domain.event.Event;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -9,12 +10,13 @@ import org.springframework.stereotype.Service;
* Übersetzt JSON-Event-Payloads zu Java-Event-Repräsentationen und zurück. * Übersetzt JSON-Event-Payloads zu Java-Event-Repräsentationen und zurück.
*/ */
@Service @Service
@Log4j2
public final class JsonService { public final class JsonService {
private JsonService() {} private JsonService() {}
/** /**
* Übersetzt mithilfe der Jackson-Library eine Java-Event-Repräsentation zu einem JSON-Event-Payload. * Übersetzt eine Java-Event-Repräsentation zu einem JSON-Event-Payload.
* *
* @param event Java-Event-Repräsentation * @param event Java-Event-Repräsentation
* *
@ -29,7 +31,7 @@ public final class JsonService {
} }
/** /**
* Übersetzt mithilfe der Jackson-Library einen JSON-Event-Payload zu einer Java-Event-Repräsentation. * Übersetzt eine JSON-Event-Payload zu einer Java-Event-Repräsentation.
* *
* @param json JSON-Event-Payload als String * @param json JSON-Event-Payload als String
* *

View File

@ -1,30 +0,0 @@
package mops.gruppen2.service;
import mops.gruppen2.domain.Account;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.stereotype.Service;
@Service
public final class KeyCloakService {
private KeyCloakService() {}
/**
* Creates an Account.
*
* @param token Ein toller token
*
* @return Account with current userdata
*/
public static Account createAccountFromPrincipal(KeycloakAuthenticationToken token) {
KeycloakPrincipal principal = (KeycloakPrincipal) token.getPrincipal();
return new Account(
principal.getName(),
principal.getKeycloakSecurityContext().getIdToken().getEmail(),
null,
principal.getKeycloakSecurityContext().getIdToken().getGivenName(),
principal.getKeycloakSecurityContext().getIdToken().getFamilyName(),
token.getAccount().getRoles());
}
}

View File

@ -0,0 +1,225 @@
package mops.gruppen2.service;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.Visibility;
import mops.gruppen2.domain.event.Event;
import mops.gruppen2.domain.exception.EventException;
import mops.gruppen2.domain.exception.GroupNotFoundException;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Liefert verschiedene Projektionen auf Gruppen.
* Benötigt ausschließlich den EventStoreService.
*/
@Service
@Log4j2
public class ProjectionService {
private final EventStoreService eventStoreService;
public ProjectionService(EventStoreService eventStoreService) {
this.eventStoreService = eventStoreService;
}
// ################################## STATISCHE PROJEKTIONEN #################################
/**
* Konstruiert Gruppen aus einer Liste von Events.
*
* @param events Liste an Events
*
* @return Liste an Projizierten Gruppen
*
* @throws EventException Projektionsfehler
*/
static List<Group> projectGroups(List<Event> events) throws EventException {
Map<UUID, Group> groupMap = new HashMap<>();
events.forEach(event -> event.apply(getOrCreateGroup(groupMap, event.getGroupId())));
return new ArrayList<>(groupMap.values());
}
/**
* Projiziert Events, geht aber davon aus, dass alle zu derselben Gruppe gehören.
*
* @param events Eventliste
*
* @return Eine projizierte Gruppe
*
* @throws EventException Projektionsfehler, z.B. falls Events von verschiedenen Gruppen übergeben werden
*/
static Group projectSingleGroup(List<Event> events) throws EventException {
if (events.isEmpty()) {
throw new GroupNotFoundException(ProjectionService.class.toString());
}
Group group = new Group();
events.forEach(event -> event.apply(group));
return group;
}
/**
* Gibt die Gruppe mit der richtigen Id aus der übergebenen Map wieder, existiert diese nicht
* wird die Gruppe erstellt und der Map hizugefügt.
*
* @param groups Map aus GruppenIds und Gruppen
* @param groupId Die Id der Gruppe, die zurückgegeben werden soll
*
* @return Die gesuchte Gruppe
*/
private static Group getOrCreateGroup(Map<UUID, Group> groups, UUID groupId) {
if (!groups.containsKey(groupId)) {
groups.put(groupId, new Group());
}
return groups.get(groupId);
}
// ############################### PROJEKTIONEN MIT DATENBANK ################################
/**
* Projiziert Gruppen, welche sich seit einer übergebenen eventId geändert haben.
* Die Gruppen werden dabei vollständig konstruiert.
*
* @param status Letzte bekannte eventId
*
* @return Liste an Gruppen
*/
public List<Group> projectNewGroups(long status) {
List<Event> events = eventStoreService.findChangedGroupEvents(status);
return projectGroups(events);
}
/**
* Projiziert öffentliche Gruppen.
* Die Gruppen enthalten Metainformationen: Titel, Beschreibung und MaxUserAnzahl.
* Außerdem wird noch beachtet, ob der eingeloggte User bereits in entsprechenden Gruppen mitglied ist.
*
* @return Liste von projizierten Gruppen
*
* @throws EventException Projektionsfehler
*/
@Cacheable("groups")
//TODO: remove userID param
public List<Group> projectPublicGroups() throws EventException {
List<UUID> groupIds = eventStoreService.findExistingGroupIds();
List<Event> events = eventStoreService.findEventsByGroupAndType(groupIds,
"CreateGroupEvent",
"UpdateGroupDescriptionEvent",
"UpdateGroupTitleEvent",
"UpdateUserMaxEvent");
List<Group> groups = projectGroups(events);
return groups.stream()
.filter(group -> group.getVisibility() == Visibility.PUBLIC)
.collect(Collectors.toList());
}
/**
* Projiziert Vorlesungen.
* Projektionen enthalten nur Metainformationen: Titel.
*
* @return Liste von Veranstaltungen
*/
@Cacheable("groups")
public List<Group> projectLectures() {
List<UUID> groupIds = eventStoreService.findExistingGroupIds();
List<Event> events = eventStoreService.findEventsByGroupAndType(groupIds,
"CreateGroupEvent",
"UpdateGroupTitleEvent");
List<Group> lectures = projectGroups(events);
return lectures.stream()
.filter(group -> group.getType() == GroupType.LECTURE)
.collect(Collectors.toList());
}
/**
* Projiziert Gruppen, in welchen der User aktuell teilnimmt.
* Die Gruppen enthalten nur Metainformationen: Titel und Beschreibung.
*
* @param user Die Id
*
* @return Liste aus Gruppen
*/
@Cacheable("groups")
public List<Group> projectUserGroups(User user) {
List<UUID> groupIds = eventStoreService.findExistingUserGroups(user);
List<Event> groupEvents = eventStoreService.findEventsByGroupAndType(groupIds,
"CreateGroupEvent",
"UpdateGroupTitleEvent",
"UpdateGroupDescriptionEvent");
return projectGroups(groupEvents);
}
/**
* Gibt die Gruppe zurück, die zu der übergebenen Id passt.
* Enthält alle verfügbaren Informationen, also auch User (langsam).
* Gibt eine leere Gruppe zurück, falls die Id leer ist.
*
* @param groupId Die Id der gesuchten Gruppe
*
* @return Die gesuchte Gruppe
*
* @throws GroupNotFoundException Wenn die Gruppe nicht gefunden wird
*/
public Group projectSingleGroup(UUID groupId) throws GroupNotFoundException {
if (IdService.isEmpty(groupId)) {
throw new GroupNotFoundException(groupId + ": " + ProjectionService.class);
}
try {
List<Event> events = eventStoreService.findGroupEvents(groupId);
return projectSingleGroup(events);
} catch (Exception e) {
log.error("Gruppe {} wurde nicht gefunden!", groupId.toString(), e);
throw new GroupNotFoundException(groupId + ": " + ProjectionService.class);
}
}
/**
* Projiziert eine einzelne Gruppe, welche leer sein darf.
*/
public Group projectParent(UUID parentId) {
if (IdService.isEmpty(parentId)) {
return new Group();
}
return projectSingleGroup(parentId);
}
/**
* Entfernt alle Gruppen, in welchen ein User teilnimmt, aus einer Gruppenliste.
*
* @param groups Gruppenliste, aus der entfernt wird
* @param user User, welcher teilnimmt
*/
void removeUserGroups(List<Group> groups, User user) {
List<UUID> userGroups = eventStoreService.findExistingUserGroups(user);
groups.removeIf(group -> userGroups.contains(group.getId()));
}
}

View File

@ -1,6 +1,69 @@
package mops.gruppen2.service; package mops.gruppen2.service;
import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.exception.EventException;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service @Service
public class SearchService {} @Log4j2
public class SearchService {
private final ProjectionService projectionService;
public SearchService(ProjectionService projectionService) {
this.projectionService = projectionService;
}
/**
* Filtert alle öffentliche Gruppen nach dem Suchbegriff und gibt diese als sortierte Liste zurück.
* Groß- und Kleinschreibung wird nicht beachtet.
* Der Suchbegriff wird im Gruppentitel und in der Beschreibung gesucht.
*
* @param search Der Suchstring
*
* @return Liste von projizierten Gruppen
*
* @throws EventException Projektionsfehler
*/
@Cacheable("groups")
public List<Group> searchPublicGroups(String search, User user) throws EventException {
List<Group> groups = projectionService.projectPublicGroups();
projectionService.removeUserGroups(groups, user);
sortByGroupType(groups);
if (search.isEmpty()) {
return groups;
}
log.debug("Es wurde gesucht nach: {}", search);
return groups.stream()
.filter(group -> group.toString().toLowerCase().contains(search.toLowerCase()))
.collect(Collectors.toList());
}
/**
* Sortiert die übergebene Liste an Gruppen, sodass Veranstaltungen am Anfang der Liste sind.
*
* @param groups Die Liste von Gruppen die sortiert werden soll
*/
private static void sortByGroupType(List<Group> groups) {
groups.sort((Group g1, Group g2) -> {
if (g1.getType() == GroupType.LECTURE) {
return -1;
}
if (g2.getType() == GroupType.LECTURE) {
return 0;
}
return 1;
});
}
}

View File

@ -1,76 +0,0 @@
package mops.gruppen2.service;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.event.Event;
import mops.gruppen2.domain.exception.EventException;
import mops.gruppen2.domain.exception.GroupNotFoundException;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Service
public class UserService {
private final GroupService groupService;
private final EventService eventService;
public UserService(GroupService groupService, EventService eventService) {
this.groupService = groupService;
this.eventService = eventService;
}
@Cacheable("groups")
public List<Group> getUserGroups(String userId) throws EventException {
return getUserGroups(new User(userId, "", "", ""));
}
/**
* Gibt eine Liste aus Gruppen zurück, in denen sich der übergebene User befindet.
*
* @param user Der User
*
* @return Liste aus Gruppen
*/
//TODO: Nur AddUserEvents + DeleteUserEvents betrachten
@Cacheable("groups")
public List<Group> getUserGroups(User user) {
List<UUID> groupIds = eventService.findGroupIdsByUser(user.getId());
List<Event> events = groupService.getGroupEvents(groupIds);
List<Group> groups = groupService.projectEventList(events);
List<Group> newGroups = new ArrayList<>();
for (Group group : groups) {
if (group.getMembers().contains(user)) {
newGroups.add(group);
}
}
groupService.sortByGroupType(newGroups);
return newGroups;
}
/**
* Gibt die Gruppe zurück, die zu der übergebenen Id passt.
*
* @param groupId Die Id der gesuchten Gruppe
*
* @return Die gesuchte Gruppe
*
* @throws EventException Wenn die Gruppe nicht gefunden wird
*/
public Group getGroupById(UUID groupId) throws EventException {
List<UUID> groupIds = new ArrayList<>();
groupIds.add(groupId);
try {
List<Event> events = groupService.getGroupEvents(groupIds);
return groupService.projectEventList(events).get(0);
} catch (IndexOutOfBoundsException e) {
throw new GroupNotFoundException("@UserService");
}
}
}

View File

@ -1,157 +1,156 @@
package mops.gruppen2.service; package mops.gruppen2.service;
import mops.gruppen2.domain.Account; import lombok.extern.log4j.Log4j2;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.Role; import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.User; import mops.gruppen2.domain.User;
import mops.gruppen2.domain.Visibility; import mops.gruppen2.domain.Visibility;
import mops.gruppen2.domain.exception.BadParameterException; import mops.gruppen2.domain.exception.BadParameterException;
import mops.gruppen2.domain.exception.GroupFullException; import mops.gruppen2.domain.exception.GroupFullException;
import mops.gruppen2.domain.exception.GroupNotFoundException;
import mops.gruppen2.domain.exception.NoAccessException; import mops.gruppen2.domain.exception.NoAccessException;
import mops.gruppen2.domain.exception.NoAdminAfterActionException; import mops.gruppen2.domain.exception.NoAdminAfterActionException;
import mops.gruppen2.domain.exception.UserAlreadyExistsException; import mops.gruppen2.domain.exception.UserAlreadyExistsException;
import mops.gruppen2.domain.exception.UserNotFoundException; import mops.gruppen2.domain.exception.UserNotFoundException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static mops.gruppen2.domain.Role.ADMIN; import static mops.gruppen2.domain.Role.ADMIN;
@Service @Service
public class ValidationService { @Log4j2
public final class ValidationService {
private final UserService userService; private ValidationService() {}
private final GroupService groupService;
public ValidationService(UserService userService, GroupService groupService) {
this.userService = userService;
this.groupService = groupService;
}
//TODO: make static or change return + assignment // ######################################## CHECK ############################################
public List<Group> checkSearch(String search, List<Group> groups, Account account) {
if (search != null) {
groups = groupService.findGroupWith(search, account);
}
return groups;
}
public void throwIfGroupNotExisting(String title) {
if (title == null) {
throw new GroupNotFoundException("@details");
}
}
public void throwIfUserAlreadyInGroup(Group group, User user) { /**
if (checkIfUserInGroup(group, user)) { * Überprüft, ob ein User in einer Gruppe teilnimmt.
throw new UserAlreadyExistsException("@details"); */
} public static boolean checkIfMember(Group group, User user) {
}
void throwIfNotInGroup(Group group, User user) {
if (!checkIfUserInGroup(group, user)) {
throw new UserNotFoundException(getClass().toString());
}
}
public boolean checkIfUserInGroup(Group group, User user) {
return group.getMembers().contains(user); return group.getMembers().contains(user);
} }
public void throwIfGroupFull(Group group) { public static boolean checkIfLastMember(User user, Group group) {
if (group.getUserMaximum() < group.getMembers().size() + 1) { return checkIfMember(group, user) && group.getMembers().size() == 1;
throw new GroupFullException("Du kannst der Gruppe daher leider nicht beitreten.");
}
} }
boolean checkIfGroupEmpty(UUID groupId) { /**
return userService.getGroupById(groupId).getMembers().isEmpty(); * Überprüft, ob eine Gruppe voll ist.
*/
public static boolean checkIfGroupFull(Group group) {
return group.getMembers().size() >= group.getUserLimit();
} }
public void throwIfNoAdmin(Group group, User user) { /**
throwIfNoAccessToPrivate(group, user); * Überprüft, ob eine Gruppe leer ist.
if (group.getRoles().get(user.getId()) != ADMIN) { */
throw new NoAccessException(""); public static boolean checkIfGroupEmpty(Group group) {
} return group.getMembers().isEmpty();
} }
public void throwIfNoAccessToPrivate(Group group, User user) { /**
if (!checkIfUserInGroup(group, user) && group.getVisibility() == Visibility.PRIVATE) { * Überprüft, ob ein User in einer Gruppe Admin ist.
throw new NoAccessException(""); */
} public static boolean checkIfAdmin(Group group, User user) {
} if (checkIfMember(group, user)) {
public boolean checkIfAdmin(Group group, User user) {
if (checkIfUserInGroup(group, user)) {
return group.getRoles().get(user.getId()) == ADMIN; return group.getRoles().get(user.getId()) == ADMIN;
} }
return false; return false;
} }
void throwIfLastAdmin(Account account, Group group) { public static boolean checkIfLastAdmin(User user, Group group) {
if (checkIfLastAdmin(account, group)) { return checkIfAdmin(group, user) && group.getRoles().values().stream()
.filter(role -> role == ADMIN)
.count() == 1;
}
public static boolean checkIfGroupAccess(Group group, User user) {
return (group.getVisibility() == Visibility.PRIVATE && checkIfMember(group, user))
|| group.getVisibility() == Visibility.PUBLIC;
}
// ######################################## THROW ############################################
public static void throwIfMember(Group group, User user) {
if (checkIfMember(group, user)) {
log.error("Benutzer {} ist schon in Gruppe {}", user, group);
throw new UserAlreadyExistsException(user.toString());
}
}
public static void throwIfNoMember(Group group, User user) {
if (!checkIfMember(group, user)) {
log.error("Benutzer {} ist nicht in Gruppe {}!", user, group);
throw new UserNotFoundException(user.toString());
}
}
public static void throwIfNoAdmin(Group group, User user) {
if (!checkIfAdmin(group, user)) {
log.error("User {} ist kein Admin in Gruppe {}!", user, group);
throw new NoAccessException(group.toString());
}
}
/**
* Schmeißt keine Exception, wenn der User der letzte User ist.
*/
public static void throwIfLastAdmin(User user, Group group) {
if (!checkIfLastMember(user, group) && checkIfLastAdmin(user, group)) {
throw new NoAdminAfterActionException("Du bist letzter Admin!"); throw new NoAdminAfterActionException("Du bist letzter Admin!");
} }
} }
boolean checkIfLastAdmin(Account account, Group group) { public static void throwIfGroupFull(Group group) {
for (Map.Entry<String, Role> entry : group.getRoles().entrySet()) { if (checkIfGroupFull(group)) {
if (entry.getValue() == ADMIN && !(entry.getKey().equals(account.getName()))) { log.error("Die Gruppe {} ist voll!", group);
return false; throw new GroupFullException(group.toString());
}
} }
return true;
} }
/** public static void throwIfNoGroupAccess(Group group, User user) {
* Überprüft ob alle Felder richtig gesetzt sind. if (!checkIfGroupAccess(group, user)) {
* log.error("Der User {} hat keinen Zugriff auf Gruppe {}!", user, group);
* @param description Die Beschreibung der Gruppe throw new NoAccessException(group.toString());
* @param title Der Titel der Gruppe
* @param userMaximum Das user Limit der Gruppe
*/
public void checkFields(String title, String description, Long userMaximum, Boolean maxInfiniteUsers) {
if (description == null || description.trim().isEmpty()) {
throw new BadParameterException("Die Beschreibung wurde nicht korrekt angegeben");
} }
}
// ##################################### VALIDATE FIELDS #####################################
//TODO: max title length?
public static void validateTitle(String title) {
if (title == null || title.trim().isEmpty()) { if (title == null || title.trim().isEmpty()) {
throw new BadParameterException("Der Titel wurde nicht korrekt angegeben"); log.error("Der Titel {} ist fehlerhaft!", title);
} throw new BadParameterException("Der Titel darf nicht leer sein!");
if (userMaximum == null && maxInfiniteUsers == null) {
throw new BadParameterException("Teilnehmeranzahl wurde nicht korrekt angegeben");
}
if (userMaximum != null && (userMaximum < 1 || userMaximum > 10000L)) {
throw new BadParameterException("Teilnehmeranzahl wurde nicht korrekt angegeben");
} }
} }
public void checkFields(String title, String description) { //TODO: max description length?
public static void validateDescription(String description) {
if (description == null || description.trim().isEmpty()) { if (description == null || description.trim().isEmpty()) {
throw new BadParameterException("Die Beschreibung wurde nicht korrekt angegeben"); log.error("Die Beschreibung {} ist fehlerhaft!", description);
} throw new BadParameterException("Die Beschreibung darf nicht leer sein!");
if (title == null || title.trim().isEmpty()) {
throw new BadParameterException("Der Titel wurde nicht korrekt angegeben");
} }
} }
public void throwIfNewMaximumIsValid(Long newUserMaximum, Group group) { public static void validateFlags(Visibility visibility, GroupType groupType) {
if (newUserMaximum == null) { if (visibility == Visibility.PRIVATE && groupType == GroupType.LECTURE) {
throw new BadParameterException("Es wurde keine neue maximale Teilnehmeranzahl angegeben!"); throw new BadParameterException("Eine Veranstaltung kann nicht privat sein!");
}
}
public static void validateUserLimit(long userLimit, Group group) {
if (userLimit < 1) {
throw new BadParameterException("Das Userlimit muss größer als 1 sein!");
} }
if (newUserMaximum < 1 || newUserMaximum > 10000L) { if (userLimit < group.getMembers().size()) {
throw new BadParameterException("Die neue maximale Teilnehmeranzahl wurde nicht korrekt angegeben!"); throw new BadParameterException("Das Userlimit kann nicht unter der momentanen Mitgliederanzahl sein!");
}
if (group.getMembers().size() > newUserMaximum) {
throw new BadParameterException("Die neue maximale Teilnehmeranzahl ist kleiner als die aktuelle Teilnehmeranzahl!");
} }
} }
} }

View File

@ -1,23 +1,33 @@
application.name=gruppen2 # Logging
logging.pattern.console=[${application.name}],%magenta(%-5level), %d{dd-MM-yyyy HH:mm:ss.SSS}, %highlight(%msg),%thread,%logger.%M%n logging.application.name = gruppen2
spring.datasource.platform=h2 logging.pattern.console = [${logging.application.name}], %magenta(%-5level), %d{dd-MM-yyyy HH:mm:ss.SSS},\t%blue(%msg)\n\t\t\t\t\t\t\t\t\t\t\t%thread,%logger.%M%n
spring.datasource.url=jdbc:h2:mem:blogdb spring.output.ansi.enabled = always
spring.datasource.driver-class-name=org.h2.Driver logging.level.mops.gruppen2 = trace
spring.datasource.username=sa logging.level.org.springframework.jdbc.core = info
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect # Database
spring.h2.console.enabled=false spring.datasource.platform = h2
logging.level.org.springframework.jdbc.core=INFO spring.datasource.driver-class-name = org.h2.Driver
keycloak.principal-attribute=preferred_username spring.datasource.initialization-mode = always
keycloak.auth-server-url=https://keycloak.cs.hhu.de/auth spring.datasource.url = jdbc:h2:mem:blogdb
keycloak.realm=MOPS spring.datasource.username = sa
hhu_keycloak.token-uri=https://keycloak.cs.hhu.de/auth/realms/MOPS/protocol/openid-connect/token spring.datasource.password =
keycloak.resource=gruppenfindung spring.jpa.database-platform = org.hibernate.dialect.H2Dialect
keycloak.credentials.secret=fc6ebf10-8c63-4e71-a667-4eae4e8209a1 spring.h2.console.enabled = false
keycloak.verify-token-audience=true
keycloak.use-resource-role-mappings=true # Security
keycloak.autodetect-bearer-only=true keycloak.principal-attribute = preferred_username
keycloak.confidential-port=443 keycloak.auth-server-url = https://keycloak.cs.hhu.de/auth
server.error.include-stacktrace=always keycloak.realm = MOPS
management.endpoints.web.exposure.include=info,health hhu_keycloak.token-uri = https://keycloak.cs.hhu.de/auth/realms/MOPS/protocol/openid-connect/token
spring.cache.type=NONE keycloak.resource = gruppenfindung
keycloak.credentials.secret = fc6ebf10-8c63-4e71-a667-4eae4e8209a1
keycloak.verify-token-audience = true
keycloak.use-resource-role-mappings = true
keycloak.autodetect-bearer-only = true
keycloak.confidential-port = 443
# Misc
server.error.include-stacktrace = always
management.endpoints.web.exposure.include = info,health
spring.cache.type = none

View File

@ -1,19 +1,30 @@
application.name=gruppen2 # Logging
logging.pattern.console=[${application.name}],%magenta(%-5level), %d{dd-MM-yyyy HH:mm:ss.SSS}, %highlight(%msg),%thread,%logger.%M%n logging.application.name = gruppen2
spring.datasource.platform=mysql logging.pattern.console = [${logging.application.name}],%magenta(%-5level), %d{dd-MM-yyyy HH:mm:ss.SSS}, %highlight(%msg),%thread,%logger.%M%n
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.output.ansi.enabled = always
spring.datasource.initialization-mode=NEVER logging.level.mops.gruppen2 = info
spring.datasource.url=jdbc:mysql://dbmysql:3306/gruppen2 logging.level.org.springframework.jdbc.core = info
spring.datasource.username=root
spring.datasource.password=geheim # Database
keycloak.principal-attribute=preferred_username spring.datasource.platform = mysql
keycloak.auth-server-url=https://keycloak.cs.hhu.de/auth spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
keycloak.realm=MOPS spring.datasource.initialization-mode = never
hhu_keycloak.token-uri=https://keycloak.cs.hhu.de/auth/realms/MOPS/protocol/openid-connect/token spring.datasource.url = jdbc:mysql://dbmysql:3306/gruppen2
keycloak.resource=gruppenfindung spring.datasource.username = root
keycloak.credentials.secret=fc6ebf10-8c63-4e71-a667-4eae4e8209a1 spring.datasource.password = geheim
keycloak.verify-token-audience=true
keycloak.use-resource-role-mappings=true # Security
keycloak.autodetect-bearer-only=true keycloak.principal-attribute = preferred_username
keycloak.confidential-port=443 keycloak.auth-server-url = https://keycloak.cs.hhu.de/auth
management.endpoints.web.exposure.include=info,health keycloak.realm = MOPS
hhu_keycloak.token-uri = https://keycloak.cs.hhu.de/auth/realms/MOPS/protocol/openid-connect/token
keycloak.resource = gruppenfindung
keycloak.credentials.secret = fc6ebf10-8c63-4e71-a667-4eae4e8209a1
keycloak.verify-token-audience = true
keycloak.use-resource-role-mappings = true
keycloak.autodetect-bearer-only = true
keycloak.confidential-port = 443
# Misc
management.endpoints.web.exposure.include = info,health
server.error.include-stacktrace = always

View File

@ -1,2 +1,2 @@
spring.profiles.active=dev spring.profiles.active = dev

View File

@ -30,7 +30,7 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li> <li>
<a href="/findGroup" th:href="@{/gruppen2/findGroup}">Suche</a> <a href="/searchPage" th:href="@{/gruppen2/searchPage}">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
@ -42,7 +42,7 @@
<h1>Metadaten ändern</h1> <h1>Metadaten ändern</h1>
<form method="post" th:action="@{/gruppen2/details/changeMetadata}"> <form method="post" th:action="@{/gruppen2/details/changeMetadata}">
<div class="shadow-sm p-2" <div class="shadow-sm p-2"
style=" border: 10px solid aliceblue; background: aliceblue"> style=" border: 10px solid aliceblue; background: aliceblue;">
<div class="form-group"> <div class="form-group">
<label for="title">Titel</label> <label for="title">Titel</label>
<input class="form-control" id="title" required <input class="form-control" id="title" required
@ -56,7 +56,7 @@
</div> </div>
<div class="form-group pt-4"> <div class="form-group pt-4">
<button class="btn btn-primary" <button class="btn btn-primary"
style="background: #52a1eb; border-style: none" style="background: #52a1eb; border-style: none;"
th:if="${roles.get(user.getId()) == admin}" th:if="${roles.get(user.getId()) == admin}"
th:name="groupId" th:name="groupId"
th:value="${groupId}" th:value="${groupId}"

View File

@ -2,6 +2,7 @@
<html lang="en" xmlns:th="http://www.thymeleaf.org" <html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="~{mopslayout :: html(name='Gruppenbildung', headcontent=~{:: headcontent}, navigation=~{:: navigation}, bodycontent=~{:: bodycontent})}" th:replace="~{mopslayout :: html(name='Gruppenbildung', headcontent=~{:: headcontent}, navigation=~{:: navigation}, bodycontent=~{:: bodycontent})}"
xmlns="http://www.w3.org/1999/html"> xmlns="http://www.w3.org/1999/html">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Gruppenerstellung</title> <title>Gruppenerstellung</title>
@ -14,7 +15,9 @@
<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>
</th:block> </th:block>
</head> </head>
<body> <body>
<header> <header>
<nav class="navigation navigation-secondary" is="mops-navigation" th:fragment="navigation" th:switch="${account.getRoles().contains('orga')}"> <nav class="navigation navigation-secondary" is="mops-navigation" th:fragment="navigation" th:switch="${account.getRoles().contains('orga')}">
<ul> <ul>
@ -28,77 +31,72 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li> <li>
<a th:href="@{/gruppen2/findGroup}" href="/findGroup">Suche</a> <a th:href="@{/gruppen2/searchPage}" href="/searchPage">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
</header> </header>
<main th:fragment="bodycontent"> <main th:fragment="bodycontent">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-10"> <div class="col-10">
<h1>Gruppenerstellung</h1> <h1>Gruppenerstellung</h1>
<form enctype="multipart/form-data" method="post" <form enctype="multipart/form-data" method="post" th:action="@{/gruppen2/createOrga}">
th:action="@{/gruppen2/createOrga}"> <div class="shadow-sm p-2" style=" border: 10px solid aliceblue; background: aliceblue;">
<div class="shadow-sm p-2"
style=" border: 10px solid aliceblue; background: aliceblue">
<div class="form-group"> <div class="form-group">
<label for="titel">Titel</label> <label for="titel">Titel</label>
<input class="form-control" id="titel" required th:name="title" <input class="form-control" id="titel" required th:name="title" type="text">
type="text">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="description">Beschreibung</label> <label for="description">Beschreibung</label>
<textarea class="form-control" id="description" required <textarea class="form-control" id="description" required rows="3" th:name="description"></textarea>
rows="3" th:name="description"></textarea>
</div> </div>
<div class="custom-control custom-checkbox"> <div class="custom-control custom-checkbox">
<input class="custom-control-input" id="maxInfiniteUsers" th:name="maxInfiniteUsers" <!--DUMMY-->
type="checkbox"> <input type="hidden" id="maxInfiniteUsersDummy" name="maxInfiniteUsers" value="0"/>
<input class="custom-control-input" type="checkbox" id="maxInfiniteUsers" onchange="$('#maxInfiniteUsersDummy').val(this.checked ? 1 : 0)"/>
<label class="custom-control-label" for="maxInfiniteUsers">Anzahl <label class="custom-control-label" for="maxInfiniteUsers">Anzahl
unbegrenzt</label> unbegrenzt</label>
</div> </div>
<div class="form-group mt-3" id="userMaximum"> <div class="form-group mt-3" id="userMaximum">
<label for="userMaximum">Teilnehmeranzahl</label> <label for="userMax">Teilnehmeranzahl</label>
<input class="form-control" th:name="userMaximum" <input class="form-control" id="userMax" th:name="userMaximum" type="number" min="1" max="100000" value="1">
type="number" min="1" max="10000">
</div> </div>
<div class="custom-control custom-checkbox" id="privateCheckbox"> <div class="custom-control custom-checkbox" id="privateCheckbox">
<input class="custom-control-input" id="visibility" th:name="visibility" <!--DUMMY-->
type="checkbox"> <input type="hidden" id="visibilityDummy" name="visibility" value="0"/>
<label class="custom-control-label" for="visibility">Private <input class="custom-control-input" type="checkbox" id="visibility" onchange="$('#visibilityDummy').val(this.checked ? 1 : 0)"/>
Gruppe</label> <label class="custom-control-label" for="visibility">Privat</label>
</div> </div>
<div class="custom-control custom-checkbox" id="lectureCheckbox"> <div class="custom-control custom-checkbox" id="lectureCheckbox">
<input class="custom-control-input" id="lecture" th:name="lecture" <!--DUMMY-->
type="checkbox"> <input type="hidden" id="lectureDummy" name="lecture" value="0"/>
<input class="custom-control-input" type="checkbox" id="lecture" onchange="$('#lectureDummy').val(this.checked ? 1 : 0)"/>
<label class="custom-control-label" for="lecture">Veranstaltung</label> <label class="custom-control-label" for="lecture">Veranstaltung</label>
</div> </div>
<div class="form-group" id="lectureParent"> <div class="form-group mt-3" id="lectureParent">
<label for="parent"></label> <label for="parent">Veranstaltungszugehörigkeit</label>
<select class="form-control" id="parent" name="parent"> <select class="form-control" id="parent" th:name="parent">
<option disabled selected="true">--Bitte Veranstaltung auswählen-- <option value="" selected>--Keine--</option>
</option> <option th:each="lecture : ${lectures}" name="parent" th:value="${lecture.getId()}" th:text="${lecture.getTitle()}"></option>
<option th:each="lecture : ${lectures}" th:name="parent" th:value="${lecture.getId()}" th:text="${lecture.getTitle()}">
</option>
</select> </select>
</div> </div>
<div class="form-group pt-4"> <div class="form-group pt-4">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<div class="custom-file"> <div class="custom-file">
<input class="custom-file-input" id="file" th:name="file"
type="file">
<label class="custom-file-label" for="file">CSV Datei von <label class="custom-file-label" for="file">CSV Datei von
Mitgliedern Mitgliedern
hochladen</label> hochladen</label>
<input class="custom-file-input" id="file" th:name="file" type="file">
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group pt-4"> <div class="form-group pt-4">
<button class="btn btn-primary" <button class="btn btn-primary"
style="background: #52a1eb; border-style: none" style="background: #52a1eb; border-style: none;"
type="submit">Erstellen type="submit">Erstellen
</button> </button>
</div> </div>
@ -107,38 +105,45 @@
</div> </div>
</div> </div>
</div> </div>
<script> <script>
// Add the following code if you want the name of the file appear on select // Add the following code if you want the name of the file appear on select
$(".custom-file-input").on("change", function () { $(".custom-file-input").on("change", function () {
var fileName = $(this).val().split("\\").pop(); const fileName = $(this).val().split("\\").pop();
$(this).siblings(".custom-file-label").addClass("selected").html(fileName); $(this).siblings(".custom-file-label").addClass("selected").html(fileName);
}); });
// Collapsing lectureParent if lecture is checked // Collapse lectureParent if lecture
$(document).ready(function () { $(document).ready(function () {
$('#lecture').change(function () { $('#lecture').change(function () {
$('#lectureParent').fadeToggle(); $('#parent').prop('disable', function (i, v) { return !v; });
}); });
}); });
// Collapse provateCheckbox if lecture
$(document).ready(function () { $(document).ready(function () {
$('#lecture').change(function () { $('#lecture').change(function () {
$('#privateCheckbox').fadeToggle(); $('#visibility').prop('disabled', function (i, v) { return !v; });
}); });
}); });
// Collapse lectureCheckbox if private
$(document).ready(function () { $(document).ready(function () {
$('#visibility').change(function () { $('#visibility').change(function () {
$('#lectureCheckbox').fadeToggle(); $('#lecture').prop('disabled', function (i, v) { return !v; });
}); });
}); });
// Collapse userMaximum if infinite
$(document).ready(function () { $(document).ready(function () {
$('#maxInfiniteUsers').change(function () { $('#maxInfiniteUsers').change(function () {
$('#userMaximum').fadeToggle(); $('#userMax').prop('readonly', function (i, v) { return !v; });
}); });
}); });
</script> </script>
</main> </main>
</body> </body>
</html> </html>

View File

@ -27,7 +27,7 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li> <li>
<a th:href="@{/gruppen2/findGroup}" href="/findGroup">Suche</a> <a th:href="@{/gruppen2/searchPage}" href="/searchPage">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
@ -39,47 +39,45 @@
<h1>Gruppenerstellung</h1> <h1>Gruppenerstellung</h1>
<form method="post" th:action="@{/gruppen2/createStudent}"> <form method="post" th:action="@{/gruppen2/createStudent}">
<div class="shadow-sm p-2" <div class="shadow-sm p-2"
style=" border: 10px solid aliceblue; border-radius: 5px; background: aliceblue"> style=" border: 10px solid aliceblue; border-radius: 5px; background: aliceblue;">
<div class="form-group"> <div class="form-group">
<label for="titel">Titel</label> <label for="titel">Titel</label>
<input class="form-control" id="titel" required th:name="title" <input class="form-control" id="titel" required th:name="title" type="text">
type="text">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="description">Beschreibung</label> <label for="description">Beschreibung</label>
<textarea class="form-control" id="description" required <textarea class="form-control" id="description" required rows="3" th:name="description"></textarea>
rows="3" th:name="description"></textarea>
</div> </div>
<div class="custom-control custom-checkbox"> <div class="custom-control custom-checkbox">
<input class="custom-control-input" id="maxInfiniteUsers" th:name="maxInfiniteUsers" <!--DUMMY-->
type="checkbox"> <input type="hidden" id="maxInfiniteUsersDummy" name="maxInfiniteUsers" value="0"/>
<input class="custom-control-input" type="checkbox" id="maxInfiniteUsers" onchange="$('#maxInfiniteUsersDummy').val(this.checked ? 1 : 0)"/>
<label class="custom-control-label" for="maxInfiniteUsers">Anzahl <label class="custom-control-label" for="maxInfiniteUsers">Anzahl
unbegrenzt</label> unbegrenzt</label>
</div> </div>
<div class="form-group mt-3" id="userMaximum"> <div class="form-group mt-3" id="userMaximum">
<label for="userMaximum">Teilnehmeranzahl</label> <label for="userMax">Teilnehmeranzahl</label>
<input class="form-control" th:name="userMaximum" <input class="form-control" th:name="userMaximum"
type="number" min="1" max="10000"> type="number" min="1" max="10000" id="userMax">
</div> </div>
<div class="custom-control custom-checkbox"> <div class="custom-control custom-checkbox">
<input class="custom-control-input" id="visibility" th:name="visibility" <!--DUMMY-->
type="checkbox"> <input type="hidden" id="visibilityDummy" name="visibility" value="0"/>
<label class="custom-control-label" for="visibility">Private <input class="custom-control-input" type="checkbox" id="visibility" onchange="$('#visibilityDummy').val(this.checked ? 1 : 0)"/>
Gruppe</label> <label class="custom-control-label" for="visibility">Privat</label>
</div> </div>
<div class="form-group" id="lectureParent"> <div class="form-group" id="lectureParent">
<label for="parent"></label> <label for="parent">Veranstaltungszugehörigkeit</label>
<select class="form-control" id="parent" name="parent"> <select class="form-control" id="parent" name="parent">
<option disabled selected="true">--Bitte Veranstaltung auswählen-- <option value="" selected>--Keine--</option>
</option>
<option th:each="lecture : ${lectures}" th:name="parent" th:value="${lecture.getId()}" th:text="${lecture.getTitle()}"> <option th:each="lecture : ${lectures}" th:name="parent" th:value="${lecture.getId()}" th:text="${lecture.getTitle()}">
</option> </option>
</select> </select>
</div> </div>
<div class="form-group pt-4"> <div class="form-group pt-4">
<button class="btn btn-primary" <button class="btn btn-primary"
style="background: #52a1eb; border-style: none" style="background: #52a1eb; border-style: none;"
type="submit">Erstellen type="submit">Erstellen
</button> </button>
</div> </div>

View File

@ -24,7 +24,7 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li> <li>
<a href="/findGroup" th:href="@{/gruppen2/findGroup}">Suche</a> <a href="/searchPage" th:href="@{/gruppen2/searchPage}">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
@ -33,38 +33,38 @@
<div class="container-fluid"> <div class="container-fluid">
<div> <div>
<div class="shadow-sm p-4 col-8" <div class="shadow-sm p-4 col-8"
style="border: 10px solid aliceblue; display: inline-block; border-radius: 5px; background: aliceblue"> style="border: 10px solid aliceblue; display: inline-block; border-radius: 5px; background: aliceblue;">
<div class="row"> <div class="row">
<div class="col-11"> <div class="col-11">
<h1 style="color: black; font-weight: bold; font-optical-sizing: auto; overflow-wrap: break-word; width: 95%" <h1 style="color: black; font-weight: bold; font-optical-sizing: auto; overflow-wrap: break-word; width: 95%;"
th:text="${group.getTitle()}"></h1> th:text="${group.getTitle()}"></h1>
</div> </div>
<div class="col-1"> <div class="col-1">
<a class="fa fa-pencil" <a class="fa fa-pencil"
style="font-size:30px; width: 5%" style="font-size:30px; width: 5%;"
th:href="@{/gruppen2/details/changeMetadata/{id}(id=${group.getId()})}" th:href="@{/gruppen2/details/changeMetadata/{id}(id=${group.getId()})}"
th:if="${roles.get(user.getId()) == admin}"></a> th:if="${roles.get(user.getId()) == admin}"></a>
</div> </div>
</div> </div>
<h3> <h3>
<span class="badge badge-pill badge-dark" style="background: darkslategray" <span class="badge badge-pill badge-dark" style="background: darkslategray;"
th:if='${group.getVisibility() == group.getVisibility().PRIVATE }'>Private Gruppe</span> th:if='${group.getVisibility() == group.getVisibility().PRIVATE }'>Private Gruppe</span>
<span class="badge badge-pill badge-primary" style="background: #52a1eb" <span class="badge badge-pill badge-primary" style="background: #52a1eb;"
th:if="${group.getVisibility() == group.getVisibility().PUBLIC}">Öffentliche Gruppe</span> th:if="${group.getVisibility() == group.getVisibility().PUBLIC}">Öffentliche Gruppe</span>
<span class="badge badge-pill badge-success" style="background: lightseagreen" <span class="badge badge-pill badge-success" style="background: lightseagreen;"
th:if='${group.getType() == group.getType().LECTURE}'>Veranstaltung</span> th:if='${group.getType() == group.getType().LECTURE}'>Veranstaltung</span>
<span class="badge badge-pill badge-info" style="background: mediumorchid" <span class="badge badge-pill badge-info" style="background: mediumorchid;"
th:text="${parent.getTitle()}">Parent</span> th:text="${parent?.getTitle()}">Parent</span>
<div class="input-group mb-3" style="margin-top: 10px" <div class="input-group mb-3" style="margin-top: 10px;"
th:if="${roles.get(user.getId()) == admin}"> th:if="${roles.get(user.getId()) == admin}">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default" <span class="input-group-text" id="inputGroup-sizing-default"
style="background: #52a1eb">Einladungslink:</span> style="background: #52a1eb;">Einladungslink:</span>
</div> </div>
<input aria-describedby="basic-addon2" aria-label="Recipient's username" <input aria-describedby="basic-addon2" aria-label="Recipient's username"
class="form-control" class="form-control"
id="groupLink" readonly style="background: white" th:value="${link}" id="groupLink" readonly style="background: white;" th:value="${link}"
type="text"> type="text">
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-outline-secondary" onclick="copyLink()" <button class="btn btn-outline-secondary" onclick="copyLink()"
@ -74,23 +74,23 @@
</div> </div>
</h3> </h3>
<br> <br>
<div class="shadow-sm p-4" style="background: white"> <div class="shadow-sm p-4" style="background: white;">
<p style="overflow-wrap: break-word; font-optical-sizing: auto" th:text="${group.getDescription()}"></p> <p style="overflow-wrap: break-word; font-optical-sizing: auto;" th:text="${group.getDescription()}"></p>
</div> </div>
<br> <br>
<div class="text-right btn-toolbar" role="toolbar" style="float: right"> <div class="text-right btn-toolbar" role="toolbar" style="float: right;">
<button class="btn btn-primary" <button class="btn btn-primary"
style="background: #52a1eb; border: none; margin: 5px"> style="background: #52a1eb; border: none; margin: 5px;">
<a style="color: white" th:href="@{/gruppen2}">Zurück</a> <a style="color: white;" th:href="@{/gruppen2}">Zurück</a>
</button> </button>
<form method="post" th:action="@{/gruppen2/leaveGroup}"> <form method="post" th:action="@{/gruppen2/leaveGroup}">
<button class="btn btn-danger" style="border-style: none; margin: 5px" <button class="btn btn-danger" style="border-style: none; margin: 5px;"
th:name="group_id" th:value="${group.getId()}" th:name="group_id" th:value="${group.getId()}"
type="submit">Gruppe verlassen type="submit">Gruppe verlassen
</button> </button>
</form> </form>
<form method="post" th:action="@{/gruppen2/deleteGroup}"> <form method="post" th:action="@{/gruppen2/deleteGroup}">
<button class="btn btn-danger" style="border-style: none; margin: 5px" <button class="btn btn-danger" style="border-style: none; margin: 5px;"
th:name="group_id" th:value="${group.getId()}" th:name="group_id" th:value="${group.getId()}"
th:if="${group.getRoles().get(user.getId()) == admin}" th:if="${group.getRoles().get(user.getId()) == admin}"
type="submit">Gruppe löschen type="submit">Gruppe löschen
@ -98,13 +98,13 @@
</form> </form>
</div> </div>
</div> </div>
<div class="col-4" style="white-space: nowrap; float: right; background: white; display: inline-block; margin-bottom: 100px; margin-top: -8px"> <div class="col-4" style="white-space: nowrap; float: right; background: white; display: inline-block; margin-bottom: 100px; margin-top: -8px;">
<h2>Mitglieder</h2> <h2>Mitglieder</h2>
<div th:switch="${group.getUserMaximum() != 100000}"> <div th:switch="${group.getUserLimit() != 100000}">
<h4 th:case="${true}"> <h4 th:case="${true}">
<a th:text="${group.getMembers().size()}"></a> <a th:text="${group.getMembers().size()}"></a>
<a>von maximal</a> <a>von maximal</a>
<a th:text="${group.getUserMaximum()}"></a> <a th:text="${group.getUserLimit()}"></a>
<a>Benutzern.</a> <a>Benutzern.</a>
</h4> </h4>
<h4 th:case="${false}"> unbegrenzte Teilnehmeranzahl</h4> <h4 th:case="${false}"> unbegrenzte Teilnehmeranzahl</h4>
@ -112,7 +112,7 @@
<div th:if="${group.getRoles().get(user.getId()) == admin}"> <div th:if="${group.getRoles().get(user.getId()) == admin}">
<form method="get" <form method="get"
th:action="@{/gruppen2/details/members/{id}(id=${group.getId()})}"> th:action="@{/gruppen2/details/members/{id}(id=${group.getId()})}">
<button class="btn btn-secondary" style="background: slategrey; float: left"> <button class="btn btn-secondary" style="background: slategrey; float: left;">
Mitglieder bearbeiten Mitglieder bearbeiten
</button> </button>
</form> </form>
@ -120,10 +120,10 @@
<br> <br>
</div> </div>
<div style="overflow-y: scroll; <div style="overflow-y: scroll;
height:60vh"> height:60vh;">
<ul class="list-group-flush" style="background: slategrey" <ul class="list-group-flush" style="background: slategrey;"
th:each="member : ${group.getMembers()}"> th:each="member : ${group.getMembers()}">
<li class="list-group-item" style="background: aliceblue"> <li class="list-group-item" style="background: aliceblue;">
<span th:if='${group.getVisibility() == public}' th:text="${member.getId()}"></span> <span th:if='${group.getVisibility() == public}' th:text="${member.getId()}"></span>
<span th:if='${group.getVisibility() == private}' th:text="${#strings.abbreviate(member.getGivenname(), 15) + ' ' + member.getFamilyname().substring(0, 1) + '.'}"></span> <span th:if='${group.getVisibility() == private}' th:text="${#strings.abbreviate(member.getGivenname(), 15) + ' ' + member.getFamilyname().substring(0, 1) + '.'}"></span>
<span class="badge badge-success" <span class="badge badge-success"

View File

@ -22,59 +22,29 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li class="active"> <li class="active">
<a th:href="@{/gruppen2/findGroup}" href="/findGroup">Suche</a> <a th:href="@{/gruppen2/searchPage}" href="/searchPage">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
</header> </header>
<main th:fragment="bodycontent"> <main th:fragment="bodycontent">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="shadow-sm p-4" style="border: 1px solid aliceblue; border-radius: 5px; background: aliceblue;">
<div class="col-9"> <h1 style="color: black; font-weight: bold; font-optical-sizing: auto; overflow-wrap: break-word;" th:text="${group.getTitle()}"></h1>
<div class="shadow-sm p-4" style="border: 1px solid aliceblue; border-radius: 5px; background: aliceblue"> <h3>
<h1 style="color: black; font-weight: bold; font-optical-sizing: auto; overflow-wrap: break-word" th:text="${group.getTitle()}"></h1> <span class="badge badge-pill badge-dark" style="background: darkslategray;"
<h3>
<span class="badge badge-pill badge-dark" style="background: darkslategray"
th:if='${group.getVisibility() == group.getVisibility().PRIVATE }'>Private Gruppe</span> th:if='${group.getVisibility() == group.getVisibility().PRIVATE }'>Private Gruppe</span>
<span class="badge badge-pill badge-primary" style="background: #52a1eb" <span class="badge badge-pill badge-primary" style="background: #52a1eb;"
th:if="${group.getVisibility() == group.getVisibility().PUBLIC}">Öffentliche Gruppe</span> th:if="${group.getVisibility() == group.getVisibility().PUBLIC}">Öffentliche Gruppe</span>
<span class="badge badge-pill badge-success" <span class="badge badge-pill badge-success"
style="background: lightseagreen" style="background: lightseagreen;"
th:if='${group.getType() == group.getType().LECTURE}'> Veranstaltung</span> th:if='${group.getType() == lecture}'> Veranstaltung</span>
<span class="badge badge-pill badge-info" style="background: mediumorchid" <span class="badge badge-pill badge-info" style="background: mediumorchid;"
th:text="${parent.getTitle()}">Parent</span> th:text="${parent?.getTitle()}">Parent</span>
</h3> </h3>
<div class="shadow-sm p-4" style="background: white"> <div class="shadow-sm p-4" style="background: white;">
<p style="overflow-wrap: break-word; font-optical-sizing: auto" <p style="overflow-wrap: break-word; font-optical-sizing: auto;"
th:text="${group.getDescription()}"></p> th:text="${group.getDescription()}"></p>
</div>
<div class="form-group mt-2">
<div class="text-right">
<form method="post" th:action="@{/gruppen2/detailsBeitreten}">
<button class="btn btn-primary"
style="background: #52a1eb; border-style: none;"
th:href="@{/gruppen2/detailsBeitreten}"
th:name="id" th:value="${group.getId()}"
type="submit">Gruppe beitreten
</button>
</form>
</div>
</div>
</div>
</div>
<div class="col-3" style="white-space: nowrap">
<div style="display: inline-block; margin: 0">
<h2>Mitglieder</h2>
<div th:switch="${group.getUserMaximum() != 100000}">
<h4 th:case="${true}">
<a th:text="${group.getMembers().size()}"></a>
<a>von maximal</a>
<a th:text="${group.getUserMaximum()}"></a>
<a>Benutzern.</a>
</h4>
<h4 th:case="false">unbegrenzte Teilnehmeranzahl</h4>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -27,7 +27,7 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li> <li>
<a th:href="@{/gruppen2/findGroup}" href="/findGroup">Suche</a> <a th:href="@{/gruppen2/searchPage}" href="/searchPage">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
@ -37,16 +37,17 @@
<div class="row"> <div class="row">
<div class="col-10"> <div class="col-10">
<h1>Mitglieder bearbeiten</h1> <h1>Mitglieder bearbeiten</h1>
<div th:switch="${group.getUserMaximum() != 100000}"> <!--TODO: Anzeige bei unbegrenzt-->
<div th:switch="${group.getUserLimit() != 100000}">
<h5 th:case="${true}"> <h5 th:case="${true}">
<a th:text="${group.getMembers().size()}"></a> <a th:text="${group.getMembers().size()}"></a>
<a>von maximal</a> <a>von maximal</a>
<a th:text="${group.getUserMaximum()}"></a> <a th:text="${group.getUserLimit()}"></a>
<a>Benutzern.</a> <a>Benutzern.</a>
</h5> </h5>
<h5 th:case="${false}"> unbegrenzte Teilnehmeranzahl</h5> <h5 th:case="${false}"> unbegrenzte Teilnehmeranzahl</h5>
</div> </div>
<div class="shadow p-2" style="border: 10px solid aliceblue; background: aliceblue"> <div class="shadow p-2" style="border: 10px solid aliceblue; background: aliceblue;">
<div class="form-group pt-4" th:if="${account.getRoles().contains('orga')}"> <div class="form-group pt-4" th:if="${account.getRoles().contains('orga')}">
<form th:action="@{/gruppen2/details/members/addUsersFromCsv}" <form th:action="@{/gruppen2/details/members/addUsersFromCsv}"
enctype="multipart/form-data" enctype="multipart/form-data"
@ -61,10 +62,10 @@
</div> </div>
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-outline-secondary" <button class="btn btn-outline-secondary"
style="background: #52a1eb; border-style: none" style="background: #52a1eb; border-style: none;"
th:name="group_id" th:value="${group.getId()}" th:name="group_id" th:value="${group.getId()}"
type="submit"> type="submit">
<a style="color: white">Hinzufügen</a> <a style="color: white;">Hinzufügen</a>
</button> </button>
</div> </div>
</div> </div>
@ -73,29 +74,31 @@
<div class="form-group pt-4"> <div class="form-group pt-4">
<form method="post" th:action="@{/gruppen2/details/members/changeMaximum}"> <form method="post" th:action="@{/gruppen2/details/members/changeMaximum}">
<div class="input-group mb-3" id="userMaximum"> <div class="input-group mb-3" id="userMaximum">
<label for="teilnehmerzahl"></label>
<input class="form-control" <input class="form-control"
id="teilnehmerzahl"
placeholder="Maximale Teilnehmerzahl ändern..." placeholder="Maximale Teilnehmerzahl ändern..."
th:name="maximum" th:name="maximum"
type="number" th:min="${group.getMembers().size()}" type="number" th:min="${group.getMembers().size()}"
max="10000"> max="10000">
<div class="input-group-append"> <div class="input-group-append">
<button class="btn btn-outline-secondary" <button class="btn btn-outline-secondary"
style="background: #52a1eb; border-style: none" style="background: #52a1eb; border-style: none;"
th:name="group_id" th:value="${group.getId()}" th:name="group_id" th:value="${group.getId()}"
type="submit"> type="submit">
<a style="color: white">Speichern</a> <a style="color: white;">Speichern</a>
</button> </button>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<table class="table" style="table-layout: fixed"> <table class="table" style="table-layout: fixed;">
<thead> <thead>
<tr> <tr>
<th scope="col">Mitglied</th> <th scope="col">Mitglied</th>
<th scope="col" style="width: 180px">Rolle</th> <th scope="col" style="width: 180px;">Rolle</th>
<th scope="col" style="width: 280px">Optionen</th> <th scope="col" style="width: 280px;">Optionen</th>
</tr> </tr>
</thead> </thead>
<tbody class="table-striped"> <tbody class="table-striped">
@ -123,7 +126,7 @@
type="hidden"> type="hidden">
<input th:name="user_id" th:value="${member.getId()}" <input th:name="user_id" th:value="${member.getId()}"
type="hidden"> type="hidden">
<button class="btn btn-danger btn-sm" style="margin: 5px" <button class="btn btn-danger btn-sm" style="margin: 5px;"
th:if='!${account.getName().equals(member.getId())}'> th:if='!${account.getName().equals(member.getId())}'>
Mitglied entfernen Mitglied entfernen
</button> </button>
@ -134,7 +137,7 @@
</tbody> </tbody>
</table> </table>
<form method="get" th:action="@{/gruppen2/details/{id}(id=${group.getId()})}"> <form method="get" th:action="@{/gruppen2/details/{id}(id=${group.getId()})}">
<button class="btn btn-primary" style="background: #52a1eb; border-style: none" type="submit"> <button class="btn btn-primary" style="background: #52a1eb; border-style: none;" type="submit">
Fertig Fertig
</button> </button>
</form> </form>

View File

@ -11,7 +11,7 @@
</head> </head>
<body> <body>
<div class="mx-auto" style="vertical-align: center; border-radius: 5px; horiz-align: center; top: 50%; left: 50%;"> <div class="mx-auto" style="vertical-align: center; border-radius: 5px; horiz-align: center; top: 50%; left: 50%;">
<div class="jumbotron" style="background: aliceblue"> <div class="jumbotron" style="background: aliceblue;">
<div class="container"> <div class="container">
<h1 class="display-3">UPSI</h1> <h1 class="display-3">UPSI</h1>
<p class="lead">Da ist wohl etwas schiefgelaufen :(</p><br> <p class="lead">Da ist wohl etwas schiefgelaufen :(</p><br>
@ -30,7 +30,7 @@
<button class="btn btn-primary" <button class="btn btn-primary"
style="background: #52a1eb; border-style: none;"> style="background: #52a1eb; border-style: none;">
<a href="#" onclick="window.history.back(-1);return false;" role="button" <a href="#" onclick="window.history.back(-1);return false;" role="button"
style="color: white">Zurück</a> style="color: white;">Zurück</a>
</button> </button>
</div> </div>
</div> </div>

View File

@ -23,7 +23,7 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li> <li>
<a href="/findGroup" th:href="@{/gruppen2/findGroup}">Suche</a> <a href="/searchPage" th:href="@{/gruppen2/searchPage}">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
@ -34,28 +34,28 @@
<div class="col-10"> <div class="col-10">
<h1>Meine Gruppen</h1> <h1>Meine Gruppen</h1>
<form method="get" th:action="@{/}"> <form method="get" th:action="@{/}">
<h3 style="color: dodgerblue; font-weight: bold; font-optical-sizing: auto"> <h3 style="color: dodgerblue; font-weight: bold; font-optical-sizing: auto;">
<small style="font-weight: normal; color: black">Mitglied in </small> <small style="font-weight: normal; color: black;">Mitglied in </small>
<small style="font-weight: bold; color: black" <small style="font-weight: bold; color: black;"
th:text="${gruppen.size()}"></small> th:text="${gruppen.size()}"></small>
<small style="font-weight: normal; color: black" <small style="font-weight: normal; color: black;"
th:if='${gruppen.size()==1}'> Gruppe.</small> th:if='${gruppen.size()==1}'> Gruppe.</small>
<small style="font-weight: normal; color: black" <small style="font-weight: normal; color: black;"
th:if='${gruppen.size()!=1}'> Gruppen.</small> th:if='${gruppen.size()!=1}'> Gruppen.</small>
</h3> </h3>
<br> <br>
<div th:each="gruppe: ${gruppen}"> <div th:each="gruppe: ${gruppen}">
<div class="shadow-sm p-4" <div class="shadow-sm p-4"
style="border: none; border-radius: 5px; background: aliceblue"> style="border: none; border-radius: 5px; background: aliceblue;">
<h3 style="color: dodgerblue; font-weight: bold; font-optical-sizing: auto; overflow-wrap: break-word"> <h3 style="color: dodgerblue; font-weight: bold; font-optical-sizing: auto; overflow-wrap: break-word;">
<span class="badge badge-pill badge-success" <span class="badge badge-pill badge-success"
style="background: lightseagreen; margin-right: 25px; float: right" style="background: lightseagreen; margin-right: 25px; float: right;"
th:if='${gruppe.getType() == gruppe.getType().LECTURE}'>Veranstaltung</span> th:if='${gruppe.getType() == lecture}'>Veranstaltung</span>
<a th:href="@{/gruppen2/details/{id}(id=${gruppe.getId()})}" <a th:href="@{/gruppen2/details/{id}(id=${gruppe.getId()})}"
th:text="${gruppe.getTitle()}"></a> th:text="${gruppe.getTitle()}"></a>
</h3> </h3>
<div class="shadow-sm p-4" style="background: white"> <div class="shadow-sm p-4" style="background: white;">
<p style="overflow-wrap: break-word; font-optical-sizing: auto" <p style="overflow-wrap: break-word; font-optical-sizing: auto;"
th:text="${#strings.abbreviate(gruppe.getDescription(),300)}"></p> th:text="${#strings.abbreviate(gruppe.getDescription(),300)}"></p>
</div> </div>
</div> </div>

View File

@ -10,6 +10,7 @@
</th:block> </th:block>
</head> </head>
<body> <body>
<header> <header>
<nav class="navigation navigation-secondary" is="mops-navigation" th:fragment="navigation" <nav class="navigation navigation-secondary" is="mops-navigation" th:fragment="navigation"
th:switch="${account.getRoles().contains('orga')}"> th:switch="${account.getRoles().contains('orga')}">
@ -24,56 +25,44 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li class="active"> <li class="active">
<a href="/findGroup" th:href="@{/gruppen2/findGroup}">Suche</a> <a href="/searchPage" th:href="@{/gruppen2/searchPage}">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
</header> </header>
<main th:fragment="bodycontent"> <main th:fragment="bodycontent">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="shadow-sm p-4"
<div class="col-9"> style="border: 1px solid aliceblue; border-radius: 5px; background: aliceblue;">
<div class="shadow-sm p-4" <h1 style="color: black; font-weight: bold; font-optical-sizing: auto; overflow-wrap: break-word;"
style="border: 1px solid aliceblue; border-radius: 5px; background: aliceblue"> th:text="${group.getTitle()}"></h1>
<h1 style="color: black; font-weight: bold; font-optical-sizing: auto; overflow-wrap: break-word" <div class="shadow-sm p-4" style="background: white;">
th:text="${group.getTitle()}"></h1> <p style="overflow-wrap: break-word; font-optical-sizing: auto;"
<h3>Möchtest du dieser privaten Gruppe beitreten?</h3> th:text="${group.getDescription()}"></p>
<div class="shadow-sm p-4" style="background: white"> </div>
<p style="overflow-wrap: break-word; font-optical-sizing: auto" <div class="form-group mt-2" th:if="${group.getMembers().size() < group.getUserLimit()}">
th:text="${group.getDescription()}"></p> <h3>Möchtest du dieser privaten Gruppe beitreten?</h3>
</div> <div class="text-right">
<div class="form-group mt-2"> <form method="post" th:action="@{/gruppen2/acceptinvite}">
<div class="text-right"> <input name="id" th:value="${group.getId()}" type="hidden"/>
<form method="post" th:action="@{/gruppen2/acceptinvite}"> <button class="btn btn-primary"
<input name="id" th:value="${group.getId()}" type="hidden"/> style="background: #52a1eb; border-style: none;"
<button class="btn btn-primary" type="submit">Ja, Gruppe beitreten
style="background: #52a1eb; border-style: none;" </button>
type="submit">Ja, Gruppe beitreten <a class="btn btn-primary"
</button> href="/gruppen2"
<a class="btn btn-primary" style="background: #52a1eb; border-style: none;"
href="/gruppen2" type="submit">Ich will das nicht.
style="background: #52a1eb; border-style: none;" </a>
type="submit">Ich will das nicht. </form>
</a>
</form>
</div>
</div>
</div>
</div>
<div class="col-3" style="white-space: nowrap">
<div style="display: inline-block; margin: 0">
<h2>Mitglieder</h2>
<div th:switch="${group.getUserMaximum() != 100000}">
<h4 th:case="${true}">
<a th:text="${group.getMembers().size()}"></a>
<a>von maximal</a>
<a th:text="${group.getUserMaximum()}"></a>
<a>Benutzern.</a>
</h4>
<h4 th:case="false">unbegrenzte Teilnehmeranzahl</h4>
</div>
</div> </div>
</div> </div>
<h3 class="mt-2" th:if="${group.getMembers().size() >= group.getUserLimit()}">Gruppe ist
voll und
kann nicht
beigetreten
werden.</h3>
</div> </div>
</div> </div>
</main> </main>

View File

@ -23,7 +23,7 @@
<a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a> <a href="/createStudent" th:href="@{/gruppen2/createStudent}">Erstellen</a>
</li> </li>
<li class="active"> <li class="active">
<a th:href="@{/gruppen2/findGroup}" href="/findGroup">Suche</a> <a th:href="@{/gruppen2/searchPage}" href="/searchPage">Suche</a>
</li> </li>
</ul> </ul>
</nav> </nav>
@ -34,8 +34,8 @@
<div class="col-10"> <div class="col-10">
<h1>Gruppensuche</h1> <h1>Gruppensuche</h1>
<div class="shadow-sm p-2" <div class="shadow-sm p-2"
style="border: 10px solid aliceblue; border-radius: 5px; background: aliceblue"> style="border: 10px solid aliceblue; border-radius: 5px; background: aliceblue;">
<form method="get" th:action="@{/gruppen2/findGroup}"> <form method="get" th:action="@{/gruppen2/search}">
<div class="form-group"> <div class="form-group">
<label for="suchleiste">Suchbegriff:</label> <label for="suchleiste">Suchbegriff:</label>
<input class="form-control" id="suchleiste" <input class="form-control" id="suchleiste"
@ -43,14 +43,12 @@
th:name="suchbegriff" type="text"> th:name="suchbegriff" type="text">
</div> </div>
<button class="btn btn-primary" <button class="btn btn-primary"
style="background: #52a1eb; border-style: none" style="background: #52a1eb; border-style: none;"
type="submit">Suchen type="submit">Suchen
</button> </button>
<button class="btn btn-primary" <button class="btn btn-primary" style="background: deepskyblue; border-style: none;" type="submit">
style="background: deepskyblue; border-style: none" <a href="/gruppen2/search?suchbegriff=" style="color: white;">Alle
type="submit"> anzeigen</a>
<a href="/gruppen2/findGroup?suchbegriff=" style="color: white">Alle
anzeigen</a>
</button> </button>
</form> </form>
</div> </div>
@ -65,7 +63,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr th:each="gruppe : ${gruppen}" th:switch="${gruppe.getUserMaximum() != 100000}"> <tr th:each="gruppe : ${gruppen}" th:switch="${gruppe.getUserLimit() != 100000}">
<th scope="row"> <th scope="row">
<span class="badge badge-pill badge-success" <span class="badge badge-pill badge-success"
style="background: lightseagreen; margin-right: 25px;" style="background: lightseagreen; margin-right: 25px;"
@ -77,7 +75,7 @@
Beschreibung Beschreibung
</td> </td>
<td th:case="${true}"> <td th:case="${true}">
<a th:text="${gruppe.getUserMaximum()}"></a> <a th:text="${gruppe.getUserLimit()}"></a>
</td> </td>
<td th:case="${false}">unbegrenzt</td> <td th:case="${false}">unbegrenzt</td>
</tr> </tr>

View File

@ -6,6 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest @SpringBootTest
class Gruppen2ApplicationTests { class Gruppen2ApplicationTests {
@SuppressWarnings("EmptyMethod")
@Test @Test
void contextLoads() { void contextLoads() {
} }

View File

@ -14,6 +14,7 @@ import mops.gruppen2.domain.event.Event;
import mops.gruppen2.domain.event.UpdateGroupDescriptionEvent; import mops.gruppen2.domain.event.UpdateGroupDescriptionEvent;
import mops.gruppen2.domain.event.UpdateGroupTitleEvent; import mops.gruppen2.domain.event.UpdateGroupTitleEvent;
import mops.gruppen2.domain.event.UpdateRoleEvent; import mops.gruppen2.domain.event.UpdateRoleEvent;
import mops.gruppen2.domain.event.UpdateUserLimitEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -93,6 +94,7 @@ public class TestBuilder {
eventList.add(createPublicGroupEvent(groupId)); eventList.add(createPublicGroupEvent(groupId));
eventList.add(updateGroupTitleEvent(groupId)); eventList.add(updateGroupTitleEvent(groupId));
eventList.add(updateGroupDescriptionEvent(groupId)); eventList.add(updateGroupDescriptionEvent(groupId));
eventList.add(new UpdateUserLimitEvent(groupId, "fgsadggas", Long.MAX_VALUE));
eventList.addAll(addUserEvents(membercount, groupId)); eventList.addAll(addUserEvents(membercount, groupId));
return eventList; return eventList;
@ -105,6 +107,7 @@ public class TestBuilder {
eventList.add(createPrivateGroupEvent(groupId)); eventList.add(createPrivateGroupEvent(groupId));
eventList.add(updateGroupTitleEvent(groupId)); eventList.add(updateGroupTitleEvent(groupId));
eventList.add(updateGroupDescriptionEvent(groupId)); eventList.add(updateGroupDescriptionEvent(groupId));
eventList.add(new UpdateUserLimitEvent(groupId, "fgsadggas", Long.MAX_VALUE));
eventList.addAll(addUserEvents(membercount, groupId)); eventList.addAll(addUserEvents(membercount, groupId));
return eventList; return eventList;
@ -170,8 +173,7 @@ public class TestBuilder {
faker.random().hex(), faker.random().hex(),
null, null,
GroupType.SIMPLE, GroupType.SIMPLE,
visibility, visibility
10000000L
); );
} }
@ -185,8 +187,7 @@ public class TestBuilder {
faker.random().hex(), faker.random().hex(),
null, null,
GroupType.LECTURE, GroupType.LECTURE,
Visibility.PUBLIC, Visibility.PUBLIC
10000000L
); );
} }
@ -286,6 +287,10 @@ public class TestBuilder {
); );
} }
public static Event updateUserLimitMaxEvent(UUID groupId) {
return new UpdateUserLimitEvent(groupId, firstname(), Long.MAX_VALUE);
}
public static Event updateRoleEvent(UUID groupId, String userId, Role role) { public static Event updateRoleEvent(UUID groupId, String userId, Role role) {
return new UpdateRoleEvent( return new UpdateRoleEvent(
groupId, groupId,

View File

@ -11,7 +11,7 @@ import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class) @AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
public class ControllerTest { class ControllerTest {
@ArchTest @ArchTest
public static final ArchRule controllerClassesShouldBeAnnotatedWithControllerOrRestControllerAnnotation = classes() public static final ArchRule controllerClassesShouldBeAnnotatedWithControllerOrRestControllerAnnotation = classes()

View File

@ -10,7 +10,7 @@ import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class) @AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
public class DomainTest { class DomainTest {
@ArchTest @ArchTest
public static final ArchRule domainClassesShouldNotAccessClassesFromOtherPackagesExceptDomainItself = noClasses() public static final ArchRule domainClassesShouldNotAccessClassesFromOtherPackagesExceptDomainItself = noClasses()

View File

@ -7,7 +7,7 @@ import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.library.Architectures; import com.tngtech.archunit.library.Architectures;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class) @AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
public class LayeredArchitectureTest { class LayeredArchitectureTest {
private static final Architectures.LayeredArchitecture layeredArchitecture = Architectures private static final Architectures.LayeredArchitecture layeredArchitecture = Architectures
.layeredArchitecture() .layeredArchitecture()

View File

@ -10,7 +10,7 @@ import org.springframework.stereotype.Repository;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class) @AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
public class RepositoryTest { class RepositoryTest {
@ArchTest @ArchTest
public static final ArchRule repositoryClassesThatAreAnnotatedWithRepositoryShouldHaveRepositoryInName = classes() public static final ArchRule repositoryClassesThatAreAnnotatedWithRepositoryShouldHaveRepositoryInName = classes()

View File

@ -9,7 +9,7 @@ import org.springframework.stereotype.Service;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
@AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class) @AnalyzeClasses(packages = "mops.gruppen2", importOptions = ImportOption.DoNotIncludeTests.class)
public class ServiceTest { class ServiceTest {
@ArchTest @ArchTest
public static final ArchRule serviceClassesShouldHaveServiceInName = classes() public static final ArchRule serviceClassesShouldHaveServiceInName = classes()

View File

@ -1,9 +1,11 @@
package mops.gruppen2.controller; package mops.gruppen2.controller;
import mops.gruppen2.Gruppen2Application; import mops.gruppen2.Gruppen2Application;
import mops.gruppen2.domain.exception.GroupNotFoundException;
import mops.gruppen2.repository.EventRepository; import mops.gruppen2.repository.EventRepository;
import mops.gruppen2.service.EventService; import mops.gruppen2.service.EventStoreService;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -20,8 +22,10 @@ import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
import static mops.gruppen2.TestBuilder.deleteGroupEvent; import static mops.gruppen2.TestBuilder.deleteGroupEvent;
import static mops.gruppen2.TestBuilder.deleteUserEvent; import static mops.gruppen2.TestBuilder.deleteUserEvent;
import static mops.gruppen2.TestBuilder.updateGroupTitleEvent; import static mops.gruppen2.TestBuilder.updateGroupTitleEvent;
import static mops.gruppen2.TestBuilder.updateUserLimitMaxEvent;
import static mops.gruppen2.TestBuilder.uuidMock; import static mops.gruppen2.TestBuilder.uuidMock;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Gruppen2Application.class) @SpringBootTest(classes = Gruppen2Application.class)
@ -33,13 +37,14 @@ class APIControllerTest {
private EventRepository eventRepository; private EventRepository eventRepository;
@Autowired @Autowired
private APIController apiController; private APIController apiController;
private EventService eventService; @Autowired
private EventStoreService eventStoreService;
@Autowired @Autowired
private JdbcTemplate template; private JdbcTemplate template;
@SuppressWarnings("SyntaxError")
@BeforeEach @BeforeEach
void setUp() { void setUp() {
eventService = new EventService(eventRepository);
eventRepository.deleteAll(); eventRepository.deleteAll();
//noinspection SqlResolve //noinspection SqlResolve
template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1"); template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1");
@ -57,35 +62,38 @@ class APIControllerTest {
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void updateGroup_singleGroup() { void updateGroup_singleGroup() {
eventService.saveAll(createPublicGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPublicGroupEvent(uuidMock(0)),
addUserEvent(uuidMock(0)), updateUserLimitMaxEvent(uuidMock(0)),
addUserEvent(uuidMock(0)), addUserEvent(uuidMock(0)),
addUserEvent(uuidMock(0)), addUserEvent(uuidMock(0)),
addUserEvent(uuidMock(0))); addUserEvent(uuidMock(0)),
addUserEvent(uuidMock(0)));
assertThat(apiController.updateGroups(0L).getGroupList()).hasSize(1); assertThat(apiController.updateGroups(0L).getGroupList()).hasSize(1);
assertThat(apiController.updateGroups(4L).getGroupList()).hasSize(1); assertThat(apiController.updateGroups(4L).getGroupList()).hasSize(1);
assertThat(apiController.updateGroups(10L).getGroupList()).hasSize(0); assertThat(apiController.updateGroups(10L).getGroupList()).hasSize(0);
assertThat(apiController.updateGroups(0L).getStatus()).isEqualTo(5); assertThat(apiController.updateGroups(0L).getStatus()).isEqualTo(6);
} }
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void updateGroup_multipleGroups() { void updateGroup_multipleGroups() {
eventService.saveAll(createPublicGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPublicGroupEvent(uuidMock(0)),
addUserEvent(uuidMock(0)), updateUserLimitMaxEvent(uuidMock(0)),
addUserEvent(uuidMock(0)), addUserEvent(uuidMock(0)),
createPrivateGroupEvent(uuidMock(1)), addUserEvent(uuidMock(0)),
addUserEvent(uuidMock(1)), createPrivateGroupEvent(uuidMock(1)),
addUserEvent(uuidMock(1)), updateUserLimitMaxEvent(uuidMock(1)),
addUserEvent(uuidMock(1))); addUserEvent(uuidMock(1)),
addUserEvent(uuidMock(1)),
addUserEvent(uuidMock(1)));
assertThat(apiController.updateGroups(0L).getGroupList()).hasSize(2); assertThat(apiController.updateGroups(0L).getGroupList()).hasSize(2);
assertThat(apiController.updateGroups(4L).getGroupList()).hasSize(1); assertThat(apiController.updateGroups(4L).getGroupList()).hasSize(1);
assertThat(apiController.updateGroups(6L).getGroupList()).hasSize(1); assertThat(apiController.updateGroups(6L).getGroupList()).hasSize(1);
assertThat(apiController.updateGroups(7L).getGroupList()).hasSize(0); assertThat(apiController.updateGroups(7L).getGroupList()).hasSize(1);
assertThat(apiController.updateGroups(0L).getStatus()).isEqualTo(7); assertThat(apiController.updateGroups(0L).getStatus()).isEqualTo(9);
} }
@Test @Test
@ -97,10 +105,10 @@ class APIControllerTest {
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void getGroupsOfUser_singleGroup() { void getGroupsOfUser_singleGroup() {
eventService.saveAll(createPrivateGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPrivateGroupEvent(uuidMock(0)),
createPrivateGroupEvent(uuidMock(1)), createPrivateGroupEvent(uuidMock(1)),
createPrivateGroupEvent(uuidMock(2)), createPrivateGroupEvent(uuidMock(2)),
addUserEvent(uuidMock(0), "A")); addUserEvent(uuidMock(0), "A"));
assertThat(apiController.getGroupIdsOfUser("A")).hasSize(1); assertThat(apiController.getGroupIdsOfUser("A")).hasSize(1);
} }
@ -108,19 +116,20 @@ class APIControllerTest {
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void getGroupsOfUser_singleGroupDeletedUser() { void getGroupsOfUser_singleGroupDeletedUser() {
eventService.saveAll(createPrivateGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPrivateGroupEvent(uuidMock(0)),
addUserEvent(uuidMock(0), "A"), addUserEvent(uuidMock(0), "A"),
deleteUserEvent(uuidMock(0), "A")); deleteUserEvent(uuidMock(0), "A"));
assertThat(apiController.getGroupIdsOfUser("A")).isEmpty(); assertThat(apiController.getGroupIdsOfUser("A")).isEmpty();
} }
@Disabled
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void getGroupsOfUser_singleDeletedGroup() { void getGroupsOfUser_singleDeletedGroup() {
eventService.saveAll(createPrivateGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPrivateGroupEvent(uuidMock(0)),
addUserEvent(uuidMock(0), "A"), addUserEvent(uuidMock(0), "A"),
deleteGroupEvent(uuidMock(0))); deleteGroupEvent(uuidMock(0)));
assertThat(apiController.getGroupIdsOfUser("A")).isEmpty(); assertThat(apiController.getGroupIdsOfUser("A")).isEmpty();
} }
@ -128,14 +137,14 @@ class APIControllerTest {
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void getGroupsOfUser_multipleGroups() { void getGroupsOfUser_multipleGroups() {
eventService.saveAll(createPrivateGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPrivateGroupEvent(uuidMock(0)),
createPrivateGroupEvent(uuidMock(1)), createPrivateGroupEvent(uuidMock(1)),
createPrivateGroupEvent(uuidMock(2)), createPrivateGroupEvent(uuidMock(2)),
addUserEvent(uuidMock(0), "A"), addUserEvent(uuidMock(0), "A"),
addUserEvent(uuidMock(0), "B"), addUserEvent(uuidMock(0), "B"),
addUserEvent(uuidMock(1), "A"), addUserEvent(uuidMock(1), "A"),
addUserEvent(uuidMock(2), "A"), addUserEvent(uuidMock(2), "A"),
addUserEvent(uuidMock(2), "B")); addUserEvent(uuidMock(2), "B"));
assertThat(apiController.getGroupIdsOfUser("A")).hasSize(3); assertThat(apiController.getGroupIdsOfUser("A")).hasSize(3);
assertThat(apiController.getGroupIdsOfUser("B")).hasSize(2); assertThat(apiController.getGroupIdsOfUser("B")).hasSize(2);
@ -144,13 +153,13 @@ class APIControllerTest {
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void getGroupFromId_noGroup() { void getGroupFromId_noGroup() {
assertThat(apiController.getGroupById(uuidMock(0).toString())).isEqualTo(null); assertThrows(GroupNotFoundException.class, () -> apiController.getGroupById(uuidMock(0).toString()));
} }
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void getGroupFromId_singleGroup() { void getGroupFromId_singleGroup() {
eventService.saveAll(createPrivateGroupEvent(uuidMock(0))); eventStoreService.saveAll(createPrivateGroupEvent(uuidMock(0)));
assertThat(apiController.getGroupById(uuidMock(0).toString()).getId()).isEqualTo(uuidMock(0)); assertThat(apiController.getGroupById(uuidMock(0).toString()).getId()).isEqualTo(uuidMock(0));
} }
@ -158,9 +167,9 @@ class APIControllerTest {
@Test @Test
@WithMockUser(username = "api_user", roles = "api_user") @WithMockUser(username = "api_user", roles = "api_user")
void getGroupFromId_deletedGroup() { void getGroupFromId_deletedGroup() {
eventService.saveAll(createPrivateGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPrivateGroupEvent(uuidMock(0)),
updateGroupTitleEvent(uuidMock(0)), updateGroupTitleEvent(uuidMock(0)),
deleteGroupEvent(uuidMock(0))); deleteGroupEvent(uuidMock(0)));
assertThat(apiController.getGroupById(uuidMock(0).toString()).getTitle()).isEqualTo(null); assertThat(apiController.getGroupById(uuidMock(0).toString()).getTitle()).isEqualTo(null);
} }

View File

@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test;
import static mops.gruppen2.TestBuilder.addUserEvent; import static mops.gruppen2.TestBuilder.addUserEvent;
import static mops.gruppen2.TestBuilder.apply; import static mops.gruppen2.TestBuilder.apply;
import static mops.gruppen2.TestBuilder.createPublicGroupEvent; import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
import static mops.gruppen2.TestBuilder.updateUserLimitMaxEvent;
import static mops.gruppen2.TestBuilder.uuidMock; import static mops.gruppen2.TestBuilder.uuidMock;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -17,9 +18,10 @@ class AddUserEventTest {
@Test @Test
void applyEvent() { void applyEvent() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateLimitEvent = updateUserLimitMaxEvent(uuidMock(0));
Event addEvent = new AddUserEvent(uuidMock(0), "A", "Thomas", "Tom", "tho@mail.de"); Event addEvent = new AddUserEvent(uuidMock(0), "A", "Thomas", "Tom", "tho@mail.de");
Group group = apply(createEvent, addEvent); Group group = apply(createEvent, updateLimitEvent, addEvent);
assertThat(group.getMembers()).hasSize(1); assertThat(group.getMembers()).hasSize(1);
assertThat(group.getMembers().get(0).getGivenname()).isEqualTo("Thomas"); assertThat(group.getMembers().get(0).getGivenname()).isEqualTo("Thomas");
@ -30,11 +32,12 @@ class AddUserEventTest {
@Test @Test
void applyEvent_userAlreadyExists() { void applyEvent_userAlreadyExists() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateLimitEvent = updateUserLimitMaxEvent(uuidMock(0));
Event addEventA = addUserEvent(uuidMock(0), "A"); Event addEventA = addUserEvent(uuidMock(0), "A");
Event addEventB = addUserEvent(uuidMock(0), "B"); Event addEventB = addUserEvent(uuidMock(0), "B");
Event addEventC = addUserEvent(uuidMock(0), "A"); Event addEventC = addUserEvent(uuidMock(0), "A");
Group group = apply(createEvent, addEventA, addEventB); Group group = apply(createEvent, updateLimitEvent, addEventA, addEventB);
assertThrows(UserAlreadyExistsException.class, () -> addEventA.apply(group)); assertThrows(UserAlreadyExistsException.class, () -> addEventA.apply(group));
assertThrows(UserAlreadyExistsException.class, () -> addEventC.apply(group)); assertThrows(UserAlreadyExistsException.class, () -> addEventC.apply(group));
@ -44,7 +47,7 @@ class AddUserEventTest {
@Test @Test
void applyEvent_groupFull() { void applyEvent_groupFull() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event maxSizeEvent = new UpdateUserMaxEvent(uuidMock(0), "A", 2L); Event maxSizeEvent = new UpdateUserLimitEvent(uuidMock(0), "A", 2L);
Event addEventA = addUserEvent(uuidMock(0), "A"); Event addEventA = addUserEvent(uuidMock(0), "A");
Event addEventB = addUserEvent(uuidMock(0), "B"); Event addEventB = addUserEvent(uuidMock(0), "B");
Event addEventC = addUserEvent(uuidMock(0), "C"); Event addEventC = addUserEvent(uuidMock(0), "C");

View File

@ -17,15 +17,13 @@ class CreateGroupEventTest {
"A", "A",
uuidMock(1), uuidMock(1),
GroupType.SIMPLE, GroupType.SIMPLE,
Visibility.PUBLIC, Visibility.PUBLIC);
100L);
Group group = TestBuilder.apply(createEvent); Group group = TestBuilder.apply(createEvent);
assertThat(group.getMembers()).hasSize(0); assertThat(group.getMembers()).hasSize(0);
assertThat(group.getType()).isEqualTo(GroupType.SIMPLE); assertThat(group.getType()).isEqualTo(GroupType.SIMPLE);
assertThat(group.getVisibility()).isEqualTo(Visibility.PUBLIC); assertThat(group.getVisibility()).isEqualTo(Visibility.PUBLIC);
assertThat(group.getUserMaximum()).isEqualTo(100);
assertThat(group.getId()).isEqualTo(uuidMock(0)); assertThat(group.getId()).isEqualTo(uuidMock(0));
assertThat(group.getParent()).isEqualTo(uuidMock(1)); assertThat(group.getParent()).isEqualTo(uuidMock(1));
} }

View File

@ -17,8 +17,7 @@ class DeleteGroupEventTest {
"A", "A",
uuidMock(1), uuidMock(1),
GroupType.SIMPLE, GroupType.SIMPLE,
Visibility.PUBLIC, Visibility.PUBLIC);
100L);
Event deleteEvent = new DeleteGroupEvent(uuidMock(0), "A"); Event deleteEvent = new DeleteGroupEvent(uuidMock(0), "A");
Group group = TestBuilder.apply(createEvent, deleteEvent); Group group = TestBuilder.apply(createEvent, deleteEvent);
@ -26,7 +25,7 @@ class DeleteGroupEventTest {
assertThat(group.getMembers()).isEmpty(); assertThat(group.getMembers()).isEmpty();
assertThat(group.getType()).isEqualTo(null); assertThat(group.getType()).isEqualTo(null);
assertThat(group.getVisibility()).isEqualTo(null); assertThat(group.getVisibility()).isEqualTo(null);
assertThat(group.getUserMaximum()).isEqualTo(0); assertThat(group.getUserLimit()).isEqualTo(0);
assertThat(group.getId()).isEqualTo(uuidMock(0)); assertThat(group.getId()).isEqualTo(uuidMock(0));
assertThat(group.getParent()).isEqualTo(null); assertThat(group.getParent()).isEqualTo(null);
} }

View File

@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test;
import static mops.gruppen2.TestBuilder.addUserEvent; import static mops.gruppen2.TestBuilder.addUserEvent;
import static mops.gruppen2.TestBuilder.createPublicGroupEvent; import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
import static mops.gruppen2.TestBuilder.updateUserLimitMaxEvent;
import static mops.gruppen2.TestBuilder.uuidMock; import static mops.gruppen2.TestBuilder.uuidMock;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -16,10 +17,11 @@ class DeleteUserEventTest {
@Test @Test
void applyEvent() { void applyEvent() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateLimitEvent = updateUserLimitMaxEvent(uuidMock(0));
Event addEvent = addUserEvent(uuidMock(0), "A"); Event addEvent = addUserEvent(uuidMock(0), "A");
Event deleteEvent = new DeleteUserEvent(uuidMock(0), "A"); Event deleteEvent = new DeleteUserEvent(uuidMock(0), "A");
Group group = TestBuilder.apply(createEvent, addEvent, deleteEvent); Group group = TestBuilder.apply(createEvent, updateLimitEvent, addEvent, deleteEvent);
assertThat(group.getMembers()).hasSize(0); assertThat(group.getMembers()).hasSize(0);
} }
@ -27,10 +29,11 @@ class DeleteUserEventTest {
@Test @Test
void applyEvent_userNotFound() { void applyEvent_userNotFound() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateLimitEvent = updateUserLimitMaxEvent(uuidMock(0));
Event addEvent = addUserEvent(uuidMock(0), "A"); Event addEvent = addUserEvent(uuidMock(0), "A");
Event deleteEvent = new DeleteUserEvent(uuidMock(0), "B"); Event deleteEvent = new DeleteUserEvent(uuidMock(0), "B");
Group group = TestBuilder.apply(createEvent, addEvent); Group group = TestBuilder.apply(createEvent, updateLimitEvent, addEvent);
assertThrows(UserNotFoundException.class, () -> deleteEvent.apply(group)); assertThrows(UserNotFoundException.class, () -> deleteEvent.apply(group));
assertThat(group.getMembers()).hasSize(1); assertThat(group.getMembers()).hasSize(1);

View File

@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test;
import static mops.gruppen2.TestBuilder.addUserEvent; import static mops.gruppen2.TestBuilder.addUserEvent;
import static mops.gruppen2.TestBuilder.apply; import static mops.gruppen2.TestBuilder.apply;
import static mops.gruppen2.TestBuilder.createPublicGroupEvent; import static mops.gruppen2.TestBuilder.createPublicGroupEvent;
import static mops.gruppen2.TestBuilder.updateUserLimitMaxEvent;
import static mops.gruppen2.TestBuilder.uuidMock; import static mops.gruppen2.TestBuilder.uuidMock;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
@ -17,10 +18,11 @@ class UpdateRoleEventTest {
@Test @Test
void applyEvent() { void applyEvent() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateLimitEvent = updateUserLimitMaxEvent(uuidMock(0));
Event addEvent = addUserEvent(uuidMock(0), "A"); Event addEvent = addUserEvent(uuidMock(0), "A");
Event updateEvent = new UpdateRoleEvent(uuidMock(0), "A", Role.ADMIN); Event updateEvent = new UpdateRoleEvent(uuidMock(0), "A", Role.ADMIN);
Group group = apply(createEvent, addEvent, updateEvent); Group group = apply(createEvent, updateLimitEvent, addEvent, updateEvent);
assertThat(group.getRoles().get("A")).isEqualTo(Role.ADMIN); assertThat(group.getRoles().get("A")).isEqualTo(Role.ADMIN);
} }
@ -28,10 +30,11 @@ class UpdateRoleEventTest {
@Test @Test
void applyEvent_userNotFound() { void applyEvent_userNotFound() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateLimitEvent = updateUserLimitMaxEvent(uuidMock(0));
Event addEvent = addUserEvent(uuidMock(0), "A"); Event addEvent = addUserEvent(uuidMock(0), "A");
Event updateEvent = new UpdateRoleEvent(uuidMock(0), "B", Role.ADMIN); Event updateEvent = new UpdateRoleEvent(uuidMock(0), "B", Role.ADMIN);
Group group = apply(createEvent, addEvent); Group group = apply(createEvent, updateLimitEvent, addEvent);
assertThrows(UserNotFoundException.class, () -> updateEvent.apply(group)); assertThrows(UserNotFoundException.class, () -> updateEvent.apply(group));
assertThat(group.getRoles().get("A")).isEqualTo(Role.MEMBER); assertThat(group.getRoles().get("A")).isEqualTo(Role.MEMBER);

View File

@ -11,22 +11,22 @@ import static mops.gruppen2.TestBuilder.uuidMock;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
class UpdateUserMaxEventTest { class UpdateUserLimitEventTest {
@Test @Test
void applyEvent() { void applyEvent() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateEvent = new UpdateUserMaxEvent(uuidMock(0), "A", 5L); Event updateEvent = new UpdateUserLimitEvent(uuidMock(0), "A", 5L);
Group group = apply(createEvent, updateEvent); Group group = apply(createEvent, updateEvent);
assertThat(group.getUserMaximum()).isEqualTo(5); assertThat(group.getUserLimit()).isEqualTo(5);
} }
@Test @Test
void applyEvent_badParameter_negative() { void applyEvent_badParameter_negative() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateEvent = new UpdateUserMaxEvent(uuidMock(0), "A", -5L); Event updateEvent = new UpdateUserLimitEvent(uuidMock(0), "A", -5L);
Group group = apply(createEvent); Group group = apply(createEvent);
@ -36,11 +36,11 @@ class UpdateUserMaxEventTest {
@Test @Test
void applyEvent_badParameter_tooSmall() { void applyEvent_badParameter_tooSmall() {
Event createEvent = createPublicGroupEvent(uuidMock(0)); Event createEvent = createPublicGroupEvent(uuidMock(0));
Event updateEventA = new UpdateUserMaxEvent(uuidMock(0), "A", 5L); Event updateEventA = new UpdateUserLimitEvent(uuidMock(0), "A", 5L);
Event addEventA = addUserEvent(uuidMock(0)); Event addEventA = addUserEvent(uuidMock(0));
Event addEventB = addUserEvent(uuidMock(0)); Event addEventB = addUserEvent(uuidMock(0));
Event addEventC = addUserEvent(uuidMock(0)); Event addEventC = addUserEvent(uuidMock(0));
Event updateEventB = new UpdateUserMaxEvent(uuidMock(0), "A", 2L); Event updateEventB = new UpdateUserLimitEvent(uuidMock(0), "A", 2L);
Group group = apply(createEvent, updateEventA, addEventA, addEventB, addEventC); Group group = apply(createEvent, updateEventA, addEventA, addEventB, addEventC);

View File

@ -2,15 +2,7 @@ package mops.gruppen2.service;
import mops.gruppen2.Gruppen2Application; import mops.gruppen2.Gruppen2Application;
import mops.gruppen2.domain.Account; import mops.gruppen2.domain.Account;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.GroupType;
import mops.gruppen2.domain.Role;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.Visibility;
import mops.gruppen2.domain.exception.UserNotFoundException;
import mops.gruppen2.repository.EventRepository; import mops.gruppen2.repository.EventRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@ -18,16 +10,7 @@ import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.IOException; //TODO: Alles in die entsprechenden Klassen sortieren :((((
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Gruppen2Application.class) @SpringBootTest(classes = Gruppen2Application.class)
@Transactional @Transactional
@ -37,23 +20,26 @@ class ControllerServiceTest {
Account account; Account account;
Account account2; Account account2;
Account account3; Account account3;
@Autowired
ControllerService controllerService; ControllerService controllerService;
EventService eventService; @Autowired
UserService userService; EventStoreService eventStoreService;
@Autowired
ValidationService validationService; ValidationService validationService;
@Autowired @Autowired
EventRepository eventRepository; EventRepository eventRepository;
@Autowired
GroupService groupService; GroupService groupService;
@Autowired @Autowired
InviteService inviteService; InviteService inviteService;
@Autowired
SearchService searchService;
@Autowired
ProjectionService projectionService;
/*
@BeforeEach @BeforeEach
void setUp() { void setUp() {
eventService = new EventService(eventRepository);
groupService = new GroupService(eventService, eventRepository);
userService = new UserService(groupService, eventService);
validationService = new ValidationService(userService, groupService);
controllerService = new ControllerService(eventService, userService, validationService, inviteService);
Set<String> roles = new HashSet<>(); Set<String> roles = new HashSet<>();
roles.add("l"); roles.add("l");
account = new Account("ich", "ich@hhu.de", "l", "ichdude", "jap", roles); account = new Account("ich", "ich@hhu.de", "l", "ichdude", "jap", roles);
@ -64,8 +50,8 @@ class ControllerServiceTest {
@Test @Test
void createPublicGroupWithNoParentAndLimitedNumberTest() { void createPublicGroupWithNoParentAndLimitedNumberTest() {
controllerService.createGroup(account, "test", "hi", null, null, null, 20L, null); groupService.createGroup(account, "test", "hi", null, null, null, 20L, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility()); assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
assertEquals(20L, groups.get(0).getUserMaximum()); assertEquals(20L, groups.get(0).getUserMaximum());
@ -74,9 +60,8 @@ class ControllerServiceTest {
@Test @Test
void createPublicGroupWithNoParentAndUnlimitedNumberTest() { void createPublicGroupWithNoParentAndUnlimitedNumberTest() {
controllerService.createGroup(account, "test", "hi", null, null, true, null, null); groupService.createGroup(account, "test", "hi", null, null, true, null, null);
User user = new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()); List<Group> groups = projectionService.projectUserGroups(account.getName());
List<Group> groups = userService.getUserGroups(user);
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility()); assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
assertEquals(100000L, groups.get(0).getUserMaximum()); assertEquals(100000L, groups.get(0).getUserMaximum());
@ -85,9 +70,8 @@ class ControllerServiceTest {
@Test @Test
void createPrivateGroupWithNoParentAndUnlimitedNumberTest() { void createPrivateGroupWithNoParentAndUnlimitedNumberTest() {
controllerService.createGroup(account, "test", "hi", true, null, true, null, null); groupService.createGroup(account, "test", "hi", true, null, true, null, null);
User user = new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()); List<Group> groups = projectionService.projectUserGroups(account.getName());
List<Group> groups = userService.getUserGroups(user);
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility()); assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
assertEquals(100000L, groups.get(0).getUserMaximum()); assertEquals(100000L, groups.get(0).getUserMaximum());
@ -96,9 +80,8 @@ class ControllerServiceTest {
@Test @Test
void createPrivateGroupWithNoParentAndLimitedNumberTest() { void createPrivateGroupWithNoParentAndLimitedNumberTest() {
controllerService.createGroup(account, "test", "hi", true, null, null, 20L, null); groupService.createGroup(account, "test", "hi", true, null, null, 20L, null);
User user = new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail()); List<Group> groups = projectionService.projectUserGroups(account.getName());
List<Group> groups = userService.getUserGroups(user);
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility()); assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
assertEquals(20L, groups.get(0).getUserMaximum()); assertEquals(20L, groups.get(0).getUserMaximum());
@ -107,12 +90,10 @@ class ControllerServiceTest {
@Test @Test
void createPrivateGroupWithParentAndLimitedNumberTest() throws IOException { void createPrivateGroupWithParentAndLimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account2, "test", "hi", null, true, true, null, null, null); groupService.createGroupAsOrga(account2, "test", "hi", false, true, true, 1L, null, null);
User user = new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail()); List<Group> groups1 = projectionService.projectUserGroups(account2.getName());
List<Group> groups1 = userService.getUserGroups(user); groupService.createGroup(account, "test", "hi", true, null, null, 20L, groups1.get(0).getId());
controllerService.createGroup(account, "test", "hi", true, null, null, 20L, groups1.get(0).getId()); List<Group> groups = projectionService.projectUserGroups(account.getName());
User user2 = new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail());
List<Group> groups = userService.getUserGroups(user2);
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility()); assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
assertEquals(20L, groups.get(0).getUserMaximum()); assertEquals(20L, groups.get(0).getUserMaximum());
@ -121,10 +102,10 @@ class ControllerServiceTest {
@Test @Test
void createPublicGroupWithParentAndLimitedNumberTest() throws IOException { void createPublicGroupWithParentAndLimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account2, "test", "hi", null, null, true, null, null, null); groupService.createGroupAsOrga(account2, "test", "hi", false, false, true, 1L, null, null);
List<Group> groups1 = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail())); List<Group> groups1 = projectionService.projectUserGroups(account2.getName());
controllerService.createGroup(account, "test", "hi", null, null, null, 20L, groups1.get(0).getId()); groupService.createGroup(account, "test", "hi", null, null, null, 20L, groups1.get(0).getId());
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility()); assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
assertEquals(20L, groups.get(0).getUserMaximum()); assertEquals(20L, groups.get(0).getUserMaximum());
@ -133,10 +114,10 @@ class ControllerServiceTest {
@Test @Test
void createPublicGroupWithParentAndUnlimitedNumberTest() throws IOException { void createPublicGroupWithParentAndUnlimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account2, "test", "hi", null, null, true, null, null, null); groupService.createGroupAsOrga(account2, "test", "hi", false, false, true, 1L, null, null);
List<Group> groups1 = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail())); List<Group> groups1 = projectionService.projectUserGroups(account2.getName());
controllerService.createGroup(account, "test", "hi", null, true, true, null, groups1.get(0).getId()); groupService.createGroup(account, "test", "hi", null, true, true, null, groups1.get(0).getId());
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility()); assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
assertEquals(100000L, groups.get(0).getUserMaximum()); assertEquals(100000L, groups.get(0).getUserMaximum());
@ -145,10 +126,10 @@ class ControllerServiceTest {
@Test @Test
void createPrivateGroupWithParentAndUnlimitedNumberTest() throws IOException { void createPrivateGroupWithParentAndUnlimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account2, "test", "hi", null, null, true, null, null, null); groupService.createGroupAsOrga(account2, "test", "hi", false, false, true, 1L, null, null);
List<Group> groups1 = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail())); List<Group> groups1 = projectionService.projectUserGroups(account2.getName());
controllerService.createGroup(account, "test", "hi", true, true, true, null, groups1.get(0).getId()); groupService.createGroup(account, "test", "hi", true, true, true, null, groups1.get(0).getId());
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility()); assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
assertEquals(100000L, groups.get(0).getUserMaximum()); assertEquals(100000L, groups.get(0).getUserMaximum());
@ -157,8 +138,8 @@ class ControllerServiceTest {
@Test @Test
void createPublicOrgaGroupWithNoParentAndLimitedNumberTest() throws IOException { void createPublicOrgaGroupWithNoParentAndLimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account, "test", "hi", null, null, null, 20L, null, null); groupService.createGroupAsOrga(account, "test", "hi", false, false, false, 20L, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(GroupType.SIMPLE, groups.get(0).getType()); assertEquals(GroupType.SIMPLE, groups.get(0).getType());
assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility()); assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
@ -168,8 +149,8 @@ class ControllerServiceTest {
@Test @Test
void createPublicOrgaGroupWithNoParentAndUnlimitedNumberTest() throws IOException { void createPublicOrgaGroupWithNoParentAndUnlimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account, "test", "hi", null, null, true, null, null, null); groupService.createGroupAsOrga(account, "test", "hi", false, false, true, 1L, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(GroupType.SIMPLE, groups.get(0).getType()); assertEquals(GroupType.SIMPLE, groups.get(0).getType());
assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility()); assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
@ -179,8 +160,8 @@ class ControllerServiceTest {
@Test @Test
void createPrivateOrgaGroupWithNoParentAndLimitedNumberTest() throws IOException { void createPrivateOrgaGroupWithNoParentAndLimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account, "test", "hi", true, null, null, 20L, null, null); groupService.createGroupAsOrga(account, "test", "hi", true, false, false, 20L, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(GroupType.SIMPLE, groups.get(0).getType()); assertEquals(GroupType.SIMPLE, groups.get(0).getType());
assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility()); assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
@ -190,8 +171,8 @@ class ControllerServiceTest {
@Test @Test
void createPrivateOrgaGroupWithNoParentAndUnlimitedNumberTest() throws IOException { void createPrivateOrgaGroupWithNoParentAndUnlimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account, "test", "hi", true, null, true, null, null, null); groupService.createGroupAsOrga(account, "test", "hi", true, false, true, 1L, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(GroupType.SIMPLE, groups.get(0).getType()); assertEquals(GroupType.SIMPLE, groups.get(0).getType());
assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility()); assertEquals(Visibility.PRIVATE, groups.get(0).getVisibility());
@ -201,8 +182,8 @@ class ControllerServiceTest {
@Test @Test
void createOrgaLectureGroupAndLimitedNumberTest() throws IOException { void createOrgaLectureGroupAndLimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account, "test", "hi", null, true, null, 20L, null, null); groupService.createGroupAsOrga(account, "test", "hi", false, true, false, 20L, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(GroupType.LECTURE, groups.get(0).getType()); assertEquals(GroupType.LECTURE, groups.get(0).getType());
assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility()); assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
@ -212,8 +193,8 @@ class ControllerServiceTest {
@Test @Test
void createOrgaLectureGroupAndUnlimitedNumberTest() throws IOException { void createOrgaLectureGroupAndUnlimitedNumberTest() throws IOException {
controllerService.createGroupAsOrga(account, "test", "hi", null, true, true, null, null, null); groupService.createGroupAsOrga(account, "test", "hi", false, true, true, 1L, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription()); testTitleAndDescription(groups.get(0).getTitle(), groups.get(0).getDescription());
assertEquals(GroupType.LECTURE, groups.get(0).getType()); assertEquals(GroupType.LECTURE, groups.get(0).getType());
assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility()); assertEquals(Visibility.PUBLIC, groups.get(0).getVisibility());
@ -221,53 +202,61 @@ class ControllerServiceTest {
assertNull(groups.get(0).getParent()); assertNull(groups.get(0).getParent());
} }
//TODO: GroupServiceTest
@Disabled
@Test @Test
public void deleteUserTest() { public void deleteUserTest() {
controllerService.createGroup(account, "test", "hi", true, true, true, null, null); groupService.createGroup(account, "test", "hi", true, true, true, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
controllerService.addUser(account2, groups.get(0).getId()); groupService.addUser(account2, groups.get(0).getId());
User user = new User(account.getName(), "", "", ""); User user = new User(account.getName(), "", "", "");
controllerService.deleteUser(account, user, groups.get(0)); groupService.deleteUser(account, user, groups.get(0));
assertTrue(userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())).isEmpty()); assertTrue(projectionService.projectUserGroups(account.getName()).isEmpty());
} }
//TODO: GroupServiceTest
@Disabled
@Test @Test
public void updateRoleAdminTest() { public void updateRoleAdminTest() {
controllerService.createGroup(account, "test", "hi", null, null, true, null, null); groupService.createGroup(account, "test", "hi", null, null, true, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
controllerService.addUser(account2, groups.get(0).getId()); groupService.addUser(account2, groups.get(0).getId());
User user = new User(account.getName(), "", "", ""); User user = new User(account.getName(), "", "", "");
controllerService.updateRole(user, groups.get(0).getId()); groupService.updateRole(user, groups.get(0).getId());
groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); groups = projectionService.projectUserGroups(account.getName());
assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account.getName())); assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account.getName()));
} }
//TODO: GroupServiceTest
@Disabled
@Test @Test
public void updateRoleMemberTest() { public void updateRoleMemberTest() {
controllerService.createGroup(account, "test", "hi", null, null, true, null, null); groupService.createGroup(account, "test", "hi", null, null, true, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
controllerService.addUser(account2, groups.get(0).getId()); groupService.addUser(account2, groups.get(0).getId());
User user = new User(account2.getName(), "", "", ""); User user = new User(account2.getName(), "", "", "");
controllerService.updateRole(user, groups.get(0).getId()); groupService.updateRole(user, groups.get(0).getId());
groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); groups = projectionService.projectUserGroups(account.getName());
assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName())); assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName()));
} }
//TODO: GroupServiceTest
@Test @Test
public void updateRoleNonUserTest() { public void updateRoleNonUserTest() {
controllerService.createGroup(account, "test", "hi", null, null, true, null, null); groupService.createGroup(account, "test", "hi", null, null, true, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
User user = new User(account2.getName(), "", "", ""); User user = new User(account2.getName(), "", "", "");
Throwable exception = assertThrows(UserNotFoundException.class, () -> controllerService.updateRole(user, groups.get(0).getId())); Throwable exception = assertThrows(UserNotFoundException.class, () -> groupService.updateRole(user, groups.get(0).getId()));
assertEquals("404 NOT_FOUND \"Der User wurde nicht gefunden. (class mops.gruppen2.service.ValidationService)\"", exception.getMessage()); assertEquals("404 NOT_FOUND \"Der User wurde nicht gefunden. (class mops.gruppen2.service.ValidationService)\"", exception.getMessage());
} }
//TODO: GroupServiceTest
@Test @Test
public void deleteNonUserTest() { public void deleteNonUserTest() {
controllerService.createGroup(account, "test", "hi", true, null, true, null, null); groupService.createGroup(account, "test", "hi", true, null, true, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
User user = new User(account2.getName(), "", "", ""); User user = new User(account2.getName(), "", "", "");
Throwable exception = assertThrows(UserNotFoundException.class, () -> controllerService.deleteUser(account, user, groups.get(0))); Throwable exception = assertThrows(UserNotFoundException.class, () -> groupService.deleteUser(account, user, groups.get(0)));
assertEquals("404 NOT_FOUND \"Der User wurde nicht gefunden. (class mops.gruppen2.service.ValidationService)\"", exception.getMessage()); assertEquals("404 NOT_FOUND \"Der User wurde nicht gefunden. (class mops.gruppen2.service.ValidationService)\"", exception.getMessage());
} }
@ -276,44 +265,50 @@ class ControllerServiceTest {
assertEquals("hi", description); assertEquals("hi", description);
} }
//TODO: GroupServiceTest
@Disabled
@Test @Test
void passIfLastAdminTest() { void passIfLastAdminTest() {
controllerService.createGroup(account, "test", "hi", null, null, true, null, null); groupService.createGroup(account, "test", "hi", null, null, true, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
controllerService.addUser(account2, groups.get(0).getId()); groupService.addUser(account2, groups.get(0).getId());
User user = new User(account.getName(), "", "", ""); User user = new User(account.getName(), "", "", "");
groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail())); groups = projectionService.projectUserGroups(account2.getName());
controllerService.deleteUser(account, user, groups.get(0)); groupService.deleteUser(account, user, groups.get(0));
groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail())); groups = projectionService.projectUserGroups(account2.getName());
assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName())); assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName()));
} }
//TODO: GroupServiceTest
@Disabled
@Test @Test
void dontPassIfNotLastAdminTest() { void dontPassIfNotLastAdminTest() {
controllerService.createGroup(account, "test", "hi", null, null, true, null, null); groupService.createGroup(account, "test", "hi", null, null, true, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
controllerService.addUser(account2, groups.get(0).getId()); groupService.addUser(account2, groups.get(0).getId());
User user2 = new User(account2.getName(), "", "", ""); User user2 = new User(account2.getName(), "", "", "");
controllerService.updateRole(user2, groups.get(0).getId()); groupService.updateRole(user2, groups.get(0).getId());
controllerService.addUser(account3, groups.get(0).getId()); groupService.addUser(account3, groups.get(0).getId());
controllerService.changeRoleIfLastAdmin(account, groups.get(0)); groupService.changeRoleIfLastAdmin(account, groups.get(0));
User user = new User(account.getName(), "", "", ""); User user = new User(account.getName(), "", "", "");
controllerService.deleteUser(account, user, groups.get(0)); groupService.deleteUser(account, user, groups.get(0));
groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail())); groups = projectionService.projectUserGroups(account2.getName());
assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account3.getName())); assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account3.getName()));
} }
//TODO: GroupServiceTest
@Disabled
@Test @Test
void getVeteranMemberTest() { void getVeteranMemberTest() {
controllerService.createGroup(account, "test", "hi", null, null, true, null, null); groupService.createGroup(account, "test", "hi", null, null, true, null, null);
List<Group> groups = userService.getUserGroups(new User(account.getName(), account.getGivenname(), account.getFamilyname(), account.getEmail())); List<Group> groups = projectionService.projectUserGroups(account.getName());
controllerService.addUser(account2, groups.get(0).getId()); groupService.addUser(account2, groups.get(0).getId());
controllerService.addUser(account3, groups.get(0).getId()); groupService.addUser(account3, groups.get(0).getId());
User user = new User(account.getName(), "", "", ""); User user = new User(account.getName(), "", "", "");
groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail())); groups = projectionService.projectUserGroups(account2.getName());
controllerService.deleteUser(account, user, groups.get(0)); groupService.deleteUser(account, user, groups.get(0));
groups = userService.getUserGroups(new User(account2.getName(), account2.getGivenname(), account2.getFamilyname(), account2.getEmail())); groups = projectionService.projectUserGroups(account2.getName());
assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName())); assertEquals(Role.ADMIN, groups.get(0).getRoles().get(account2.getName()));
assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account3.getName())); assertEquals(Role.MEMBER, groups.get(0).getRoles().get(account3.getName()));
} }*/
} }

View File

@ -1,6 +1,7 @@
package mops.gruppen2.service; package mops.gruppen2.service;
import mops.gruppen2.Gruppen2Application; import mops.gruppen2.Gruppen2Application;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.dto.EventDTO; import mops.gruppen2.domain.dto.EventDTO;
import mops.gruppen2.domain.event.Event; import mops.gruppen2.domain.event.Event;
import mops.gruppen2.repository.EventRepository; import mops.gruppen2.repository.EventRepository;
@ -26,17 +27,18 @@ import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = Gruppen2Application.class) @SpringBootTest(classes = Gruppen2Application.class)
@Transactional @Transactional
@Rollback @Rollback
class EventServiceTest { class EventStoreServiceTest {
@Autowired @Autowired
private EventRepository eventRepository; private EventRepository eventRepository;
private EventService eventService; private EventStoreService eventStoreService;
@Autowired @Autowired
private JdbcTemplate template; private JdbcTemplate template;
@SuppressWarnings("SyntaxError")
@BeforeEach @BeforeEach
void setUp() { void setUp() {
eventService = new EventService(eventRepository); eventStoreService = new EventStoreService(eventRepository);
eventRepository.deleteAll(); eventRepository.deleteAll();
//noinspection SqlResolve //noinspection SqlResolve
template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1"); template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1");
@ -44,22 +46,22 @@ class EventServiceTest {
@Test @Test
void saveEvent() { void saveEvent() {
eventService.saveEvent(createPublicGroupEvent()); eventStoreService.saveEvent(createPublicGroupEvent());
assertThat(eventRepository.findAll()).hasSize(1); assertThat(eventRepository.findAll()).hasSize(1);
} }
@Test @Test
void saveAll() { void saveAll() {
eventService.saveAll(createPrivateGroupEvents(10)); eventStoreService.saveAll(createPrivateGroupEvents(10));
assertThat(eventRepository.findAll()).hasSize(10); assertThat(eventRepository.findAll()).hasSize(10);
} }
@Test @Test
void testSaveAll() { void testSaveAll() {
eventService.saveAll(createPublicGroupEvents(5), eventStoreService.saveAll(createPublicGroupEvents(5),
createPrivateGroupEvents(5)); createPrivateGroupEvents(5));
assertThat(eventRepository.findAll()).hasSize(10); assertThat(eventRepository.findAll()).hasSize(10);
} }
@ -68,7 +70,7 @@ class EventServiceTest {
void getDTO() { void getDTO() {
Event event = createPublicGroupEvent(); Event event = createPublicGroupEvent();
EventDTO dto = eventService.getDTOFromEvent(event); EventDTO dto = EventStoreService.getDTOFromEvent(event);
assertThat(dto.getGroup_id()).isEqualTo(event.getGroupId().toString()); assertThat(dto.getGroup_id()).isEqualTo(event.getGroupId().toString());
assertThat(dto.getUser_id()).isEqualTo(event.getUserId()); assertThat(dto.getUser_id()).isEqualTo(event.getUserId());
@ -78,22 +80,22 @@ class EventServiceTest {
@Test @Test
void getEventsOfGroup() { void getEventsOfGroup() {
eventService.saveAll(addUserEvents(10, uuidMock(0)), eventStoreService.saveAll(addUserEvents(10, uuidMock(0)),
addUserEvents(5, uuidMock(1))); addUserEvents(5, uuidMock(1)));
assertThat(eventService.getEventsOfGroup(uuidMock(0))).hasSize(10); assertThat(eventStoreService.findGroupEvents(uuidMock(0))).hasSize(10);
assertThat(eventService.getEventsOfGroup(uuidMock(1))).hasSize(5); assertThat(eventStoreService.findGroupEvents(uuidMock(1))).hasSize(5);
} }
@Test @Test
void findGroupIdsByUser() { void findGroupIdsByUser() {
eventService.saveAll(addUserEvent(uuidMock(0), "A"), eventStoreService.saveAll(addUserEvent(uuidMock(0), "A"),
addUserEvent(uuidMock(1), "A"), addUserEvent(uuidMock(1), "A"),
addUserEvent(uuidMock(2), "A"), addUserEvent(uuidMock(2), "A"),
addUserEvent(uuidMock(3), "A"), addUserEvent(uuidMock(3), "A"),
addUserEvent(uuidMock(3), "B")); addUserEvent(uuidMock(3), "B"));
assertThat(eventService.findGroupIdsByUser("A")).hasSize(4); assertThat(eventStoreService.findExistingUserGroups(new User("A"))).hasSize(4);
assertThat(eventService.findGroupIdsByUser("B")).hasSize(1); assertThat(eventStoreService.findExistingUserGroups(new User("B"))).hasSize(1);
} }
} }

View File

@ -3,10 +3,12 @@ package mops.gruppen2.service;
import mops.gruppen2.Gruppen2Application; import mops.gruppen2.Gruppen2Application;
import mops.gruppen2.TestBuilder; import mops.gruppen2.TestBuilder;
import mops.gruppen2.domain.Group; import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.User;
import mops.gruppen2.domain.Visibility; import mops.gruppen2.domain.Visibility;
import mops.gruppen2.domain.event.Event; import mops.gruppen2.domain.event.Event;
import mops.gruppen2.repository.EventRepository; import mops.gruppen2.repository.EventRepository;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -20,7 +22,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static mops.gruppen2.TestBuilder.account;
import static mops.gruppen2.TestBuilder.addUserEvent; import static mops.gruppen2.TestBuilder.addUserEvent;
import static mops.gruppen2.TestBuilder.completePrivateGroup; import static mops.gruppen2.TestBuilder.completePrivateGroup;
import static mops.gruppen2.TestBuilder.completePrivateGroups; import static mops.gruppen2.TestBuilder.completePrivateGroups;
@ -43,63 +44,78 @@ class GroupServiceTest {
@Autowired @Autowired
private EventRepository eventRepository; private EventRepository eventRepository;
@Autowired @Autowired
private EventService eventService; SearchService searchService;
private GroupService groupService; private GroupService groupService;
@Autowired @Autowired
private JdbcTemplate template; private JdbcTemplate template;
@Autowired
ProjectionService projectionService;
@Autowired
private EventStoreService eventStoreService;
@Autowired
private ValidationService validationService;
@Autowired
private InviteService inviteService;
@SuppressWarnings("SyntaxError")
@BeforeEach @BeforeEach
void setUp() { void setUp() {
groupService = new GroupService(eventService, eventRepository); groupService = new GroupService(eventStoreService, inviteService);
eventRepository.deleteAll(); eventRepository.deleteAll();
//noinspection SqlResolve //noinspection SqlResolve
template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1"); template.execute("ALTER TABLE event ALTER COLUMN event_id RESTART WITH 1");
} }
//TODO: Wofür ist dieser Test? //TODO: Wofür ist dieser Test?
//TODO: ProjectionServiceTest
@Test @Test
void rightClassForSuccessfulGroup() { void rightClassForSuccessfulGroup() {
List<Event> eventList = completePrivateGroup(1); List<Event> eventList = completePrivateGroup(1);
List<Group> groups = groupService.projectEventList(eventList); List<Group> groups = ProjectionService.projectGroups(eventList);
assertThat(groups.get(0)).isInstanceOf(Group.class); assertThat(groups.get(0)).isInstanceOf(Group.class);
} }
//TODO: ProjectionServiceTest
@Test @Test
void projectEventList_SingleGroup() { void projectEventList_SingleGroup() {
List<Event> eventList = completePrivateGroup(5); List<Event> eventList = completePrivateGroup(5);
List<Group> groups = groupService.projectEventList(eventList); List<Group> groups = ProjectionService.projectGroups(eventList);
assertThat(groups).hasSize(1); assertThat(groups).hasSize(1);
assertThat(groups.get(0).getMembers()).hasSize(5); assertThat(groups.get(0).getMembers()).hasSize(5);
assertThat(groups.get(0).getVisibility()).isEqualTo(Visibility.PRIVATE); assertThat(groups.get(0).getVisibility()).isEqualTo(Visibility.PRIVATE);
} }
//TODO: ProjectionServiceTest
@Test @Test
void projectEventList_MultipleGroups() { void projectEventList_MultipleGroups() {
List<Event> eventList = completePrivateGroups(10, 2); List<Event> eventList = completePrivateGroups(10, 2);
eventList.addAll(completePublicGroups(10, 5)); eventList.addAll(completePublicGroups(10, 5));
List<Group> groups = groupService.projectEventList(eventList); List<Group> groups = ProjectionService.projectGroups(eventList);
assertThat(groups).hasSize(20); assertThat(groups).hasSize(20);
assertThat(groups.stream().map(group -> group.getMembers().size()).reduce(Integer::sum).get()).isEqualTo(70); assertThat(groups.stream().map(group -> group.getMembers().size()).reduce(Integer::sum).get()).isEqualTo(70);
} }
//TODO: EventStoreServiceTest
@Test @Test
void getGroupEvents() { void getGroupEvents() {
eventService.saveAll(createPublicGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPublicGroupEvent(uuidMock(0)),
createPublicGroupEvent(uuidMock(1)), createPublicGroupEvent(uuidMock(1)),
createPrivateGroupEvent(uuidMock(2))); createPrivateGroupEvent(uuidMock(2)));
List<UUID> groupIds = Arrays.asList(uuidMock(0), uuidMock(1)); List<UUID> groupIds = Arrays.asList(uuidMock(0), uuidMock(1));
assertThat(groupService.getGroupEvents(groupIds)).hasSize(2); assertThat(eventStoreService.findGroupEvents(groupIds)).hasSize(2);
assertThat(groupService.getGroupEvents(groupIds).get(0).getGroupId()).isEqualTo(uuidMock(0)); assertThat(eventStoreService.findGroupEvents(groupIds).get(0).getGroupId()).isEqualTo(uuidMock(0));
assertThat(groupService.getGroupEvents(groupIds).get(1).getGroupId()).isEqualTo(uuidMock(1)); assertThat(eventStoreService.findGroupEvents(groupIds).get(1).getGroupId()).isEqualTo(uuidMock(1));
} }
//TODO: ProjectionServiceTest
@Disabled
@Test @Test
void getAllGroupWithVisibilityPublicTestCreateAndDeleteSameGroup() { void getAllGroupWithVisibilityPublicTestCreateAndDeleteSameGroup() {
Event test1 = createPublicGroupEvent(uuidMock(0)); Event test1 = createPublicGroupEvent(uuidMock(0));
@ -109,83 +125,93 @@ class GroupServiceTest {
Group group = TestBuilder.apply(test1, test2); Group group = TestBuilder.apply(test1, test2);
assertThat(group.getType()).isEqualTo(null); assertThat(group.getType()).isEqualTo(null);
assertThat(groupService.getAllGroupWithVisibilityPublic("errer")).isEmpty(); assertThat(projectionService.projectPublicGroups()).isEmpty();
} }
//TODO: ProjectionServiceTest
@Disabled
@Test @Test
void getAllGroupWithVisibilityPublicTestGroupPublic() { void getAllGroupWithVisibilityPublicTestGroupPublic() {
eventService.saveAll(createPublicGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPublicGroupEvent(uuidMock(0)),
deleteGroupEvent(uuidMock(0)), deleteGroupEvent(uuidMock(0)),
createPublicGroupEvent()); createPublicGroupEvent());
assertThat(groupService.getAllGroupWithVisibilityPublic("test1").size()).isEqualTo(1); assertThat(projectionService.projectPublicGroups().size()).isEqualTo(1);
} }
//TODO: ProjectionServiceTest
@Disabled
@Test @Test
void getAllGroupWithVisibilityPublicTestAddSomeEvents() { void getAllGroupWithVisibilityPublicTestAddSomeEvents() {
eventService.saveAll(createPublicGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPublicGroupEvent(uuidMock(0)),
deleteGroupEvent(uuidMock(0)), deleteGroupEvent(uuidMock(0)),
createPublicGroupEvent(), createPublicGroupEvent(),
createPublicGroupEvent(), createPublicGroupEvent(),
createPublicGroupEvent(), createPublicGroupEvent(),
createPrivateGroupEvent()); createPrivateGroupEvent());
assertThat(groupService.getAllGroupWithVisibilityPublic("test1").size()).isEqualTo(3); assertThat(projectionService.projectPublicGroups().size()).isEqualTo(3);
} }
//TODO: ProjectionServiceTest
@Disabled
@Test @Test
void getAllGroupWithVisibilityPublic_UserInGroup() { void getAllGroupWithVisibilityPublic_UserInGroup() {
eventService.saveAll(createPublicGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPublicGroupEvent(uuidMock(0)),
addUserEvent(uuidMock(0), "kobold"), addUserEvent(uuidMock(0), "kobold"),
createPrivateGroupEvent(), createPrivateGroupEvent(),
createPublicGroupEvent()); createPublicGroupEvent());
assertThat(groupService.getAllGroupWithVisibilityPublic("kobold")).hasSize(1); assertThat(projectionService.projectPublicGroups()).hasSize(1);
assertThat(groupService.getAllGroupWithVisibilityPublic("peter")).hasSize(2); assertThat(projectionService.projectPublicGroups()).hasSize(2);
} }
//TODO: ProjectionServiceTest
@Test @Test
void getAllLecturesWithVisibilityPublic() { void getAllLecturesWithVisibilityPublic() {
eventService.saveAll(createLectureEvent(), eventStoreService.saveAll(createLectureEvent(),
createPublicGroupEvent(), createPublicGroupEvent(),
createLectureEvent(), createLectureEvent(),
createLectureEvent(), createLectureEvent(),
createLectureEvent()); createLectureEvent());
assertThat(groupService.getAllLecturesWithVisibilityPublic().size()).isEqualTo(4); assertThat(projectionService.projectLectures().size()).isEqualTo(4);
} }
//TODO: SearchServiceTest
@Test @Test
void findGroupWith_UserMember_AllGroups() { void findGroupWith_UserMember_AllGroups() {
eventService.saveAll(createPublicGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPublicGroupEvent(uuidMock(0)),
addUserEvent(uuidMock(0), "jens"), addUserEvent(uuidMock(0), "jens"),
updateGroupTitleEvent(uuidMock(0)), updateGroupTitleEvent(uuidMock(0)),
updateGroupDescriptionEvent(uuidMock(0))); updateGroupDescriptionEvent(uuidMock(0)));
assertThat(groupService.findGroupWith("", account("jens"))).isEmpty(); assertThat(searchService.searchPublicGroups("", new User("jens"))).isEmpty();
} }
//TODO: SearchServiceTest
@Test @Test
void findGroupWith_UserNoMember_AllGroups() { void findGroupWith_UserNoMember_AllGroups() {
eventService.saveAll(completePublicGroups(10, 0), eventStoreService.saveAll(completePublicGroups(10, 0),
completePrivateGroups(10, 0)); completePrivateGroups(10, 0));
assertThat(groupService.findGroupWith("", account("jens"))).hasSize(10); assertThat(searchService.searchPublicGroups("", new User("jens"))).hasSize(10);
} }
//TODO: SearchServiceTest
@Test @Test
void findGroupWith_FilterGroups() { void findGroupWith_FilterGroups() {
eventService.saveAll(createPublicGroupEvent(uuidMock(0)), eventStoreService.saveAll(createPublicGroupEvent(uuidMock(0)),
updateGroupTitleEvent(uuidMock(0), "KK"), updateGroupTitleEvent(uuidMock(0), "KK"),
updateGroupDescriptionEvent(uuidMock(0), "ABCDE"), updateGroupDescriptionEvent(uuidMock(0), "ABCDE"),
createPublicGroupEvent(uuidMock(1)), createPublicGroupEvent(uuidMock(1)),
updateGroupTitleEvent(uuidMock(1), "ABCDEFG"), updateGroupTitleEvent(uuidMock(1), "ABCDEFG"),
updateGroupDescriptionEvent(uuidMock(1), "KK"), updateGroupDescriptionEvent(uuidMock(1), "KK"),
createPrivateGroupEvent()); createPrivateGroupEvent());
assertThat(groupService.findGroupWith("A", account("jesus"))).hasSize(2); assertThat(searchService.searchPublicGroups("A", new User("jesus"))).hasSize(2);
assertThat(groupService.findGroupWith("F", account("jesus"))).hasSize(1); assertThat(searchService.searchPublicGroups("F", new User("jesus"))).hasSize(1);
assertThat(groupService.findGroupWith("Z", account("jesus"))).hasSize(0); assertThat(searchService.searchPublicGroups("Z", new User("jesus"))).hasSize(0);
} }
} }