Skip to content

Commit

Permalink
Merge pull request #370 from it-at-m/147-implementierung-von-pflege-u…
Browse files Browse the repository at this point in the history
…ngültige-wahlscheine

147 implementierung von pflege ungültige wahlscheine
  • Loading branch information
MrSebastian authored Jul 22, 2024
2 parents fcb4374 + 53fda32 commit aab731d
Show file tree
Hide file tree
Showing 42 changed files with 1,453 additions and 58 deletions.
17 changes: 16 additions & 1 deletion docs/src/features/basisdaten-service/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Service zur Bereitstellung folgender Basisdaten:
- Wahlvorschläge
- Kopfdaten
- Handbuch
- Ungültige Wahlscheine

Wahlen, Wahlbezirke und Kopfdaten können in der Service-Datenbank gespeichert werden.

Expand All @@ -21,4 +22,18 @@ Folgende Services werden zum Betrieb benötigt:

In dem Service werden Handbücher verwaltet. Je Wahl und Wahlbezirkart kann ein Handbuch hinterlegt werden.

Bei dem Handbuch soll es sich um ein PDF-Dokument handeln.
Bei dem Handbuch soll es sich um ein PDF-Dokument handeln.

## Ungültige Wahlscheine

Für Wahltage können Listen mit ungültigen Wahlscheinen verwaltet werden. Die Übermittlung der Daten erfolgt
im csv-Format. Dieses umfasst eine Headerzeile, gefolgt von den Daten in den Spalten Name, Vorname und Nummer.

## Konfigurationsparameter

Alle Konfigurationsparameter beginnen mit `service.config`

| Name | Beschreibung | Default |
| ---- |---------------------------------------------------| ------- |
| ungueltigewahlscheine.filenamesuffix | Dateinamenssuffix für die ungueltigen Wahlscheine | Ungueltigews.csv |
| manual.filenamesuffix | Dateinamenssuffix für das Handbuch | Handbuch.pdf |
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
id: add authorities basisdaten ungueltige wahlscheine
author: MrSebastian
realm: ${SSO_REALM}
changes:
- addRole:
name: Basisdaten_BUSINESSACTION_GetUngueltigews
clientRole: true
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allBasisdatenAuthorities
role: Basisdaten_BUSINESSACTION_GetUngueltigews
clientId: ${SSO_CLIENT_ID}

- addRole:
name: Basisdaten_BUSINESSACTION_PostUngueltigews
clientRole: true
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allBasisdatenAuthorities
role: Basisdaten_BUSINESSACTION_PostUngueltigews
clientId: ${SSO_CLIENT_ID}

- addRole:
name: Basisdaten_READ_Ungueltigews
clientRole: true
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allBasisdatenAuthorities
role: Basisdaten_READ_Ungueltigews
clientId: ${SSO_CLIENT_ID}

- addRole:
name: Basisdaten_WRITE_Ungueltigews
clientRole: true
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allBasisdatenAuthorities
role: Basisdaten_WRITE_Ungueltigews
clientId: ${SSO_CLIENT_ID}

- addRole:
name: Basisdaten_DELETE_Ungueltigews
clientRole: true
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allBasisdatenAuthorities
role: Basisdaten_DELETE_Ungueltigews
clientId: ${SSO_CLIENT_ID}
3 changes: 2 additions & 1 deletion stack/keycloak/migration/keycloak-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ includes:
- path: add-authorities-eai-wahlvorschlag.yml
- path: add-authorities-eai-wahldaten.yml
- path: add-authorities-basisdaten-handbuch.yml
- path: add-authorities-basisdaten-wahltage.yml
- path: add-authorities-basisdaten-wahltage.yml
- path: add-authorities-basisdaten-ungueltigewahlscheine.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain;

import jakarta.persistence.Column;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Lob;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Entity
@Table(name = "Ungueltigews")
@Getter
@Setter
@EqualsAndHashCode
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UngueltigeWahlscheine {

// ========= //
// Variables //
// ========= //
@EmbeddedId
private WahltagIdUndWahlbezirksart wahltagIdUndWahlbezirksart;

@Column(name = "ungueltigews")
@NotNull
@Lob
private byte[] ungueltigeWahlscheine;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain;

import java.util.Optional;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.repository.CrudRepository;
import org.springframework.security.access.prepost.PreAuthorize;

@PreAuthorize("hasAuthority('Basisdaten_READ_Ungueltigews')")
public interface UngueltigeWahlscheineRepository extends CrudRepository<UngueltigeWahlscheine, WahltagIdUndWahlbezirksart> {

String CACHE = "UNGUELTIGEWS_CACHE";

@Override
Iterable<UngueltigeWahlscheine> findAll();

@Override
@Cacheable(value = CACHE, key = "#p0")
Optional<UngueltigeWahlscheine> findById(WahltagIdUndWahlbezirksart wahltagIdUndWahlbezirksart);

@Override
@CachePut(value = CACHE, key = "#p0.wahltagIdUndWahlbezirksart")
@PreAuthorize("hasAuthority('Basisdaten_WRITE_Ungueltigews')")
<S extends UngueltigeWahlscheine> S save(S ungueltigews);

@Override
@CacheEvict(value = CACHE, key = "#p0")
@PreAuthorize("hasAuthority('Basisdaten_DELETE_Ungueltigews')")
void deleteById(WahltagIdUndWahlbezirksart wahltagIdUndWahlbezirksart);

@Override
@CacheEvict(value = CACHE, key = "#p0.wahltagIdUndWahlbezirksart")
@PreAuthorize("hasAuthority('Basisdaten_DELETE_Ungueltigews')")
void delete(UngueltigeWahlscheine entity);

@Override
@CacheEvict(value = CACHE, allEntries = true)
@PreAuthorize("hasAuthority('Basisdaten_DELETE_Ungueltigews')")
void deleteAll(Iterable<? extends UngueltigeWahlscheine> entities);

@Override
@CacheEvict(value = CACHE, allEntries = true)
@PreAuthorize("hasAuthority('Basisdaten_DELETE_Ungueltigews')")
void deleteAll();
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,14 @@ public class ExceptionConstants {
public static ExceptionDataWrapper POSTHANDBUCH_SPEICHERN_NICHT_ERFOLGREICH = new ExceptionDataWrapper("316",
"postHandbuch: Das speichern des Handbuches war nicht erfolgreich.");

public static ExceptionDataWrapper GETUNGUELTIGEWAHLSCHEINE_PARAMETER_UNVOLLSTAENDIG = new ExceptionDataWrapper("331",
"getUngueltigews: Suchkriterien unvollständig.");
public static ExceptionDataWrapper GETUNGUELTIGEWAHLSCHEINE_KEINE_DATEN = new ExceptionDataWrapper("332",
"Die ungueltigen Wahlscheine konnte nicht geladen werden.");

public static ExceptionDataWrapper POSTUNGUELTIGEWS_PARAMETER_UNVOLLSTAENDIG = new ExceptionDataWrapper("345",
"postUngueltigews: Suchkriterien unvollständig.");
public static ExceptionDataWrapper POSTUNGUELTIGEWS_SPEICHERN_NICHT_ERFOLGREICH = new ExceptionDataWrapper("346",
"postUngueltigews: Das speichern der ungueltigen Wahlscheine war nicht erfolgreich.");

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.common;

import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartHttpServletRequest;

@Component
@Slf4j
public class FileMapper {

public ResponseEntity<byte[]> toResponseEntity(final FileResponseEntityModel fileResponseEntityModel) {
val responseHeaders = new HttpHeaders();
responseHeaders.add(HttpHeaders.CONTENT_TYPE, fileResponseEntityModel.headerContentType());
responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileResponseEntityModel.attachmentFilename());

return new ResponseEntity<>(fileResponseEntityModel.responseBody(), responseHeaders, HttpStatus.OK);
}

public byte[] fromRequest(final MultipartHttpServletRequest request) throws IOException {
val fileName = request.getFileNames().next();
log.debug("using filename > {}", fileName);
val file = request.getFile(fileName);

if (file == null) {
throw new IOException("No file was uploaded");
}

return file.getBytes();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.common;

public record FileResponseEntityModel(byte[] responseBody, String headerContentType, String attachmentFilename) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.common;

public enum WahlbezirkArtDTO {
UWB, BWB
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.handbuch;

import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.common.FileMapper;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.common.FileResponseEntityModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.common.WahlbezirkArtDTO;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.handbuch.HandbuchService;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.rest.model.WlsExceptionDTO;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
Expand All @@ -13,8 +16,6 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -29,6 +30,8 @@
@Slf4j
public class HandbuchController {

private static final String HANDBUCH_FILE_CONTENT_TYPE = "application/pdf";

@Value("${service.config.manual.filenamesuffix:Handbuch.pdf}")
String manualFileNameSuffix;

Expand All @@ -38,6 +41,8 @@ public class HandbuchController {

private final HandbuchDTOMapper handbuchDTOMapper;

private final FileMapper fileMapper;

@GetMapping("{wahltagID}/{wahlbezirksart}")
@Operation(
description = "Abrufen des Handbuches einer Wahl für eine bestimmte Wahlbezirksart",
Expand All @@ -55,7 +60,9 @@ public class HandbuchController {
public ResponseEntity<byte[]> getHandbuch(@PathVariable("wahltagID") String wahltagID,
@PathVariable("wahlbezirksart") WahlbezirkArtDTO wahlbezirkArtDTO) {
val handbuchData = handbuchService.getHandbuch(handbuchDTOMapper.toModel(wahltagID, wahlbezirkArtDTO));
return createPDFResponse(handbuchData, wahlbezirkArtDTO);

val attachmentFilename = wahlbezirkArtDTO + manualFileNameSuffix;
return fileMapper.toResponseEntity(new FileResponseEntityModel(handbuchData, HANDBUCH_FILE_CONTENT_TYPE, attachmentFilename));
}

@PostMapping("{wahltagID}/{wahlbezirksart}")
Expand All @@ -72,31 +79,11 @@ public ResponseEntity<byte[]> getHandbuch(@PathVariable("wahltagID") String wahl
public void setHandbuch(@PathVariable("wahltagID") String wahltagID, @PathVariable("wahlbezirksart") WahlbezirkArtDTO wahlbezirkArtDTO,
final MultipartHttpServletRequest request) {
try {
val handbuchData = getHandbuchFromRequest(request);
val handbuchData = fileMapper.fromRequest(request);
val modelToSet = handbuchDTOMapper.toModel(handbuchDTOMapper.toModel(wahltagID, wahlbezirkArtDTO), handbuchData);
handbuchService.setHandbuch(modelToSet);
} catch (final IOException e) {
throw exceptionFactory.createTechnischeWlsException(ExceptionConstants.POSTHANDBUCH_SPEICHERN_NICHT_ERFOLGREICH);
}
}

private byte[] getHandbuchFromRequest(final MultipartHttpServletRequest request) throws IOException {
val fileName = request.getFileNames().next();
log.debug("using filename > {}", fileName);
val file = request.getFile(fileName);

if (file == null) {
throw new IOException("No file was uploaded");
}

return file.getBytes();
}

private ResponseEntity<byte[]> createPDFResponse(final byte[] responseBody, final WahlbezirkArtDTO wahlbezirkArtDTO) {
val responseHeaders = new HttpHeaders();
responseHeaders.add(HttpHeaders.CONTENT_TYPE, "application/pdf");
responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + wahlbezirkArtDTO + manualFileNameSuffix);

return new ResponseEntity<>(responseBody, responseHeaders, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.handbuch;

import de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.common.WahlbezirkArtDTO;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.handbuch.HandbuchReferenceModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.handbuch.HandbuchWriteModel;
import org.mapstruct.Mapper;
Expand Down

This file was deleted.

Loading

0 comments on commit aab731d

Please sign in to comment.