initial member + event export
This commit is contained in:
@ -16,19 +16,23 @@ import mops.gruppen2.infrastructure.GroupCache;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static com.fasterxml.jackson.annotation.JsonSubTypes.Type;
|
||||||
|
import static com.fasterxml.jackson.annotation.JsonTypeInfo.As;
|
||||||
|
import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "class")
|
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "class")
|
||||||
@JsonSubTypes({@JsonSubTypes.Type(value = AddMemberEvent.class, name = "ADDMEMBER"),
|
@JsonSubTypes({@Type(value = AddMemberEvent.class, name = "ADDMEMBER"),
|
||||||
@JsonSubTypes.Type(value = CreateGroupEvent.class, name = "CREATEGROUP"),
|
@Type(value = CreateGroupEvent.class, name = "CREATEGROUP"),
|
||||||
@JsonSubTypes.Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"),
|
@Type(value = DestroyGroupEvent.class, name = "DESTROYGROUP"),
|
||||||
@JsonSubTypes.Type(value = KickMemberEvent.class, name = "KICKMEMBER"),
|
@Type(value = KickMemberEvent.class, name = "KICKMEMBER"),
|
||||||
@JsonSubTypes.Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"),
|
@Type(value = SetDescriptionEvent.class, name = "SETDESCRIPTION"),
|
||||||
@JsonSubTypes.Type(value = SetInviteLinkEvent.class, name = "SETLINK"),
|
@Type(value = SetInviteLinkEvent.class, name = "SETLINK"),
|
||||||
@JsonSubTypes.Type(value = SetLimitEvent.class, name = "SETLIMIT"),
|
@Type(value = SetLimitEvent.class, name = "SETLIMIT"),
|
||||||
@JsonSubTypes.Type(value = SetParentEvent.class, name = "SETPARENT"),
|
@Type(value = SetParentEvent.class, name = "SETPARENT"),
|
||||||
@JsonSubTypes.Type(value = SetTitleEvent.class, name = "SETTITLE"),
|
@Type(value = SetTitleEvent.class, name = "SETTITLE"),
|
||||||
@JsonSubTypes.Type(value = SetTypeEvent.class, name = "SETTYPE"),
|
@Type(value = SetTypeEvent.class, name = "SETTYPE"),
|
||||||
@JsonSubTypes.Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")})
|
@Type(value = UpdateRoleEvent.class, name = "UPDATEROLE")})
|
||||||
@Getter
|
@Getter
|
||||||
@NoArgsConstructor // Lombok needs a default constructor in the base class
|
@NoArgsConstructor // Lombok needs a default constructor in the base class
|
||||||
public abstract class Event {
|
public abstract class Event {
|
||||||
@ -93,6 +97,7 @@ public abstract class Event {
|
|||||||
|
|
||||||
protected abstract void applyEvent(Group group) throws EventException;
|
protected abstract void applyEvent(Group group) throws EventException;
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public abstract String format();
|
public abstract String format();
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
|
@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import mops.gruppen2.domain.event.Event;
|
import mops.gruppen2.domain.event.Event;
|
||||||
import mops.gruppen2.domain.exception.BadPayloadException;
|
import mops.gruppen2.domain.exception.BadPayloadException;
|
||||||
|
import mops.gruppen2.domain.exception.GroupNotFoundException;
|
||||||
import mops.gruppen2.domain.service.helper.JsonHelper;
|
import mops.gruppen2.domain.service.helper.JsonHelper;
|
||||||
import mops.gruppen2.persistance.EventRepository;
|
import mops.gruppen2.persistance.EventRepository;
|
||||||
import mops.gruppen2.persistance.dto.EventDTO;
|
import mops.gruppen2.persistance.dto.EventDTO;
|
||||||
@ -12,6 +13,7 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@ -98,7 +100,14 @@ public class EventStoreService {
|
|||||||
return getEventsFromDTOs(eventStore.findAllEvents());
|
return getEventsFromDTOs(eventStore.findAllEvents());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Event> findGroupEvents(String groupId) {
|
public List<Event> findGroupEvents(UUID groupId) {
|
||||||
return getEventsFromDTOs(eventStore.findGroupEvents(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."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,4 +45,20 @@ public final class CsvHelper {
|
|||||||
|
|
||||||
return reader.<User>readValues(stream).readAll();
|
return reader.<User>readValues(stream).readAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String writeCsvUserList(List<User> 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import mops.gruppen2.domain.service.helper.CsvHelper;
|
|||||||
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
import mops.gruppen2.domain.service.helper.ValidationHelper;
|
||||||
import mops.gruppen2.infrastructure.GroupCache;
|
import mops.gruppen2.infrastructure.GroupCache;
|
||||||
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -25,7 +26,9 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import javax.annotation.security.RolesAllowed;
|
import javax.annotation.security.RolesAllowed;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@SuppressWarnings("SameReturnValue")
|
@SuppressWarnings("SameReturnValue")
|
||||||
@ -102,11 +105,49 @@ public class GroupDetailsController {
|
|||||||
Model model,
|
Model model,
|
||||||
@PathVariable("id") String groupId) {
|
@PathVariable("id") String groupId) {
|
||||||
|
|
||||||
model.addAttribute("events", eventStoreService.findGroupEvents(groupId));
|
model.addAttribute("events",
|
||||||
|
eventStoreService.findGroupEvents(UUID.fromString(groupId)));
|
||||||
|
|
||||||
return "history";
|
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"})
|
@RolesAllowed({"ROLE_orga", "ROLE_studentin"})
|
||||||
@GetMapping("/details/{id}/edit")
|
@GetMapping("/details/{id}/edit")
|
||||||
public String getDetailsEdit(KeycloakAuthenticationToken token,
|
public String getDetailsEdit(KeycloakAuthenticationToken token,
|
||||||
@ -183,6 +224,7 @@ public class GroupDetailsController {
|
|||||||
Group group = groupCache.group(UUID.fromString(groupId));
|
Group group = groupCache.group(UUID.fromString(groupId));
|
||||||
|
|
||||||
ValidationHelper.throwIfNoAdmin(group, principal);
|
ValidationHelper.throwIfNoAdmin(group, principal);
|
||||||
|
ValidationHelper.throwIfLastAdmin(group, principal);
|
||||||
|
|
||||||
groupService.toggleMemberRole(group, principal, target);
|
groupService.toggleMemberRole(group, principal, target);
|
||||||
|
|
||||||
|
@ -20,4 +20,7 @@ public interface EventRepository extends CrudRepository<EventDTO, Long> {
|
|||||||
|
|
||||||
@Query("SELECT * FROM event WHERE group_id = :groupid")
|
@Query("SELECT * FROM event WHERE group_id = :groupid")
|
||||||
List<EventDTO> findGroupEvents(@Param("groupid") String groupId);
|
List<EventDTO> findGroupEvents(@Param("groupid") String groupId);
|
||||||
|
|
||||||
|
@Query("SELECT event_payload FROM event WHERE group_id = :groupid")
|
||||||
|
List<String> findGroupPayloads(@Param("groupid") String groupId);
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,23 @@
|
|||||||
<span>Event-Historie</span>
|
<span>Event-Historie</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<a class="btn btn-primary btn-bar"
|
||||||
|
th:href="@{/gruppen2/details/{id}/history(id=${group.getId()})}">Event-Log</a>
|
||||||
|
|
||||||
<!--Spacer-->
|
<!--Spacer-->
|
||||||
<span class="col"></span>
|
<span class="col"></span>
|
||||||
|
|
||||||
<a class="btn btn-primary btn-bar" th:href="@{/gruppen2/details/{id}/history(id=${group.getId()})}">Event-Log</a>
|
<a class="btn btn-info btn-bar mr-2"
|
||||||
|
th:href="@{/gruppen2/details/{id}/export/history(id=${group.getId()})}"
|
||||||
|
title="Exportiert die gesamte Event-Historie dieser Gruppe. Kann beim erstellen importiert werden.">
|
||||||
|
Event-Log exportieren
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="btn btn-info btn-bar"
|
||||||
|
th:href="@{/gruppen2/details/{id}/export/members(id=${group.getId()})}"
|
||||||
|
title="Exportiert die Teilnehmerliste. Kann beim erstellen (oder nachträglich) importiert werden.">
|
||||||
|
Teilnehmer exportieren
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user