initial member + event export
This commit is contained in:
@ -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
|
||||
|
@ -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<Event> findGroupEvents(String groupId) {
|
||||
return getEventsFromDTOs(eventStore.findGroupEvents(groupId));
|
||||
public List<Event> 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."));
|
||||
}
|
||||
}
|
||||
|
@ -45,4 +45,20 @@ public final class CsvHelper {
|
||||
|
||||
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.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);
|
||||
|
||||
|
@ -20,4 +20,7 @@ public interface EventRepository extends CrudRepository<EventDTO, Long> {
|
||||
|
||||
@Query("SELECT * FROM event WHERE group_id = :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>
|
||||
</div>
|
||||
<div class="row">
|
||||
<a class="btn btn-primary btn-bar"
|
||||
th:href="@{/gruppen2/details/{id}/history(id=${group.getId()})}">Event-Log</a>
|
||||
|
||||
<!--Spacer-->
|
||||
<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>
|
||||
|
||||
|
Reference in New Issue
Block a user