@ -1,6 +1,5 @@
|
||||
package mops.gruppen2.config;
|
||||
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
@ -16,7 +15,6 @@ import java.util.Collections;
|
||||
|
||||
@Profile("dev")
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@EnableSwagger2
|
||||
public class SwaggerConfig {
|
||||
|
||||
|
@ -11,6 +11,7 @@ import mops.gruppen2.domain.exception.BadArgumentException;
|
||||
import mops.gruppen2.domain.exception.EventException;
|
||||
import mops.gruppen2.domain.exception.IdMismatchException;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@ -31,7 +32,6 @@ import java.util.UUID;
|
||||
@NoArgsConstructor // Lombok needs a default constructor in the base class
|
||||
public abstract class Event {
|
||||
|
||||
|
||||
@JsonProperty("groupid")
|
||||
protected UUID groupid;
|
||||
|
||||
@ -60,7 +60,7 @@ public abstract class Event {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Group apply(Group group) throws EventException {
|
||||
public void apply(Group group, GroupCache cache) throws EventException {
|
||||
log.trace("Event wird angewendet:\t{}", this);
|
||||
|
||||
if (version == 0) {
|
||||
@ -68,23 +68,32 @@ public abstract class Event {
|
||||
}
|
||||
|
||||
checkGroupIdMatch(group.getId());
|
||||
group.update(version);
|
||||
group.updateVersion(version);
|
||||
applyEvent(group);
|
||||
|
||||
return group;
|
||||
updateCache(cache, group);
|
||||
}
|
||||
|
||||
private void checkGroupIdMatch(UUID groupId) throws IdMismatchException {
|
||||
private void checkGroupIdMatch(UUID groupid) throws IdMismatchException {
|
||||
// CreateGroupEvents müssen die Id erst initialisieren
|
||||
if (this instanceof CreateGroupEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!groupid.equals(groupId)) {
|
||||
if (!this.groupid.equals(groupid)) {
|
||||
throw new IdMismatchException("Das Event gehört zu einer anderen Gruppe");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCache(GroupCache cache, Group group) {
|
||||
if (this instanceof CreateGroupEvent) {
|
||||
cache.put(group);
|
||||
}
|
||||
|
||||
if (this instanceof DestroyGroupEvent) {
|
||||
cache.remove(group);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void applyEvent(Group group) throws EventException;
|
||||
|
||||
@JsonIgnore
|
||||
|
@ -10,14 +10,14 @@ import mops.gruppen2.domain.exception.LastAdminException;
|
||||
import mops.gruppen2.domain.exception.NoAccessException;
|
||||
import mops.gruppen2.domain.exception.UserAlreadyExistsException;
|
||||
import mops.gruppen2.domain.exception.UserNotFoundException;
|
||||
import mops.gruppen2.domain.helper.CommonHelper;
|
||||
import mops.gruppen2.domain.helper.ValidationHelper;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Body;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Description;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Link;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||
import mops.gruppen2.domain.service.helper.CommonHelper;
|
||||
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.time.LocalDateTime;
|
||||
@ -73,6 +73,7 @@ public class Group {
|
||||
|
||||
// ####################################### Members ###########################################
|
||||
|
||||
|
||||
public List<User> getMembers() {
|
||||
return SortHelper.sortByMemberRole(new ArrayList<>(memberships.values())).stream()
|
||||
.map(Membership::getUser)
|
||||
@ -210,6 +211,10 @@ public class Group {
|
||||
return type == Type.LECTURE;
|
||||
}
|
||||
|
||||
public boolean hasParent() {
|
||||
return !parent.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
// ######################################## Setters ##########################################
|
||||
|
||||
@ -262,7 +267,7 @@ public class Group {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public void update(long version) throws IdMismatchException {
|
||||
public void updateVersion(long version) throws IdMismatchException {
|
||||
meta = meta.setVersion(version);
|
||||
}
|
||||
|
||||
@ -310,4 +315,8 @@ public class Group {
|
||||
+ (meta == null ? "meta: null" : meta.toString())
|
||||
+ ")";
|
||||
}
|
||||
|
||||
public static Group EMPTY() {
|
||||
return new Group();
|
||||
}
|
||||
}
|
||||
|
@ -56,4 +56,8 @@ public class User {
|
||||
public String format() {
|
||||
return givenname + " " + familyname;
|
||||
}
|
||||
|
||||
public boolean isMember(Group group) {
|
||||
return group.getMembers().contains(this);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.ToString;
|
||||
import lombok.Value;
|
||||
import mops.gruppen2.domain.helper.CommonHelper;
|
||||
import mops.gruppen2.domain.service.helper.CommonHelper;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
@ -3,39 +3,26 @@ package mops.gruppen2.domain.service;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||
import mops.gruppen2.domain.event.AddMemberEvent;
|
||||
import mops.gruppen2.domain.event.CreateGroupEvent;
|
||||
import mops.gruppen2.domain.event.Event;
|
||||
import mops.gruppen2.domain.event.EventType;
|
||||
import mops.gruppen2.domain.event.SetTypeEvent;
|
||||
import mops.gruppen2.domain.exception.BadPayloadException;
|
||||
import mops.gruppen2.domain.exception.InvalidInviteException;
|
||||
import mops.gruppen2.domain.helper.CommonHelper;
|
||||
import mops.gruppen2.domain.helper.JsonHelper;
|
||||
import mops.gruppen2.domain.model.group.Type;
|
||||
import mops.gruppen2.domain.service.helper.JsonHelper;
|
||||
import mops.gruppen2.persistance.EventRepository;
|
||||
import mops.gruppen2.persistance.dto.EventDTO;
|
||||
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;
|
||||
|
||||
import static mops.gruppen2.domain.event.EventType.CREATEGROUP;
|
||||
import static mops.gruppen2.domain.event.EventType.DESTROYGROUP;
|
||||
import static mops.gruppen2.domain.event.EventType.SETLINK;
|
||||
import static mops.gruppen2.domain.event.EventType.SETTYPE;
|
||||
import static mops.gruppen2.domain.helper.CommonHelper.eventTypesToString;
|
||||
import static mops.gruppen2.domain.helper.CommonHelper.uuidsToString;
|
||||
import static mops.gruppen2.domain.service.helper.CommonHelper.eventTypesToString;
|
||||
|
||||
@Log4j2
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@TraceMethodCalls
|
||||
public class EventStoreService {
|
||||
|
||||
private final EventRepository eventStore;
|
||||
@ -77,12 +64,6 @@ public class EventStoreService {
|
||||
//########################################### DTOs ###########################################
|
||||
|
||||
|
||||
private static List<EventDTO> getDTOsFromEvents(List<Event> events) {
|
||||
return events.stream()
|
||||
.map(EventStoreService::getDTOFromEvent)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt aus einem Event Objekt ein EventDTO Objekt.
|
||||
*
|
||||
@ -132,81 +113,6 @@ public class EventStoreService {
|
||||
// ######################################## 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<UUID> findChangedGroups(long status) {
|
||||
List<String> changedGroupIds = eventStore.findGroupIdsWhereEventIdGreaterThanStatus(status);
|
||||
|
||||
log.debug("Seit Event {} haben sich {} Gruppen geändert!", status, changedGroupIds.size());
|
||||
|
||||
return CommonHelper.stringsToUUID(changedGroupIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert Gruppen-Ids von existierenden (ungelöschten) Gruppen.
|
||||
*
|
||||
* @return GruppenIds (UUID) als Liste
|
||||
*/
|
||||
List<UUID> findExistingGroupIds() {
|
||||
List<Event> createEvents = findLatestEventsFromGroupsByType(CREATEGROUP,
|
||||
DESTROYGROUP);
|
||||
|
||||
return createEvents.stream()
|
||||
.filter(event -> event instanceof CreateGroupEvent)
|
||||
.map(Event::getGroupid)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<UUID> findPublicGroupIds() {
|
||||
List<UUID> groups = findExistingGroupIds();
|
||||
List<Event> typeEvents = findLatestEventsFromGroupsByType(SETTYPE);
|
||||
|
||||
typeEvents.removeIf(event -> ((SetTypeEvent) event).getType() == Type.PRIVATE);
|
||||
typeEvents.removeIf(event -> !groups.contains(event.getGroupid()));
|
||||
|
||||
return typeEvents.stream()
|
||||
.map(Event::getGroupid)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<UUID> findLectureGroupIds() {
|
||||
List<UUID> groups = findExistingGroupIds();
|
||||
List<Event> typeEvents = findLatestEventsFromGroupsByType(SETTYPE);
|
||||
|
||||
typeEvents.removeIf(event -> ((SetTypeEvent) event).getType() != Type.LECTURE);
|
||||
typeEvents.removeIf(event -> !groups.contains(event.getGroupid()));
|
||||
|
||||
return typeEvents.stream()
|
||||
.map(Event::getGroupid)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert Gruppen-Ids von existierenden (ungelöschten) Gruppen, in welchen der User teilnimmt.
|
||||
*
|
||||
@ -234,20 +140,6 @@ public class EventStoreService {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public UUID findGroupByLink(String link) {
|
||||
List<Event> groupEvents = findEventsByType(eventTypesToString(SETLINK));
|
||||
|
||||
if (groupEvents.size() > 1) {
|
||||
throw new InvalidInviteException("Es existieren mehrere Gruppen mit demselben Link.");
|
||||
}
|
||||
|
||||
if (groupEvents.isEmpty()) {
|
||||
throw new InvalidInviteException("Link nicht gefunden.");
|
||||
}
|
||||
|
||||
return groupEvents.get(0).getGroupid();
|
||||
}
|
||||
|
||||
|
||||
// #################################### SIMPLE QUERIES #######################################
|
||||
|
||||
@ -262,23 +154,10 @@ public class EventStoreService {
|
||||
return eventStore.findMaxEventId();
|
||||
} catch (NullPointerException e) {
|
||||
log.debug("Keine Events vorhanden!");
|
||||
return 1;
|
||||
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(uuidsToString(groupIds),
|
||||
Arrays.asList(types)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht zu jeder Gruppe das letzte Add- oder DeleteUserEvent heraus, welches den übergebenen User betrifft.
|
||||
*
|
||||
@ -301,4 +180,12 @@ public class EventStoreService {
|
||||
private List<Event> findLatestEventsFromGroupsByType(EventType... types) {
|
||||
return getEventsFromDTOs(eventStore.findLatestEventDTOsPartitionedByGroupByType(Arrays.asList(eventTypesToString(types))));
|
||||
}
|
||||
|
||||
public List<Event> findAllEvents() {
|
||||
return getEventsFromDTOs(eventStore.findAllEvents());
|
||||
}
|
||||
|
||||
public List<Event> findNewEvents(long version, long maxid) {
|
||||
return getEventsFromDTOs(eventStore.findNewEvents(version, maxid));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package mops.gruppen2.domain.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||
import mops.gruppen2.domain.event.AddMemberEvent;
|
||||
import mops.gruppen2.domain.event.CreateGroupEvent;
|
||||
import mops.gruppen2.domain.event.DestroyGroupEvent;
|
||||
@ -16,7 +15,6 @@ import mops.gruppen2.domain.event.SetTitleEvent;
|
||||
import mops.gruppen2.domain.event.SetTypeEvent;
|
||||
import mops.gruppen2.domain.event.UpdateRoleEvent;
|
||||
import mops.gruppen2.domain.exception.EventException;
|
||||
import mops.gruppen2.domain.helper.ValidationHelper;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.model.group.Role;
|
||||
import mops.gruppen2.domain.model.group.Type;
|
||||
@ -26,6 +24,8 @@ import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Link;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@ -37,11 +37,11 @@ import java.util.UUID;
|
||||
* Es werden übergebene Gruppen bearbeitet und dementsprechend Events erzeugt und gespeichert.
|
||||
*/
|
||||
@Log4j2
|
||||
@TraceMethodCalls
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class GroupService {
|
||||
|
||||
private final GroupCache groupCache;
|
||||
private final EventStoreService eventStoreService;
|
||||
|
||||
// ################################# GRUPPE ERSTELLEN ########################################
|
||||
@ -266,7 +266,7 @@ public class GroupService {
|
||||
|
||||
private void applyAndSave(Group group, Event event) throws EventException {
|
||||
event.init(group.version() + 1);
|
||||
event.apply(group);
|
||||
event.apply(group, groupCache);
|
||||
|
||||
eventStoreService.saveEvent(event);
|
||||
}
|
||||
|
@ -1,215 +0,0 @@
|
||||
package mops.gruppen2.domain.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.domain.event.Event;
|
||||
import mops.gruppen2.domain.exception.EventException;
|
||||
import mops.gruppen2.domain.exception.GroupNotFoundException;
|
||||
import mops.gruppen2.domain.helper.CommonHelper;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Liefert verschiedene Projektionen auf Gruppen.
|
||||
* Benötigt ausschließlich den EventStoreService.
|
||||
*/
|
||||
@Log4j2
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ProjectionService {
|
||||
|
||||
private final EventStoreService eventStoreService;
|
||||
|
||||
|
||||
// ################################## STATISCHE PROJEKTIONEN #################################
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
private static Group projectGroupByEvents(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Konstruiert Gruppen aus einer Liste von Events.
|
||||
*
|
||||
* @param events Liste an Events
|
||||
*
|
||||
* @return Liste an Projizierten Gruppen
|
||||
*
|
||||
* @throws EventException Projektionsfehler
|
||||
*/
|
||||
public static List<Group> projectGroupsByEvents(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());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ################################
|
||||
|
||||
|
||||
/**
|
||||
* 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 projectGroupById(UUID groupId) throws GroupNotFoundException {
|
||||
try {
|
||||
List<Event> events = eventStoreService.findGroupEvents(groupId);
|
||||
return projectGroupByEvents(events);
|
||||
} catch (Exception e) {
|
||||
log.error("Gruppe {} wurde nicht gefunden!", groupId.toString(), e);
|
||||
throw new GroupNotFoundException(groupId + ": " + ProjectionService.class);
|
||||
}
|
||||
}
|
||||
|
||||
public Group projectParent(UUID parent) {
|
||||
if (CommonHelper.uuidIsEmpty(parent)) {
|
||||
return new Group();
|
||||
}
|
||||
|
||||
return projectGroupById(parent);
|
||||
}
|
||||
|
||||
public List<Group> projectGroupsByIds(List<UUID> groupids) {
|
||||
List<Event> events = eventStoreService.findGroupEvents(groupids);
|
||||
|
||||
return projectGroupsByEvents(events);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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> projectChangedGroups(long status) {
|
||||
List<UUID> changedids = eventStoreService.findChangedGroups(status);
|
||||
|
||||
return projectGroupsByIds(changedids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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")
|
||||
public List<Group> projectPublicGroups() throws EventException {
|
||||
List<UUID> groupIds = eventStoreService.findPublicGroupIds();
|
||||
|
||||
if (groupIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return projectGroupsByIds(groupIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Projiziert Vorlesungen.
|
||||
* Projektionen enthalten nur Metainformationen: Titel.
|
||||
*
|
||||
* @return Liste von Veranstaltungen
|
||||
*/
|
||||
@Cacheable("groups")
|
||||
public List<Group> projectLectures() {
|
||||
List<UUID> groupIds = eventStoreService.findLectureGroupIds();
|
||||
|
||||
if (groupIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return projectGroupsByIds(groupIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Projiziert Gruppen, in welchen der User aktuell teilnimmt.
|
||||
* Die Gruppen enthalten nur Metainformationen: Titel und Beschreibung.
|
||||
*
|
||||
* @param userid Die Id
|
||||
*
|
||||
* @return Liste aus Gruppen
|
||||
*/
|
||||
@Cacheable("groups")
|
||||
public List<Group> projectUserGroups(String userid) {
|
||||
List<UUID> groupIds = eventStoreService.findExistingUserGroups(userid);
|
||||
|
||||
if (groupIds.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return projectGroupsByIds(groupIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entfernt alle Gruppen, in welchen ein User teilnimmt, aus einer Gruppenliste.
|
||||
*
|
||||
* @param groups Gruppenliste, aus der entfernt wird
|
||||
* @param userid User, welcher teilnimmt
|
||||
*/
|
||||
void removeUserGroups(List<Group> groups, String userid) {
|
||||
List<UUID> userGroups = eventStoreService.findExistingUserGroups(userid);
|
||||
|
||||
groups.removeIf(group -> userGroups.contains(group.getId()));
|
||||
}
|
||||
|
||||
public Group projectGroupByLink(String link) {
|
||||
return projectGroupById(eventStoreService.findGroupByLink(link));
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,21 @@
|
||||
package mops.gruppen2.domain.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.domain.exception.EventException;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.model.group.SortHelper;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Log4j2
|
||||
public class SearchService {
|
||||
|
||||
private final ProjectionService projectionService;
|
||||
|
||||
public SearchService(ProjectionService projectionService) {
|
||||
this.projectionService = projectionService;
|
||||
}
|
||||
private final GroupCache groupCache;
|
||||
|
||||
/**
|
||||
* Filtert alle öffentliche Gruppen nach dem Suchbegriff und gibt diese als sortierte Liste zurück.
|
||||
@ -31,13 +28,11 @@ public class SearchService {
|
||||
*
|
||||
* @throws EventException Projektionsfehler
|
||||
*/
|
||||
@Cacheable("groups")
|
||||
//TODO: search in lectures
|
||||
public List<Group> searchPublicGroups(String search, String principal) {
|
||||
List<Group> groups = projectionService.projectPublicGroups();
|
||||
System.out.println(groups);
|
||||
projectionService.removeUserGroups(groups, principal);
|
||||
System.out.println(groups);
|
||||
SortHelper.sortByGroupType(groups);
|
||||
List<Group> groups = groupCache.publics();
|
||||
|
||||
groups = removeUserGroups(groups, principal);
|
||||
|
||||
if (search.isEmpty()) {
|
||||
return groups;
|
||||
@ -50,4 +45,10 @@ public class SearchService {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<Group> removeUserGroups(List<Group> groups, String principal) {
|
||||
return groups.stream()
|
||||
.filter(group -> !group.isMember(principal))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package mops.gruppen2.domain.helper;
|
||||
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.web.api.GroupRequestWrapper;
|
||||
import mops.gruppen2.infrastructure.api.GroupRequestWrapper;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package mops.gruppen2.domain.helper;
|
||||
package mops.gruppen2.domain.service.helper;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
@ -1,4 +1,4 @@
|
||||
package mops.gruppen2.domain.helper;
|
||||
package mops.gruppen2.domain.service.helper;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
|
@ -1,4 +1,4 @@
|
||||
package mops.gruppen2.domain.helper;
|
||||
package mops.gruppen2.domain.service.helper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
@ -0,0 +1,49 @@
|
||||
package mops.gruppen2.domain.service.helper;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.domain.event.Event;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Liefert verschiedene Projektionen auf Gruppen.
|
||||
* Benötigt ausschließlich den EventStoreService.
|
||||
*/
|
||||
@Log4j2
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class ProjectionHelper {
|
||||
|
||||
public static void project(Map<UUID, Group> groups, List<Event> events, GroupCache cache) {
|
||||
if (events.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.trace(groups);
|
||||
log.trace(events);
|
||||
|
||||
events.forEach(event -> event.apply(getOrCreateGroup(groups, event.getGroupid()), cache));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Gruppe mit der richtigen Id aus der übergebenen Map wieder, existiert diese nicht
|
||||
* wird die Gruppe erstellt und der Map hizugefügt.
|
||||
*
|
||||
* @param groups Map aus GruppenIds und Gruppen
|
||||
* @param groupId Die Id der Gruppe, die zurückgegeben werden soll
|
||||
*
|
||||
* @return Die gesuchte Gruppe
|
||||
*/
|
||||
private static Group getOrCreateGroup(Map<UUID, Group> groups, UUID groupId) {
|
||||
if (!groups.containsKey(groupId)) {
|
||||
groups.put(groupId, new Group());
|
||||
}
|
||||
|
||||
return groups.get(groupId);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package mops.gruppen2.domain.helper;
|
||||
package mops.gruppen2.domain.service.helper;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
@ -0,0 +1,18 @@
|
||||
package mops.gruppen2.infrastructure;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class ApplicationInit {
|
||||
|
||||
private final GroupCache groupCache;
|
||||
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void init() {
|
||||
groupCache.init();
|
||||
}
|
||||
}
|
79
src/main/java/mops/gruppen2/infrastructure/GroupCache.java
Normal file
79
src/main/java/mops/gruppen2/infrastructure/GroupCache.java
Normal file
@ -0,0 +1,79 @@
|
||||
package mops.gruppen2.infrastructure;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import mops.gruppen2.domain.exception.GroupNotFoundException;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.service.EventStoreService;
|
||||
import mops.gruppen2.domain.service.helper.ProjectionHelper;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class GroupCache {
|
||||
|
||||
private final EventStoreService eventStoreService;
|
||||
|
||||
private final Map<UUID, Group> groups = new HashMap<>();
|
||||
|
||||
public void init() {
|
||||
long maxid = eventStoreService.findMaxEventId();
|
||||
ProjectionHelper.project(groups, eventStoreService.findNewEvents(0, maxid), this);
|
||||
}
|
||||
|
||||
public void put(Group group) {
|
||||
groups.put(group.getId(), group);
|
||||
}
|
||||
|
||||
public void remove(Group group) {
|
||||
groups.remove(group.getId());
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
public Group group(UUID groupid) {
|
||||
if (!groups.containsKey(groupid)) {
|
||||
throw new GroupNotFoundException("Gruppe ist nicht im Cache.");
|
||||
}
|
||||
|
||||
return groups.get(groupid);
|
||||
}
|
||||
|
||||
public Group group(String link) {
|
||||
return groups.values().stream()
|
||||
.filter(group -> group.getLink().equals(link))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new GroupNotFoundException("Link nicht im Cache."));
|
||||
}
|
||||
|
||||
public List<Group> userGroups(String userid) {
|
||||
return groups.values().stream()
|
||||
.filter(group -> group.isMember(userid))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
public List<Group> publics() {
|
||||
return groups.values().stream()
|
||||
.filter(Group::isPublic)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
public List<Group> privates() {
|
||||
return groups.values().stream()
|
||||
.filter(Group::isPrivate)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
public List<Group> lectures() {
|
||||
return groups.values().stream()
|
||||
.filter(Group::isLecture)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package mops.gruppen2.web;
|
||||
package mops.gruppen2.infrastructure;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import mops.gruppen2.domain.Account;
|
||||
import mops.gruppen2.domain.model.group.Role;
|
||||
import mops.gruppen2.domain.model.group.Type;
|
||||
@ -9,9 +10,12 @@ import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@ControllerAdvice
|
||||
public class ModelAttributeControllerAdvice {
|
||||
|
||||
private final GroupCache groupCache;
|
||||
|
||||
// Add modelAttributes before each @RequestMapping
|
||||
@ModelAttribute
|
||||
public void modelAttributes(KeycloakAuthenticationToken token,
|
@ -1,4 +1,4 @@
|
||||
package mops.gruppen2.web.api;
|
||||
package mops.gruppen2.infrastructure.api;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
@ -1,4 +1,4 @@
|
||||
package mops.gruppen2.web;
|
||||
package mops.gruppen2.infrastructure.controller;
|
||||
|
||||
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@ -6,12 +6,8 @@ import io.swagger.annotations.ApiParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||
import mops.gruppen2.domain.helper.APIHelper;
|
||||
import mops.gruppen2.domain.helper.CommonHelper;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.service.EventStoreService;
|
||||
import mops.gruppen2.domain.service.ProjectionService;
|
||||
import mops.gruppen2.web.api.GroupRequestWrapper;
|
||||
import mops.gruppen2.domain.service.helper.CommonHelper;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@ -19,7 +15,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Api zum Datenabgleich.
|
||||
@ -31,8 +26,9 @@ import java.util.UUID;
|
||||
@RequestMapping("/gruppen2/api")
|
||||
public class APIController {
|
||||
|
||||
//TODO: redo api
|
||||
|
||||
private final EventStoreService eventStoreService;
|
||||
private final ProjectionService projectionService;
|
||||
|
||||
/**
|
||||
* Erzeugt eine Liste aus Gruppen, welche sich seit einer übergebenen Event-Id geändert haben.
|
||||
@ -40,15 +36,15 @@ 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(),
|
||||
projectionService.projectChangedGroups(eventId));
|
||||
}
|
||||
projectionHelper.projectChangedGroups(eventId));
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Gibt die Gruppen-IDs von Gruppen, in welchen der übergebene Nutzer teilnimmt, zurück.
|
||||
@ -65,13 +61,13 @@ public class APIController {
|
||||
/**
|
||||
* 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 projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
}
|
||||
return projectionHelper.projectGroupById(UUID.fromString(groupId));
|
||||
}*/
|
||||
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
package mops.gruppen2.web;
|
||||
package mops.gruppen2.infrastructure.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||
import mops.gruppen2.domain.helper.CsvHelper;
|
||||
import mops.gruppen2.domain.helper.ValidationHelper;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.model.group.Type;
|
||||
import mops.gruppen2.domain.model.group.User;
|
||||
@ -13,9 +11,10 @@ import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Parent;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||
import mops.gruppen2.domain.service.GroupService;
|
||||
import mops.gruppen2.domain.service.ProjectionService;
|
||||
import mops.gruppen2.domain.service.helper.CsvHelper;
|
||||
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -35,21 +34,20 @@ import javax.validation.Valid;
|
||||
@RequestMapping("/gruppen2")
|
||||
public class GroupCreationController {
|
||||
|
||||
private final GroupCache groupCache;
|
||||
private final GroupService groupService;
|
||||
private final ProjectionService projectionService;
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@GetMapping("/create")
|
||||
public String getCreate(Model model) {
|
||||
|
||||
model.addAttribute("lectures", projectionService.projectLectures());
|
||||
model.addAttribute("lectures", groupCache.lectures());
|
||||
|
||||
return "create";
|
||||
}
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/create")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postCreateOrga(KeycloakAuthenticationToken token,
|
||||
@RequestParam("type") Type type,
|
||||
@RequestParam("parent") @Valid Parent parent,
|
@ -1,19 +1,18 @@
|
||||
package mops.gruppen2.web;
|
||||
package mops.gruppen2.infrastructure.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||
import mops.gruppen2.domain.helper.CsvHelper;
|
||||
import mops.gruppen2.domain.helper.ValidationHelper;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.model.group.User;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Description;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Limit;
|
||||
import mops.gruppen2.domain.model.group.wrapper.Title;
|
||||
import mops.gruppen2.domain.service.GroupService;
|
||||
import mops.gruppen2.domain.service.ProjectionService;
|
||||
import mops.gruppen2.domain.service.helper.CsvHelper;
|
||||
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -36,8 +35,8 @@ import java.util.UUID;
|
||||
@RequestMapping("/gruppen2")
|
||||
public class GroupDetailsController {
|
||||
|
||||
private final GroupCache groupCache;
|
||||
private final GroupService groupService;
|
||||
private final ProjectionService projectionService;
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@GetMapping("/details/{id}")
|
||||
@ -46,10 +45,13 @@ public class GroupDetailsController {
|
||||
@PathVariable("id") String groupId) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
// Parent Badge
|
||||
Group parent = projectionService.projectParent(group.getParent());
|
||||
Group parent = Group.EMPTY();
|
||||
if (group.hasParent()) {
|
||||
parent = groupCache.group(group.getParent());
|
||||
}
|
||||
|
||||
model.addAttribute("group", group);
|
||||
model.addAttribute("parent", parent);
|
||||
@ -64,12 +66,11 @@ public class GroupDetailsController {
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/details/{id}/join")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postDetailsJoin(KeycloakAuthenticationToken token,
|
||||
@PathVariable("id") String groupId) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
if (ValidationHelper.checkIfMember(group, principal)) {
|
||||
return "redirect:/gruppen2/details/" + groupId;
|
||||
@ -82,12 +83,11 @@ public class GroupDetailsController {
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/details/{id}/leave")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postDetailsLeave(KeycloakAuthenticationToken token,
|
||||
@PathVariable("id") String groupId) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
groupService.kickMember(group, principal, principal);
|
||||
|
||||
@ -102,7 +102,7 @@ public class GroupDetailsController {
|
||||
@PathVariable("id") String groupId) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
// Invite Link
|
||||
String actualURL = request.getRequestURL().toString();
|
||||
@ -119,14 +119,15 @@ public class GroupDetailsController {
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/details/{id}/edit/meta")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postDetailsEditMeta(KeycloakAuthenticationToken token,
|
||||
@PathVariable("id") String groupId,
|
||||
@Valid Title title,
|
||||
@Valid Description description) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
System.out.println(group);
|
||||
|
||||
groupService.setTitle(group, principal, title);
|
||||
groupService.setDescription(group, principal, description);
|
||||
@ -136,12 +137,11 @@ public class GroupDetailsController {
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/details/{id}/edit/userlimit")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postDetailsEditUserLimit(KeycloakAuthenticationToken token,
|
||||
@PathVariable("id") String groupId,
|
||||
@Valid Limit limit) {
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
groupService.setLimit(group, principal, limit);
|
||||
|
||||
@ -150,13 +150,12 @@ public class GroupDetailsController {
|
||||
|
||||
@RolesAllowed("ROLE_orga")
|
||||
@PostMapping("/details/{id}/edit/csv")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postDetailsEditCsv(KeycloakAuthenticationToken token,
|
||||
@PathVariable("id") String groupId,
|
||||
@RequestParam(value = "file", required = false) MultipartFile file) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
groupService.addUsersToGroup(group, principal, CsvHelper.readCsvFile(file));
|
||||
|
||||
@ -165,13 +164,12 @@ public class GroupDetailsController {
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/details/{id}/edit/role/{userid}")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postDetailsEditRole(KeycloakAuthenticationToken token,
|
||||
@PathVariable("id") String groupId,
|
||||
@PathVariable("userid") String target) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
ValidationHelper.throwIfNoAdmin(group, principal);
|
||||
|
||||
@ -187,13 +185,12 @@ public class GroupDetailsController {
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/details/{id}/edit/delete/{userid}")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postDetailsEditDelete(KeycloakAuthenticationToken token,
|
||||
@PathVariable("id") String groupId,
|
||||
@PathVariable("userid") String target) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupId));
|
||||
Group group = groupCache.group(UUID.fromString(groupId));
|
||||
|
||||
ValidationHelper.throwIfNoAdmin(group, principal);
|
||||
|
||||
@ -207,12 +204,11 @@ public class GroupDetailsController {
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@PostMapping("/details/{id}/edit/destroy")
|
||||
@CacheEvict(value = "groups", allEntries = true)
|
||||
public String postDetailsEditDestroy(KeycloakAuthenticationToken token,
|
||||
@PathVariable("id") String groupid) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupById(UUID.fromString(groupid));
|
||||
Group group = groupCache.group(UUID.fromString(groupid));
|
||||
|
||||
groupService.deleteGroup(group, principal);
|
||||
|
@ -1,10 +1,10 @@
|
||||
package mops.gruppen2.web;
|
||||
package mops.gruppen2.infrastructure.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.aspect.annotation.TraceMethodCall;
|
||||
import mops.gruppen2.domain.exception.PageNotFoundException;
|
||||
import mops.gruppen2.domain.service.ProjectionService;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
@ -20,22 +20,25 @@ import javax.servlet.http.HttpServletRequest;
|
||||
@Controller
|
||||
public class GruppenfindungController {
|
||||
|
||||
private final ProjectionService projectionService;
|
||||
private final GroupCache groupCache;
|
||||
|
||||
// For convenience
|
||||
//@GetMapping("")
|
||||
//public String redirect() {
|
||||
// return "redirect:/gruppen2";
|
||||
//}
|
||||
@GetMapping("")
|
||||
public String redirect() {
|
||||
return "redirect:/gruppen2";
|
||||
}
|
||||
|
||||
@GetMapping("/login")
|
||||
public String login() {
|
||||
return "redirect:/gruppen2";
|
||||
}
|
||||
|
||||
@TraceMethodCall
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@GetMapping("/gruppen2")
|
||||
public String getIndexPage(KeycloakAuthenticationToken token,
|
||||
Model model) {
|
||||
|
||||
String principal = token.getName();
|
||||
model.addAttribute("groups", projectionService.projectUserGroups(principal));
|
||||
model.addAttribute("groups", groupCache.userGroups(token.getName()));
|
||||
|
||||
return "index";
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package mops.gruppen2.web;
|
||||
package mops.gruppen2.infrastructure.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import mops.gruppen2.aspect.annotation.TraceMethodCalls;
|
||||
import mops.gruppen2.domain.helper.ValidationHelper;
|
||||
import mops.gruppen2.domain.model.group.Group;
|
||||
import mops.gruppen2.domain.model.group.Type;
|
||||
import mops.gruppen2.domain.service.ProjectionService;
|
||||
import mops.gruppen2.domain.service.SearchService;
|
||||
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||
import mops.gruppen2.infrastructure.GroupCache;
|
||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
@ -29,7 +29,7 @@ import java.util.List;
|
||||
@RequestMapping("/gruppen2")
|
||||
public class SearchAndInviteController {
|
||||
|
||||
private final ProjectionService projectionService;
|
||||
private final GroupCache groupCache;
|
||||
private final SearchService searchService;
|
||||
|
||||
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||
@ -62,7 +62,7 @@ public class SearchAndInviteController {
|
||||
@PathVariable("link") String link) {
|
||||
|
||||
String principal = token.getName();
|
||||
Group group = projectionService.projectGroupByLink(link);
|
||||
Group group = groupCache.group(link);
|
||||
|
||||
model.addAttribute("group", group);
|
||||
|
@ -11,43 +11,21 @@ import java.util.List;
|
||||
@Repository
|
||||
public interface EventRepository extends CrudRepository<EventDTO, Long> {
|
||||
|
||||
// ####################################### GROUP IDs #########################################
|
||||
|
||||
/*@Query("SELECT DISTINCT group_id FROM event"
|
||||
+ " 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")
|
||||
List<String> findGroupIdsWhereEventIdGreaterThanStatus(@Param("status") long status);
|
||||
|
||||
// ####################################### EVENT DTOs ########################################
|
||||
|
||||
@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") String... userIds);*/
|
||||
@Query("SELECT * FROM event WHERE event_id > :version AND event_id <= :max")
|
||||
List<EventDTO> findNewEvents(@Param("version") long version,
|
||||
@Param("max") long maxid);
|
||||
|
||||
@Query("SELECT * FROM event"
|
||||
+ " WHERE event_type IN (:types)")
|
||||
List<EventDTO> findEventDTOsByType(@Param("types") List<String> types);
|
||||
@Query("SELECT * FROM event")
|
||||
List<EventDTO> findAllEvents();
|
||||
|
||||
@Query("SELECT * FROM event"
|
||||
+ " WHERE event_type IN (:types) AND group_id IN (:groupIds)")
|
||||
List<EventDTO> findEventDTOsByGroupAndType(@Param("groupIds") List<String> groupIds,
|
||||
@Param("types") List<String> types);
|
||||
|
||||
/*@Query("SELECT * FROM event"
|
||||
+ " WHERE event_type IN (:types) AND user_id = :userId")
|
||||
List<EventDTO> findEventDTOsByUserAndType(@Param("userId") String userId,
|
||||
@Param("types") String... types);*/
|
||||
|
||||
// ################################ 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"
|
||||
|
@ -12,11 +12,6 @@ spring.datasource.password =
|
||||
spring.jpa.database-platform = org.hibernate.dialect.H2Dialect
|
||||
spring.h2.console.enabled = false
|
||||
|
||||
# Security
|
||||
keycloak.auth-server-url = http://localhost:8082/auth
|
||||
hhu_keycloak.token-uri = http://localhost:8082/auth/realms/Gruppen/protocol/openid-connect/token
|
||||
|
||||
|
||||
# Misc
|
||||
server.error.include-stacktrace = always
|
||||
management.endpoints.web.exposure.include = info,health
|
||||
|
@ -10,11 +10,6 @@ spring.datasource.url = jdbc:mysql://dbmysql:3306/gruppen
|
||||
spring.datasource.username = gruppen
|
||||
spring.datasource.password = password
|
||||
|
||||
# Security
|
||||
keycloak.auth-server-url = http://localhost:8082/auth
|
||||
hhu_keycloak.token-uri = http://localhost:8082/auth/realms/Gruppen/protocol/openid-connect/token
|
||||
|
||||
|
||||
# Misc
|
||||
management.endpoints.web.exposure.include = info,health
|
||||
server.error.include-stacktrace = always
|
||||
|
@ -10,10 +10,6 @@ spring.datasource.url = mysql://b4b665d39d0670:cc933ff7@eu
|
||||
spring.datasource.username = b4b665d39d0670
|
||||
spring.datasource.password = cc933ff7
|
||||
|
||||
# Security
|
||||
keycloak.auth-server-url = https://gruppenkeycloak.herokuapp.com/auth
|
||||
hhu_keycloak.token-uri = https://gruppenkeycloak.herokuapp.com/auth/realms/master/protocol/openid-connect/token
|
||||
|
||||
|
||||
# Misc
|
||||
management.endpoints.web.exposure.include = info,health
|
||||
|
@ -11,6 +11,8 @@ spring.profiles.active = dev
|
||||
#keycloak.use-resource-role-mappings = true
|
||||
#keycloak.autodetect-bearer-only = true
|
||||
#keycloak.confidential-port = 443
|
||||
keycloak.auth-server-url = https://gruppenkeycloak.herokuapp.com/auth
|
||||
hhu_keycloak.token-uri = https://gruppenkeycloak.herokuapp.com/auth/realms/master/protocol/openid-connect/token
|
||||
keycloak.principal-attribute = preferred_username
|
||||
keycloak.realm = master
|
||||
keycloak.resource = gruppen-app
|
||||
|
@ -30,7 +30,7 @@ class ControllerTest {
|
||||
public static final ArchRule controllerClassesShouldBeInControllerPackage = classes()
|
||||
.that().areAnnotatedWith(Controller.class)
|
||||
.or().areAnnotatedWith(RestController.class)
|
||||
.should().resideInAPackage("..web");
|
||||
.should().resideInAPackage("..controller");
|
||||
|
||||
@ArchTest
|
||||
public static final ArchRule classesInControllerPackageShouldHaveControllerInName = classes()
|
||||
|
@ -25,11 +25,11 @@ class ServiceTest {
|
||||
@ArchTest
|
||||
public static final ArchRule serviceClassesShouldBeInServicePackage = classes()
|
||||
.that().areAnnotatedWith(Service.class)
|
||||
.should().resideInAPackage("..service..");
|
||||
.should().resideInAPackage("..service");
|
||||
|
||||
@ArchTest
|
||||
public static final ArchRule classesInServicePackageShouldHaveServiceInName = classes()
|
||||
.that().resideInAPackage("..service..")
|
||||
.that().resideInAPackage("..service")
|
||||
.should().haveSimpleNameEndingWith("Service");
|
||||
|
||||
@ArchIgnore
|
||||
|
Reference in New Issue
Block a user