diff --git a/src/main/java/mops/gruppen2/domain/event/Event.java b/src/main/java/mops/gruppen2/domain/event/Event.java index d1b484b..eee06b4 100644 --- a/src/main/java/mops/gruppen2/domain/event/Event.java +++ b/src/main/java/mops/gruppen2/domain/event/Event.java @@ -16,19 +16,23 @@ import mops.gruppen2.infrastructure.GroupCache; import java.time.LocalDateTime; import java.util.UUID; +import static com.fasterxml.jackson.annotation.JsonSubTypes.Type; +import static com.fasterxml.jackson.annotation.JsonTypeInfo.As; +import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id; + @Log4j2 -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "class") -@JsonSubTypes({@JsonSubTypes.Type(value = AddMemberEvent.class, name = "ADDMEMBER"), - @JsonSubTypes.Type(value = CreateGroupEvent.class, name = "CREATEGROUP"), - @JsonSubTypes.Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"), - @JsonSubTypes.Type(value = KickMemberEvent.class, name = "KICKMEMBER"), - @JsonSubTypes.Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"), - @JsonSubTypes.Type(value = SetInviteLinkEvent.class, name = "SETLINK"), - @JsonSubTypes.Type(value = SetLimitEvent.class, name = "SETLIMIT"), - @JsonSubTypes.Type(value = SetParentEvent.class, name = "SETPARENT"), - @JsonSubTypes.Type(value = SetTitleEvent.class, name = "SETTITLE"), - @JsonSubTypes.Type(value = SetTypeEvent.class, name = "SETTYPE"), - @JsonSubTypes.Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")}) +@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "class") +@JsonSubTypes({@Type(value = AddMemberEvent.class, name = "ADDMEMBER"), + @Type(value = CreateGroupEvent.class, name = "CREATEGROUP"), + @Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"), + @Type(value = KickMemberEvent.class, name = "KICKMEMBER"), + @Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"), + @Type(value = SetInviteLinkEvent.class, name = "SETLINK"), + @Type(value = SetLimitEvent.class, name = "SETLIMIT"), + @Type(value = SetParentEvent.class, name = "SETPARENT"), + @Type(value = SetTitleEvent.class, name = "SETTITLE"), + @Type(value = SetTypeEvent.class, name = "SETTYPE"), + @Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")}) @Getter @NoArgsConstructor // Lombok needs a default constructor in the base class public abstract class Event { @@ -93,6 +97,7 @@ public abstract class Event { protected abstract void applyEvent(Group group) throws EventException; + @JsonIgnore public abstract String format(); @JsonIgnore diff --git a/src/main/java/mops/gruppen2/domain/service/EventStoreService.java b/src/main/java/mops/gruppen2/domain/service/EventStoreService.java index 84e1912..69500e6 100644 --- a/src/main/java/mops/gruppen2/domain/service/EventStoreService.java +++ b/src/main/java/mops/gruppen2/domain/service/EventStoreService.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import mops.gruppen2.domain.event.Event; import mops.gruppen2.domain.exception.BadPayloadException; +import mops.gruppen2.domain.exception.GroupNotFoundException; import mops.gruppen2.domain.service.helper.JsonHelper; import mops.gruppen2.persistance.EventRepository; import mops.gruppen2.persistance.dto.EventDTO; @@ -12,6 +13,7 @@ import org.springframework.stereotype.Service; import java.sql.Timestamp; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; @Log4j2 @@ -98,7 +100,14 @@ public class EventStoreService { return getEventsFromDTOs(eventStore.findAllEvents()); } - public List findGroupEvents(String groupId) { - return getEventsFromDTOs(eventStore.findGroupEvents(groupId)); + public List findGroupEvents(UUID groupId) { + return getEventsFromDTOs(eventStore.findGroupEvents(groupId.toString())); + } + + public String findGroupPayloads(UUID groupId) { + return eventStore.findGroupPayloads(groupId.toString()).stream() + .map(payload -> payload + "\n") + .reduce((String payloadA, String payloadB) -> payloadA + payloadB) + .orElseThrow(() -> new GroupNotFoundException("Keine Payloads gefunden.")); } } diff --git a/src/main/java/mops/gruppen2/domain/service/helper/CsvHelper.java b/src/main/java/mops/gruppen2/domain/service/helper/CsvHelper.java index c087540..a12dc8a 100644 --- a/src/main/java/mops/gruppen2/domain/service/helper/CsvHelper.java +++ b/src/main/java/mops/gruppen2/domain/service/helper/CsvHelper.java @@ -45,4 +45,20 @@ public final class CsvHelper { return reader.readValues(stream).readAll(); } + + public static String writeCsvUserList(List members) { + StringBuilder builder = new StringBuilder(); + builder.append("id,givenname,familyname,email"); + + members.forEach(user -> builder.append(user.getId()) + .append(",") + .append(user.getGivenname()) + .append(",") + .append(user.getFamilyname()) + .append(",") + .append(user.getEmail()) + .append("\n")); + + return builder.toString(); + } } diff --git a/src/main/java/mops/gruppen2/infrastructure/controller/GroupDetailsController.java b/src/main/java/mops/gruppen2/infrastructure/controller/GroupDetailsController.java index e3f412d..d482a47 100644 --- a/src/main/java/mops/gruppen2/infrastructure/controller/GroupDetailsController.java +++ b/src/main/java/mops/gruppen2/infrastructure/controller/GroupDetailsController.java @@ -14,6 +14,7 @@ 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.http.HttpHeaders; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -25,7 +26,9 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.security.RolesAllowed; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.IOException; import java.util.UUID; @SuppressWarnings("SameReturnValue") @@ -102,11 +105,49 @@ public class GroupDetailsController { Model model, @PathVariable("id") String groupId) { - model.addAttribute("events", eventStoreService.findGroupEvents(groupId)); + model.addAttribute("events", + eventStoreService.findGroupEvents(UUID.fromString(groupId))); return "history"; } + @RolesAllowed({"ROLE_orga", "ROLE_studentin"}) + @GetMapping("details/{id}/export/history") + public void getDetailsExportHistory(HttpServletResponse response, + @PathVariable("id") String groupId) { + + String filename = "eventlog-" + groupId + ".txt"; + + response.setContentType("text/txt"); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename=\"" + filename + "\""); + + try { + response.getWriter().write(eventStoreService.findGroupPayloads(UUID.fromString(groupId))); + } catch (IOException e) { + log.error("Payloads konnten nicht geschrieben werden.", e); + } + } + + @RolesAllowed({"ROLE_orga", "ROLE_studentin"}) + @GetMapping("details/{id}/export/members") + public void getDetailsExportMembers(HttpServletResponse response, + @PathVariable("id") String groupId) { + + String filename = "teilnehmer-" + groupId + ".csv"; + + response.setContentType("text/csv"); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename=\"" + filename + "\""); + + try { + response.getWriter() + .print(CsvHelper.writeCsvUserList(groupCache.group(UUID.fromString(groupId)).getMembers())); + } catch (IOException e) { + log.error("Teilnehmerliste konnte nicht geschrieben werden.", e); + } + } + @RolesAllowed({"ROLE_orga", "ROLE_studentin"}) @GetMapping("/details/{id}/edit") public String getDetailsEdit(KeycloakAuthenticationToken token, @@ -183,6 +224,7 @@ public class GroupDetailsController { Group group = groupCache.group(UUID.fromString(groupId)); ValidationHelper.throwIfNoAdmin(group, principal); + ValidationHelper.throwIfLastAdmin(group, principal); groupService.toggleMemberRole(group, principal, target); diff --git a/src/main/java/mops/gruppen2/persistance/EventRepository.java b/src/main/java/mops/gruppen2/persistance/EventRepository.java index 7abe489..5ce23fb 100644 --- a/src/main/java/mops/gruppen2/persistance/EventRepository.java +++ b/src/main/java/mops/gruppen2/persistance/EventRepository.java @@ -20,4 +20,7 @@ public interface EventRepository extends CrudRepository { @Query("SELECT * FROM event WHERE group_id = :groupid") List findGroupEvents(@Param("groupid") String groupId); + + @Query("SELECT event_payload FROM event WHERE group_id = :groupid") + List findGroupPayloads(@Param("groupid") String groupId); } diff --git a/src/main/resources/templates/edit.html b/src/main/resources/templates/edit.html index c2da10b..853d15d 100644 --- a/src/main/resources/templates/edit.html +++ b/src/main/resources/templates/edit.html @@ -93,10 +93,23 @@ Event-Historie