redo api
This commit is contained in:
@ -82,6 +82,18 @@ public abstract class Event {
|
||||
applyEvent(group);
|
||||
}
|
||||
|
||||
public void apply(Group group) throws EventException {
|
||||
log.trace("Event wird angewendet:\t{}", this);
|
||||
|
||||
if (version == 0) {
|
||||
throw new BadArgumentException("Event wurde nicht initialisiert.");
|
||||
}
|
||||
|
||||
checkGroupIdMatch(group.getId());
|
||||
group.updateVersion(version);
|
||||
applyEvent(group);
|
||||
}
|
||||
|
||||
private void checkGroupIdMatch(UUID groupid) throws IdMismatchException {
|
||||
// CreateGroupEvents müssen die Id erst initialisieren
|
||||
if (this instanceof CreateGroupEvent) {
|
||||
|
@ -5,12 +5,14 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.domain.event.Event;
|
||||
import mops.gruppen2.domain.exception.BadPayloadException;
|
||||
import mops.gruppen2.domain.service.helper.CommonHelper;
|
||||
import mops.gruppen2.domain.service.helper.FileHelper;
|
||||
import mops.gruppen2.persistance.EventRepository;
|
||||
import mops.gruppen2.persistance.dto.EventDTO;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
@ -102,6 +104,14 @@ public class EventStoreService {
|
||||
return getEventsFromDTOs(eventStore.findGroupEvents(groupId.toString()));
|
||||
}
|
||||
|
||||
public List<Event> findGroupEvents(List<UUID> ids) {
|
||||
return ids.stream()
|
||||
.map(id -> eventStore.findGroupEvents(id.toString()))
|
||||
.map(EventStoreService::getEventsFromDTOs)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<String> findGroupPayloads(UUID groupId) {
|
||||
return eventStore.findGroupPayloads(groupId.toString());
|
||||
}
|
||||
@ -109,4 +119,12 @@ public class EventStoreService {
|
||||
public List<EventDTO> findGroupDTOs(UUID groupid) {
|
||||
return eventStore.findGroupEvents(groupid.toString());
|
||||
}
|
||||
|
||||
public List<UUID> findChangedGroups(long eventid) {
|
||||
return CommonHelper.stringsToUUID(eventStore.findChangedGroupIds(eventid));
|
||||
}
|
||||
|
||||
public long findMaxEventId() {
|
||||
return eventStore.findMaxEventId();
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,25 @@ package mops.gruppen2.domain.service.helper;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.infrastructure.api.GroupRequestWrapper;
|
||||
import mops.gruppen2.infrastructure.api.GroupWrapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
//TODO: sinnvolles format
|
||||
@Log4j2
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class APIHelper {
|
||||
|
||||
/*public static GroupRequestWrapper wrap(long status, List<Group> groupList) {
|
||||
return new GroupRequestWrapper(status, groupList);
|
||||
}*/
|
||||
public static GroupRequestWrapper wrap(long status, List<Group> groupList) {
|
||||
return new GroupRequestWrapper(status, wrap(groupList));
|
||||
}
|
||||
|
||||
public static List<GroupWrapper> wrap(List<Group> groups) {
|
||||
return groups.stream()
|
||||
.map(GroupWrapper::new)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,9 @@ import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Log4j2
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@ -13,4 +15,10 @@ public final class CommonHelper {
|
||||
public static boolean uuidIsEmpty(UUID uuid) {
|
||||
return "00000000-0000-0000-0000-000000000000".equals(uuid.toString());
|
||||
}
|
||||
|
||||
public static List<UUID> stringsToUUID(List<String> changedGroupIds) {
|
||||
return changedGroupIds.stream()
|
||||
.map(UUID::fromString)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ import mops.gruppen2.domain.event.Event;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -19,6 +22,22 @@ import java.util.UUID;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class ProjectionHelper {
|
||||
|
||||
|
||||
public static List<Group> project(List<Event> events) {
|
||||
Map<UUID, Group> groups = new HashMap<>();
|
||||
|
||||
if (events.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
log.trace(groups);
|
||||
log.trace(events);
|
||||
|
||||
events.forEach(event -> event.apply(getOrCreateGroup(groups, event.getGroupid())));
|
||||
|
||||
return new ArrayList<>(groups.values());
|
||||
}
|
||||
|
||||
public static void project(Map<UUID, Group> groups, List<Event> events, GroupCache cache) {
|
||||
if (events.isEmpty()) {
|
||||
return;
|
||||
|
@ -1,4 +1,31 @@
|
||||
package mops.gruppen2.infrastructure.api;
|
||||
|
||||
import lombok.Value;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.model.group.Type;
|
||||
import mops.gruppen2.domain.model.group.User;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Value
|
||||
public class GroupWrapper {
|
||||
|
||||
UUID groupid;
|
||||
Type type;
|
||||
UUID parent;
|
||||
String title;
|
||||
String description;
|
||||
List<User> admins;
|
||||
List<User> regulars;
|
||||
|
||||
public GroupWrapper(Group group) {
|
||||
groupid = group.getId();
|
||||
type = group.getType();
|
||||
parent = group.getParent();
|
||||
title = group.getTitle();
|
||||
description = group.getDescription();
|
||||
admins = group.getAdmins();
|
||||
regulars = group.getRegulars();
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,27 @@
|
||||
package mops.gruppen2.infrastructure.controller;
|
||||
|
||||
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.service.EventStoreService;
|
||||
import mops.gruppen2.domain.service.helper.APIHelper;
|
||||
import mops.gruppen2.domain.service.helper.ProjectionHelper;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
import mops.gruppen2.infrastructure.api.GroupRequestWrapper;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Api zum Datenabgleich.
|
||||
*/
|
||||
@ -18,8 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping("/gruppen2/api")
|
||||
public class APIController {
|
||||
|
||||
//TODO: redo api
|
||||
|
||||
private final GroupCache cache;
|
||||
private final EventStoreService eventStoreService;
|
||||
|
||||
/**
|
||||
@ -28,38 +41,41 @@ public class APIController {
|
||||
*
|
||||
* @param eventId Die Event-ID, welche der Anfragesteller beim letzten Aufruf erhalten hat
|
||||
*/
|
||||
/*@GetMapping("/update/{id}")
|
||||
@GetMapping("/update/{id}")
|
||||
@Secured("ROLE_api_user")
|
||||
@ApiOperation("Gibt veränderte Gruppen zurück")
|
||||
public GroupRequestWrapper getApiUpdate(@ApiParam("Letzte gespeicherte EventId des Anfragestellers")
|
||||
@PathVariable("id") long eventId) {
|
||||
|
||||
return APIHelper.wrap(eventStoreService.findMaxEventId(),
|
||||
projectionHelper.projectChangedGroups(eventId));
|
||||
}*/
|
||||
ProjectionHelper.project(eventStoreService.findGroupEvents(eventStoreService.findChangedGroups(eventId))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Gruppen-IDs von Gruppen, in welchen der übergebene Nutzer teilnimmt, zurück.
|
||||
*/
|
||||
/*@GetMapping("/usergroups/{id}")
|
||||
@GetMapping("/usergroups/{id}")
|
||||
@Secured("ROLE_api_user")
|
||||
@ApiOperation("Gibt Gruppen zurück, in welchen ein Nutzer teilnimmt")
|
||||
public List<String> getApiUserGroups(@ApiParam("Nutzer-Id")
|
||||
@PathVariable("id") String userId) {
|
||||
|
||||
return CommonHelper.uuidsToString(eventStoreService.findExistingUserGroups(userId));
|
||||
}*/
|
||||
return cache.userGroups(userId).stream()
|
||||
.map(Group::getId)
|
||||
.map(UUID::toString)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Konstruiert eine einzelne, vollständige Gruppe.
|
||||
*/
|
||||
/*@GetMapping("/group/{id}")
|
||||
@GetMapping("/group/{id}")
|
||||
@Secured("ROLE_api_user")
|
||||
@ApiOperation("Gibt die Gruppe mit der als Parameter mitgegebenden groupId zurück")
|
||||
public Group getApiGroup(@ApiParam("Gruppen-Id der gefordeten Gruppe")
|
||||
@PathVariable("id") String groupId) {
|
||||
|
||||
return projectionHelper.projectGroupById(UUID.fromString(groupId));
|
||||
}*/
|
||||
return cache.group(UUID.fromString(groupId));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,4 +23,10 @@ public interface EventRepository extends CrudRepository<EventDTO, Long> {
|
||||
|
||||
@Query("SELECT event_payload FROM event WHERE group_id = :groupid")
|
||||
List<String> findGroupPayloads(@Param("groupid") String groupId);
|
||||
|
||||
@Query("SELECT MAX(event_id) FROM event")
|
||||
long findMaxEventId();
|
||||
|
||||
@Query("SELECT DISTINCT group_id FROM event WHERE event_id > :eventid")
|
||||
List<String> findChangedGroupIds(@Param("eventid") long eventid);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
<div class="content" th:insert="~{fragments/groups :: groupcontent}"></div>
|
||||
|
||||
|
||||
<!--Dummy Integrationen-->
|
||||
<!--Dummy Integrationen, der Inhalt kommt natürlich aus der Gruppe bzw. von anderen Systemen-->
|
||||
<div class="d-flex flex-row flex-wrap mr-n2 mt-n2">
|
||||
<!--Materialsammlung-->
|
||||
<div th:if="${group.hasMaterial()}" class="content flex-grow-1 mr-2 mt-2">
|
||||
|
@ -1,297 +0,0 @@
|
||||
package mops.gruppen2;
|
||||
|
||||
public class TestBuilder {
|
||||
|
||||
/*private static final Faker faker = new Faker();
|
||||
|
||||
public static Account account(String name) {
|
||||
return new Account(name,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
null);
|
||||
}
|
||||
|
||||
public static Group apply(Group group, Event... events) {
|
||||
for (Event event : events) {
|
||||
event.apply(group);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
public static Group apply(Event... events) {
|
||||
return apply(new Group(), events);
|
||||
}
|
||||
|
||||
*//**
|
||||
* Baut eine UUID.
|
||||
*
|
||||
* @param id Integer id
|
||||
*
|
||||
* @return UUID
|
||||
*//*
|
||||
public static UUID uuidMock(int id) {
|
||||
String idString = String.valueOf(Math.abs(id + 1));
|
||||
return UUID.fromString("00000000-0000-0000-0000-"
|
||||
+ "0".repeat(11 - idString.length())
|
||||
+ idString);
|
||||
}
|
||||
|
||||
*//**
|
||||
* Generiert ein EventLog mit mehreren Gruppen und Usern.
|
||||
*
|
||||
* @param count Gruppenanzahl
|
||||
* @param membercount Mitgliederanzahl pro Gruppe
|
||||
*
|
||||
* @return Eventliste
|
||||
*//*
|
||||
public static List<Event> completePublicGroups(int count, int membercount) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> completePublicGroup(membercount))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> completePrivateGroups(int count, int membercount) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> completePrivateGroup(membercount))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> completePublicGroup(int membercount) {
|
||||
List<Event> eventList = new ArrayList<>();
|
||||
UUID groupId = UUID.randomUUID();
|
||||
|
||||
eventList.add(createPublicGroupEvent(groupId));
|
||||
eventList.add(updateGroupTitleEvent(groupId));
|
||||
eventList.add(updateGroupDescriptionEvent(groupId));
|
||||
eventList.add(new SetLimitEvent(groupId, "fgsadggas", new Limit(Long.MAX_VALUE)));
|
||||
eventList.addAll(addUserEvents(membercount, groupId));
|
||||
|
||||
return eventList;
|
||||
}
|
||||
|
||||
public static List<Event> completePrivateGroup(int membercount) {
|
||||
List<Event> eventList = new ArrayList<>();
|
||||
UUID groupId = UUID.randomUUID();
|
||||
|
||||
eventList.add(createPrivateGroupEvent(groupId));
|
||||
eventList.add(updateGroupTitleEvent(groupId));
|
||||
eventList.add(updateGroupDescriptionEvent(groupId));
|
||||
eventList.add(new SetLimitEvent(groupId, "fgsadggas", new Limit(Long.MAX_VALUE)));
|
||||
eventList.addAll(addUserEvents(membercount, groupId));
|
||||
|
||||
return eventList;
|
||||
}
|
||||
|
||||
public static List<Event> completePublicGroup() {
|
||||
return completePublicGroup(100);
|
||||
}
|
||||
|
||||
public static List<Event> completePrivateGroup() {
|
||||
return completePrivateGroup(100);
|
||||
}
|
||||
|
||||
*//**
|
||||
* Generiert mehrere CreateGroupEvents, 1 <= groupId <= count.
|
||||
*
|
||||
* @param count Anzahl der verschiedenen Gruppen
|
||||
*
|
||||
* @return Eventliste
|
||||
*//*
|
||||
public static List<Event> createPublicGroupEvents(int count) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> createPublicGroupEvent())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> createPrivateGroupEvents(int count) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> createPublicGroupEvent())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> createMixedGroupEvents(int count) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> faker.random().nextInt(0, 1) > 0.5
|
||||
? createPublicGroupEvent()
|
||||
: createPrivateGroupEvent())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<Event> createPrivateGroupEvents(UUID groupId) {
|
||||
return (new ArrayList<>()).addAll(createGroupEvent(groupId)),
|
||||
new SetTypeEvent(groupId);
|
||||
}
|
||||
|
||||
public static Event createPrivateGroupEvent() {
|
||||
return createPrivateGroupEvent(UUID.randomUUID());
|
||||
}
|
||||
|
||||
public static Event createPublicGroupEvent(UUID groupId) {
|
||||
return createGroupEvent(groupId, Type.PUBLIC);
|
||||
}
|
||||
|
||||
public static Event createPublicGroupEvent() {
|
||||
return createPublicGroupEvent(UUID.randomUUID());
|
||||
}
|
||||
|
||||
public static Event createGroupEvent(UUID groupId) {
|
||||
return new CreateGroupEvent(groupId,
|
||||
faker.random().hex(),
|
||||
LocalDateTime.now());
|
||||
}
|
||||
|
||||
public static Event createLectureEvent() {
|
||||
return createLectureEvent(UUID.randomUUID());
|
||||
}
|
||||
|
||||
public static Event createLectureEvent(UUID groupId) {
|
||||
return new CreateGroupEvent(
|
||||
groupId,
|
||||
faker.random().hex(),
|
||||
null,
|
||||
Type.LECTURE
|
||||
);
|
||||
}
|
||||
|
||||
*//**
|
||||
* Generiert mehrere AddUserEvents für eine Gruppe, 1 <= user_id <= count.
|
||||
*
|
||||
* @param count Anzahl der Mitglieder
|
||||
* @param groupId Gruppe, zu welcher geaddet wird
|
||||
*
|
||||
* @return Eventliste
|
||||
*//*
|
||||
public static List<Event> addUserEvents(int count, UUID groupId) {
|
||||
return IntStream.range(0, count)
|
||||
.parallel()
|
||||
.mapToObj(i -> addUserEvent(groupId, String.valueOf(i)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static Event addUserEvent(UUID groupId, String userId) {
|
||||
String firstname = firstname();
|
||||
String lastname = lastname();
|
||||
|
||||
return new AddMemberEvent(
|
||||
groupId,
|
||||
userId,
|
||||
firstname,
|
||||
lastname,
|
||||
firstname + "." + lastname + "@mail.de"
|
||||
);
|
||||
}
|
||||
|
||||
public static Event addUserEvent(UUID groupId) {
|
||||
return addUserEvent(groupId, faker.random().hex());
|
||||
}
|
||||
|
||||
// Am besten einfach nicht benutzen
|
||||
public static List<Event> deleteUserEvents(int count, List<Event> eventList) {
|
||||
List<Event> removeEvents = new ArrayList<>();
|
||||
List<Event> shuffle = eventList.parallelStream()
|
||||
.filter(event -> event instanceof AddMemberEvent)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Collections.shuffle(shuffle);
|
||||
|
||||
for (Event event : shuffle) {
|
||||
removeEvents.add(new KickMemberEvent(event.getGroupid(), event.getTarget()));
|
||||
|
||||
if (removeEvents.size() >= count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return removeEvents;
|
||||
}
|
||||
|
||||
*//**
|
||||
* Erzeugt mehrere DeleteUserEvents, sodass eine Gruppe komplett geleert wird.
|
||||
*
|
||||
* @param group Gruppe welche geleert wird
|
||||
*
|
||||
* @return Eventliste
|
||||
*//*
|
||||
public static List<Event> deleteUserEvents(Group group) {
|
||||
return group.getMemberships().parallelStream()
|
||||
.map(user -> deleteUserEvent(group.getGroupid(), user.getUserId()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static Event deleteUserEvent(UUID groupId, String userId) {
|
||||
return new KickMemberEvent(
|
||||
groupId,
|
||||
userId
|
||||
);
|
||||
}
|
||||
|
||||
public static Event updateGroupDescriptionEvent(UUID groupId) {
|
||||
return updateGroupDescriptionEvent(groupId, quote());
|
||||
}
|
||||
|
||||
public static Event updateGroupDescriptionEvent(UUID groupId, String description) {
|
||||
return new SetDescriptionEvent(
|
||||
groupId,
|
||||
faker.random().hex(),
|
||||
description
|
||||
);
|
||||
}
|
||||
|
||||
public static Event updateGroupTitleEvent(UUID groupId) {
|
||||
return updateGroupTitleEvent(groupId, champion());
|
||||
}
|
||||
|
||||
public static Event updateGroupTitleEvent(UUID groupId, String title) {
|
||||
return new SetTitleEvent(
|
||||
groupId,
|
||||
faker.random().hex(),
|
||||
title
|
||||
);
|
||||
}
|
||||
|
||||
public static Event updateUserLimitMaxEvent(UUID groupId) {
|
||||
return new SetLimitEvent(groupId, firstname(), Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
public static Event updateRoleEvent(UUID groupId, String userId, Role role) {
|
||||
return new UpdateRoleEvent(
|
||||
groupId,
|
||||
userId,
|
||||
role
|
||||
);
|
||||
}
|
||||
|
||||
public static Event deleteGroupEvent(UUID groupId) {
|
||||
return new DestroyGroupEvent(groupId, faker.random().hex());
|
||||
}
|
||||
|
||||
private static String firstname() {
|
||||
return clean(faker.name().firstName());
|
||||
}
|
||||
|
||||
private static String lastname() {
|
||||
return clean(faker.name().lastName());
|
||||
}
|
||||
|
||||
private static String champion() {
|
||||
return clean(faker.leagueOfLegends().champion());
|
||||
}
|
||||
|
||||
private static String quote() {
|
||||
return clean(faker.leagueOfLegends().quote());
|
||||
}
|
||||
|
||||
private static String clean(String string) {
|
||||
return string.replaceAll("['\";,]", "");
|
||||
}*/
|
||||
}
|
Reference in New Issue
Block a user