Skip to content

Commit

Permalink
Merge pull request #458 from it-at-m/148-implementierung-der-pflege-v…
Browse files Browse the repository at this point in the history
…on-wahltermindaten

148 implementierung der pflege von wahltermindaten
  • Loading branch information
MrSebastian authored Oct 11, 2024
2 parents 2552e20 + 2841456 commit 43b559e
Show file tree
Hide file tree
Showing 39 changed files with 2,323 additions and 22 deletions.
73 changes: 72 additions & 1 deletion docs/src/features/basisdaten-service/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,28 @@ Folgende Services werden zum Betrieb benötigt:
- EAI-Service
- Infomanagement-Service

## Datenmodell

```mermaid
classDiagram
Wahltermindaten
Wahlbezirk
Wahlvorschläge
Referendumvorlagen
Kopfdaten
Wahltermindaten --> Wahlbezirk : uses
Wahltermindaten --> Kopfdaten : uses
Wahltermindaten --> Wahlvorschläge : uses
Wahltermindaten --> Referendumvorlagen : uses
class Wahltermindaten {
<<virtual>>
LocalDate wahltag
}
```

## Handbuch

In dem Service werden Handbücher verwaltet. Je Wahl und Wahlbezirkart kann ein Handbuch hinterlegt werden.
Expand All @@ -29,11 +51,60 @@ Bei dem Handbuch soll es sich um ein PDF-Dokument handeln.
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.

## Wahltermindaten

Wahltermindaten sind eine virtuelle Zusammenfassung von Daten zu einem Wahltermin.

Über den Service können diese Daten für einen Wahltag erstellt und gelöscht werden. Die zu erstellenden Daten
werden von dem EAI-Service importiert.

### Ablauf des Imports

```mermaid
sequenceDiagram
box BasisdatenService
participant WahltermindatenService
participant WahltagService
participant AsyncWahltermindatenService
end
box EAIService
participant Basisdaten
participant Wahlvorschlaege
participant Referendumvorlagen
end
WahltermindatenService ->>+ WahltagService: request für Wahltag mit ID
WahltagService -->>- WahltermindatenService: Wahltag
WahltermindatenService ->>+ Basisdaten : request Basisdaten für Wahltag
Basisdaten -->>- WahltermindatenService : Basisdaten
WahltermindatenService ->> WahltermindatenService : Speichere Wahlen aus Basisdaten
WahltermindatenService ->> WahltermindatenService : Speicher Wahlbezirke der Basisdaten
WahltermindatenService ->> WahltermindatenService : Speicher Kopfdaten der Basisdaten
WahltermindatenService -->> AsyncWahltermindatenService : Starte Initialisierung der<br>Wahlvorschläge und Referendumvorlagen
AsyncWahltermindatenService ->>+ Wahlvorschlaege : lade request Wahlvorschläge für Bezirke der Wahlen
Wahlvorschlaege -->>- AsyncWahltermindatenService : Wahlvorschläge
AsyncWahltermindatenService ->> AsyncWahltermindatenService : speichere Wahlvorschläge
AsyncWahltermindatenService ->>+ Referendumvorlagen : request Referendumvorlagen für Bezirke der Wahlen
Referendumvorlagen -->>- AsyncWahltermindatenService : Referendumvorlagen
AsyncWahltermindatenService ->> AsyncWahltermindatenService : speichere Referendumvorlagen
```

## 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 |
| manual.filenamesuffix | Dateinamenssuffix für das Handbuch | Handbuch.pdf |
| async.corePoolSize | core Poolsize von ThreadPoolTaskExecutor | 2 |
| async.maxPoolSize | max Poolsize von ThreadPoolTaskExecutor | 2 |
| async.queueCapacity | Kapazität für Queue von ThreadPoolTaskExecutor | 500 |
| async.threadNamePrefix | Prefix für Threads von ThreadPoolTaskExecutor | taskExecutor- |
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
id: add authorities basisdaten wahltermindaten
author: MrSebastian
realm: ${SSO_REALM}
changes:
- addRole:
name: Basisdaten_BUSINESSACTION_PutWahltermindaten
clientRole: true
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allBasisdatenAuthorities
role: Basisdaten_BUSINESSACTION_PutWahltermindaten
clientId: ${SSO_CLIENT_ID}

- addRole:
name: Basisdaten_BUSINESSACTION_DeleteWahltermindaten
clientRole: true
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allBasisdatenAuthorities
role: Basisdaten_BUSINESSACTION_DeleteWahltermindaten
clientId: ${SSO_CLIENT_ID}
1 change: 1 addition & 0 deletions stack/keycloak/migration/keycloak-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ includes:
- path: create-group-all-vorfaelleundvorkommnisse-authorities.yml
- path: add-authorities-vorfaelleundvorkommnisse.yml
- path: add-authorities-eai-ergebnismeldung.yml
- path: add-authorities-basisdaten-wahltermindaten.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahlart;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.StimmzettelgebietsartModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahlbezirkArtModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisdatenModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisstrukturdatenModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.KonfigurierterWahltagClient;
Expand All @@ -24,7 +25,6 @@
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlbezirke.WahlbezirkeClient;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlenClient;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltagModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltageClient;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.KandidatModel;
Expand Down Expand Up @@ -77,9 +77,11 @@ public List<WahlModel> getWahlen(final WahltagWithNummer wahltagWithNummer) thro
@Override
public ReferendumvorlagenModel getReferendumvorlagen(ReferendumvorlagenReferenceModel referendumvorlagenReferenceModel) {
return new ReferendumvorlagenModel("stimmzettelgebietID", Set.of(new ReferendumvorlageModel("wahlvorschlagID1", 1L, "kurzname1", "frage1",
Set.of(new ReferendumoptionModel("optionID11", "option11", 1L), new ReferendumoptionModel("optionID12", "option12", 2L))),
Set.of(new ReferendumoptionModel("optionID11" + UUID.randomUUID(), "option11", 1L),
new ReferendumoptionModel("optionID12" + UUID.randomUUID(), "option12", 2L))),
new ReferendumvorlageModel("wahlvorschlagID2", 2L, "kurzname2", "frage2",
Set.of(new ReferendumoptionModel("optionID21", "option21", 1L), new ReferendumoptionModel("optionID22", "option22", 2L)))));
Set.of(new ReferendumoptionModel("optionID21" + UUID.randomUUID(), "option21", 1L),
new ReferendumoptionModel("optionID22" + UUID.randomUUID(), "option22", 2L)))));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.client.WahldatenControllerApi;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.BasisdatenDTO;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.BasisdatenModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten.WahldatenClient;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.WlsException;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.client.WahldatenControllerApi;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlDTO;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlenClient;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
import java.util.List;
import java.util.Set;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.configuration;

import lombok.val;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor;

@EnableAsync
@Configuration
public class AsyncConfiguration {

@Value("${app.async.corePoolSize}")
public int corePoolSize;

@Value("${app.async.maxPoolSize}")
public int maxPoolSize;

@Value("${app.async.queueCapacity}")
public int queueCapacity;

@Value("${app.async.threadNamePrefix}")
public String threadNamePrefix;

@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
val executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(threadNamePrefix);
executor.initialize();
return executor;
}

@Bean
public DelegatingSecurityContextAsyncTaskExecutor taskExecutor(final ThreadPoolTaskExecutor threadPoolTaskExecutor) {
return new DelegatingSecurityContextAsyncTaskExecutor(threadPoolTaskExecutor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@ public interface ReferendumvorlagenRepository extends CrudRepository<Referendumv
@CacheEvict(value = CACHE, allEntries = true)
@PreAuthorize("hasAuthority('Basisdaten_DELETE_Referendumvorlagen')")
void deleteAll();

@PreAuthorize("hasAuthority('Basisdaten_DELETE_Referendumvorlagen')")
void deleteAllByBezirkUndWahlID_WahlID(String wahlID);
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,6 @@ public interface WahlvorschlaegeRepository extends CrudRepository<Wahlvorschlaeg
@PreAuthorize("hasAuthority('Basisdaten_DELETE_WLSWahlvorschlaege')")
void deleteAll();

@PreAuthorize("hasAuthority('Basisdaten_DELETE_WLSWahlvorschlaege')")
void deleteAllByBezirkUndWahlID_WahlID(String wahlID);
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,17 @@ public class ExceptionConstants {
"BasisdatenValidierung: Es gab Inkonsistenzen in den Bestandteilen der Basisdaten. Basisstrukturdaten, Wahlen, Wahlbezirke, Stimmzettelgebiete konnten nicht eindeutig einander zugeordnetwerden.");
public static final ExceptionDataWrapper GETWAHLBEZIRKE_NO_DATA = new ExceptionDataWrapper(CODE_NO_DATA_WAHLBEZIRK,
"Es wurden keine Wahlbezirke gefunden.");

public static ExceptionDataWrapper CODE_PUTWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG = new ExceptionDataWrapper("319",
"putWahltermindaten: Suchkriterien unvollständig.");
public static ExceptionDataWrapper CODE_DELETEWAHLTERMINDATEN_PARAMETER_UNVOLLSTAENDIG = new ExceptionDataWrapper("306",
"deleteWahltermindaten: Suchkriterien unvollständig.");
public static ExceptionDataWrapper CODE_PUTWAHLTERMINDATEN_NO_WAHLTAG = new ExceptionDataWrapper("320",
"putWahltermindaten: Es wurde kein Wahltag zu dieser WahltagID gefunden. Bitte überprüfen sie Konfiguration im Remote-System nach der EAI.");
public static ExceptionDataWrapper CODE_DELETEWAHLTERMINDATEN_LOESCHEN_UNVOLLSTAENDIG = new ExceptionDataWrapper("307",
"deleteWahltermindaten: Die Wahltermindaten konnten aufgrund eines Fehlers nicht vollstaendig geloescht werden.");

public static final ExceptionDataWrapper GET_BASISDATEN_NO_DATA = new ExceptionDataWrapper("401",
"Es wurden keine Basisdaten gefunden.");

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

import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WlsExceptionDTO;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltermindaten.WahltermindatenService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/businessActions/")
@RequiredArgsConstructor
@Slf4j
public class WahltermindatenController {

private final WahltermindatenService wahltermindatenService;

@Operation(
description = "Triggert die Einrichtung der Wahltermindaten.",
responses = {
@ApiResponse(
responseCode = "200", description = "Die Wahltermindaten werden angelegt."
),
@ApiResponse(
responseCode = "400", description = "Es gibt keine Wahltag zu der ID",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = WlsExceptionDTO.class))
),
@ApiResponse(
responseCode = "500", description = "Fehler während der Einrichtung",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = WlsExceptionDTO.class))
)
}
)
@PutMapping("wahltermindaten/{wahltagID}")
@ResponseStatus(HttpStatus.OK)
public void putWahltermindaten(@PathVariable("wahltagID") String wahltagID) {
wahltermindatenService.putWahltermindaten(wahltagID);
}

@Operation(
description = "Löscht die Wahltermindaten eines bestimmten Wahltags.",
responses = {
@ApiResponse(
responseCode = "200", description = "Die Wahltermindaten werden gelöscht."
),
@ApiResponse(
responseCode = "400", description = "Es gibt keine Wahltag zu der ID",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = WlsExceptionDTO.class))
),
@ApiResponse(
responseCode = "500", description = "Fehler während des Löschens",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = WlsExceptionDTO.class))
)
}
)
@DeleteMapping("wahltermindaten/{wahltagID}")
@ResponseStatus(HttpStatus.OK)
public void deleteWahltermindaten(@PathVariable("wahltagID") String wahltagID) {
wahltermindatenService.deleteWahltermindaten(wahltagID);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen;
package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common;

import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahlModel;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
public class InitializeKopfdaten {
public class KopfdatenMapper {

private final ExceptionFactory exceptionFactory;

protected void initKopfdaten(BasisdatenModel basisdatenModel) {
basisdatenModel.basisstrukturdaten()
.forEach(basisstrukturdaten -> {
initKopfdata(basisstrukturdaten.wahlID(), basisstrukturdaten.wahlbezirkID(), basisdatenModel);
});
public List<KopfdatenModel> initKopfdaten(BasisdatenModel basisdatenModel) {
return basisdatenModel.basisstrukturdaten()
.stream().map(basisstrukturdaten -> initKopfdata(basisstrukturdaten.wahlID(), basisstrukturdaten.wahlbezirkID(), basisdatenModel))
.toList();
}

protected KopfdatenModel initKopfdata(String wahlID, String wahlbezirkID, BasisdatenModel basisdaten) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten;

import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.kopfdaten.KopfdatenRepository;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -20,7 +20,7 @@ public class KopfdatenService {
private final WahldatenClient wahldatenClient;
private final KopfdatenRepository kopfdatenRepository;
private final KopfdatenModelMapper kopfdatenModelMapper;
private final InitializeKopfdaten kopfDataInitializer;
private final KopfdatenMapper kopfDataInitializer;

@PreAuthorize("hasAuthority('Basisdaten_BUSINESSACTION_GetKopfdaten')")
@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.kopfdaten;

import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.WlsException;

public interface WahldatenClient {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlen;

import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.WlsException;
import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.Wahl;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.wahlen.WahlRepository;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.common.WahltagWithNummer;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahltag.WahltageService;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
import java.util.List;
Expand Down
Loading

0 comments on commit 43b559e

Please sign in to comment.