diff --git a/stack/keycloak/migration/add-authorities-basisdaten-wahlvorschlaege.yml b/stack/keycloak/migration/add-authorities-basisdaten-wahlvorschlaege.yml
new file mode 100644
index 000000000..ab6a5f4bf
--- /dev/null
+++ b/stack/keycloak/migration/add-authorities-basisdaten-wahlvorschlaege.yml
@@ -0,0 +1,87 @@
+id: add authorities basisdaten wahlvorschlaege
+author: MrSebastian
+realm: ${SSO_REALM}
+changes:
+ - addRole:
+ name: Basisdaten_BUSINESSACTION_GetWahlvorschlaege
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_BUSINESSACTION_GetWahlvorschlaege
+ clientId: ${SSO_CLIENT_ID}
+
+ - addRole:
+ name: Basisdaten_READ_WLSWahlvorschlaege
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_READ_WLSWahlvorschlaege
+ clientId: ${SSO_CLIENT_ID}
+ - addRole:
+ name: Basisdaten_WRITE_WLSWahlvorschlaege
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_WRITE_WLSWahlvorschlaege
+ clientId: ${SSO_CLIENT_ID}
+ - addRole:
+ name: Basisdaten_DELETE_WLSWahlvorschlaege
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_DELETE_WLSWahlvorschlaege
+ clientId: ${SSO_CLIENT_ID}
+
+ - addRole:
+ name: Basisdaten_READ_Wahlvorschlag
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_READ_Wahlvorschlag
+ clientId: ${SSO_CLIENT_ID}
+ - addRole:
+ name: Basisdaten_WRITE_Wahlvorschlag
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_WRITE_Wahlvorschlag
+ clientId: ${SSO_CLIENT_ID}
+ - addRole:
+ name: Basisdaten_DELETE_Wahlvorschlag
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_DELETE_Wahlvorschlag
+ clientId: ${SSO_CLIENT_ID}
+
+ - addRole:
+ name: Basisdaten_READ_Kandidat
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_READ_Kandidat
+ clientId: ${SSO_CLIENT_ID}
+ - addRole:
+ name: Basisdaten_WRITE_Kandidat
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_WRITE_Kandidat
+ clientId: ${SSO_CLIENT_ID}
+ - addRole:
+ name: Basisdaten_DELETE_Kandidat
+ clientRole: true
+ clientId: ${SSO_CLIENT_ID}
+ - assignRoleToGroup:
+ group: allBasisdatenAuthorities
+ role: Basisdaten_DELETE_Kandidat
+ clientId: ${SSO_CLIENT_ID}
\ No newline at end of file
diff --git a/stack/keycloak/migration/create-group-all-basisdaten-authorities.yml b/stack/keycloak/migration/create-group-all-basisdaten-authorities.yml
new file mode 100644
index 000000000..fdb657eab
--- /dev/null
+++ b/stack/keycloak/migration/create-group-all-basisdaten-authorities.yml
@@ -0,0 +1,15 @@
+id: create group allBasisdatenAuthorities and link wls_all*
+author: MrSebastian
+realm: ${SSO_REALM}
+changes:
+ - addGroup:
+ name: allBasisdatenAuthorities
+ - assignGroup:
+ user: wls_all
+ group: allBasisdatenAuthorities
+ - assignGroup:
+ user: wls_all_uwb
+ group: allBasisdatenAuthorities
+ - assignGroup:
+ user: wls_all_bwb
+ group: allBasisdatenAuthorities
\ No newline at end of file
diff --git a/stack/keycloak/migration/keycloak-changelog.yml b/stack/keycloak/migration/keycloak-changelog.yml
index 493ba1c29..31513aef6 100644
--- a/stack/keycloak/migration/keycloak-changelog.yml
+++ b/stack/keycloak/migration/keycloak-changelog.yml
@@ -28,4 +28,6 @@ includes:
- path: add-authorities-wahlvorbereitung-urnenwahlschliessungsuhrzeit.yml
- path: create-group-all-eai-authorities.yml
- path: add-authorities-eai-wahlvorstand.yml
- - path: add-authorities-wahlvorbereitung-briefwahlvorbereitung.yml
\ No newline at end of file
+ - path: add-authorities-wahlvorbereitung-briefwahlvorbereitung.yml
+ - path: create-group-all-basisdaten-authorities.yml
+ - path: add-authorities-basisdaten-wahlvorschlaege.yml
\ No newline at end of file
diff --git a/wls-basisdaten-service/pom.xml b/wls-basisdaten-service/pom.xml
index ce5d4d767..52379108b 100644
--- a/wls-basisdaten-service/pom.xml
+++ b/wls-basisdaten-service/pom.xml
@@ -36,7 +36,9 @@
1.18.30
0.2.0
+ 1.5.5.Final
2.6.0
+ 1.1.0
@@ -178,6 +180,13 @@
0.2.6
+
+
+ de.muenchen.oss.wahllokalsystem.wls-common
+ security
+ ${wls.common.version}
+
+
jakarta.validation
@@ -199,6 +208,11 @@
spring-security-test
test
+
+ org.springframework.cloud
+ spring-cloud-starter-contract-stub-runner
+ test
+
org.junit.jupiter
junit-jupiter-api
@@ -209,6 +223,12 @@
junit-jupiter-engine
test
+
+ de.muenchen.oss.wahllokalsystem.wls-common
+ testing
+ ${wls.common.version}
+ test
+
@@ -328,12 +348,25 @@
lombok
${org.projectlombok.lombok.version}
+
+ org.mapstruct
+ mapstruct-processor
+ ${org.mapstruct.version}
+
org.projectlombok
lombok-mapstruct-binding
${org.projectlombok.mapstructbinding.version}
+
+
+ -Amapstruct.defaultComponentModel=spring
+
+
+ -Amapstruct.unmappedTargetPolicy=ERROR
+
+
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/MicroServiceApplication.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/MicroServiceApplication.java
index f1c57cf6b..43ac60833 100644
--- a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/MicroServiceApplication.java
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/MicroServiceApplication.java
@@ -18,7 +18,9 @@
@ComponentScan(
basePackages = {
"org.springframework.data.jpa.convert.threeten",
- "de.muenchen.oss.wahllokalsystem.basisdatenservice"
+ "de.muenchen.oss.wahllokalsystem.basisdatenservice",
+ "de.muenchen.oss.wahllokalsystem.wls.common.exception",
+ "de.muenchen.oss.wahllokalsystem.wls.common.security"
}
)
@EntityScan(
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/ClientImpl.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/ClientImpl.java
new file mode 100644
index 000000000..bdb6fa859
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/ClientImpl.java
@@ -0,0 +1,42 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.clients;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.configuration.Profiles;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.client.WahlvorschlagControllerApi;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlaegeDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeClient;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+
+@Component
+@Profile(Profiles.NOT + Profiles.DUMMY_CLIENTS)
+@RequiredArgsConstructor
+@Slf4j
+public class ClientImpl implements WahlvorschlaegeClient {
+
+ private final ExceptionFactory exceptionFactory;
+
+ private final WahlvorschlagControllerApi wahlvorschlagControllerApi;
+ private final WahlvorschlaegeClientMapper wahlvorschlaegeClientMapper;
+
+ @Override
+ public WahlvorschlaegeModel getWahlvorschlaege(final BezirkUndWahlID bezirkUndWahlID) {
+ final WahlvorschlaegeDTO wahlvorschlaege;
+ try {
+ wahlvorschlaege = wahlvorschlagControllerApi.loadWahlvorschlaege(bezirkUndWahlID.getWahlID(), bezirkUndWahlID.getWahlbezirkID());
+ } catch (final Exception exception) {
+ log.info("exception on loadwahlvorschlaege from external", exception);
+ throw exceptionFactory.createTechnischeWlsException(ExceptionConstants.FAILED_COMMUNICATION_WITH_EAI);
+ }
+ if (wahlvorschlaege == null) {
+ throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.NULL_FROM_CLIENT);
+ }
+
+ return wahlvorschlaegeClientMapper.toModel(wahlvorschlaege);
+ }
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImpl.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImpl.java
new file mode 100644
index 000000000..5b2e10b6e
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImpl.java
@@ -0,0 +1,28 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.clients;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.configuration.Profiles;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.KandidatModel;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeClient;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlagModel;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import java.util.Set;
+import java.util.UUID;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+
+@Component
+@Profile(Profiles.DUMMY_CLIENTS)
+public class DummyClientImpl implements WahlvorschlaegeClient {
+
+ @Override
+ public WahlvorschlaegeModel getWahlvorschlaege(BezirkUndWahlID bezirkUndWahlID) {
+ return new WahlvorschlaegeModel(bezirkUndWahlID, "stimmzettelgebiedID",
+ Set.of(new WahlvorschlagModel(UUID.randomUUID().toString(), 1L, "kurzname1", true,
+ Set.of(new KandidatModel(UUID.randomUUID().toString(), "kandidat11", 1L, true, 1L, true),
+ new KandidatModel(UUID.randomUUID().toString(), "kandidat21", 2L, false, 1L, false))),
+ new WahlvorschlagModel(UUID.randomUUID().toString(), 2L, "kurzname2", true,
+ Set.of(new KandidatModel(UUID.randomUUID().toString(), "kandidat21", 1L, true, 1L, true),
+ new KandidatModel(UUID.randomUUID().toString(), "kandidat22", 2L, false, 1L, false)))));
+ }
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlvorschlaegeClientMapper.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlvorschlaegeClientMapper.java
new file mode 100644
index 000000000..4a2f17bba
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlvorschlaegeClientMapper.java
@@ -0,0 +1,14 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.clients;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlaegeDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper
+public interface WahlvorschlaegeClientMapper {
+
+ @Mapping(target = "bezirkUndWahlID.wahlID", source = "wahlID")
+ @Mapping(target = "bezirkUndWahlID.wahlbezirkID", source = "wahlbezirkID")
+ WahlvorschlaegeModel toModel(WahlvorschlaegeDTO wahlvorschlaegeDTO);
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/Profiles.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/Profiles.java
new file mode 100644
index 000000000..c1fb88f5a
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/Profiles.java
@@ -0,0 +1,12 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.configuration;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class Profiles {
+
+ public static final String NOT = "!";
+
+ public static final String DUMMY_CLIENTS = "dummy.clients";
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Kandidat.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Kandidat.java
new file mode 100644
index 000000000..3417c2cbf
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Kandidat.java
@@ -0,0 +1,67 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain;
+
+import static java.sql.Types.VARCHAR;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.validation.constraints.NotNull;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import org.hibernate.annotations.JdbcTypeCode;
+import org.hibernate.annotations.NaturalId;
+import org.hibernate.annotations.UuidGenerator;
+
+@Entity
+@Getter
+@Setter
+@ToString(onlyExplicitlyIncluded = true)
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+public class Kandidat {
+
+ @Id
+ @GeneratedValue(generator = "uuid")
+ @UuidGenerator
+ @JdbcTypeCode(VARCHAR)
+ private UUID id;
+
+ @NaturalId
+ @NotNull
+ @ToString.Include
+ private String identifikator;
+
+ @ManyToOne
+ @NotNull
+ @JoinColumn(name = "wahlvorschlagID")
+ @EqualsAndHashCode.Exclude
+ private Wahlvorschlag wahlvorschlag;
+
+ @NotNull
+ @ToString.Include
+ private String name;
+
+ @NotNull
+ @ToString.Include
+ private long listenposition;
+
+ @NotNull
+ @ToString.Include
+ private boolean direktkandidat;
+
+ @NotNull
+ @ToString.Include
+ private long tabellenSpalteInNiederschrift;
+
+ @NotNull
+ @ToString.Include
+ private boolean einzelbewerber;
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/KandidatRepository.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/KandidatRepository.java
new file mode 100644
index 000000000..3c9a3a217
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/KandidatRepository.java
@@ -0,0 +1,37 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain;
+
+import java.util.UUID;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.security.access.prepost.PreAuthorize;
+
+@PreAuthorize("hasAuthority('Basisdaten_READ_Kandidat')")
+public interface KandidatRepository extends CrudRepository {
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_WRITE_Kandidat')")
+ S save(S entity);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_WRITE_Kandidat')")
+ Iterable saveAll(Iterable entities);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Kandidat')")
+ void deleteById(UUID id);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Kandidat')")
+ void delete(Kandidat entity);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Kandidat')")
+ void deleteAllById(Iterable extends UUID> strings);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Kandidat')")
+ void deleteAll(Iterable extends Kandidat> entities);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Kandidat')")
+ void deleteAll();
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Wahlvorschlaege.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Wahlvorschlaege.java
new file mode 100644
index 000000000..8a6ab1f8d
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Wahlvorschlaege.java
@@ -0,0 +1,62 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain;
+
+import static java.sql.Types.VARCHAR;
+
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import jakarta.persistence.Embeddable;
+import jakarta.persistence.Embedded;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.OneToMany;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import org.hibernate.annotations.JdbcTypeCode;
+import org.hibernate.annotations.NaturalId;
+import org.hibernate.annotations.UuidGenerator;
+
+@Entity
+@Embeddable
+@Getter
+@Setter
+@ToString(onlyExplicitlyIncluded = true)
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+public class Wahlvorschlaege {
+
+ @Id
+ @GeneratedValue(generator = "uuid")
+ @UuidGenerator
+ @JdbcTypeCode(VARCHAR)
+ private UUID id;
+
+ @Embedded
+ @NaturalId
+ @NotNull
+ @ToString.Include
+ private BezirkUndWahlID bezirkUndWahlID;
+
+ @NotNull
+ @ToString.Include
+ private String stimmzettelgebietID;
+
+ @OneToMany(mappedBy = "wahlvorschlaeage", orphanRemoval = true)
+ @NotNull
+ @Size(min = 1)
+ private Set wahlvorschlaege = new LinkedHashSet<>();
+
+ public void addWahlvorschlag(final Wahlvorschlag wahlvorschlag) {
+ wahlvorschlag.setWahlvorschlaeage(this);
+ wahlvorschlaege.add(wahlvorschlag);
+ }
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlaegeRepository.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlaegeRepository.java
new file mode 100644
index 000000000..05a26a16b
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlaegeRepository.java
@@ -0,0 +1,54 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain;
+
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+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;
+import org.springframework.transaction.annotation.Transactional;
+
+@PreAuthorize("hasAuthority('Basisdaten_READ_WLSWahlvorschlaege')")
+@Transactional
+public interface WahlvorschlaegeRepository extends CrudRepository {
+
+ String CACHE = "WLSWAHLVORSCHLAEGE_CACHE";
+
+ @Override
+ List findAll();
+
+ @Override
+ @Cacheable(value = CACHE, key = "#p0")
+ Optional findById(UUID bezirkUndWahlID);
+
+ Optional findByBezirkUndWahlID(BezirkUndWahlID bezirkUndWahlID);
+
+ @Override
+ @CachePut(value = CACHE, key = "#p0.bezirkUndWahlID")
+ @PreAuthorize("hasAuthority('Basisdaten_WRITE_WLSWahlvorschlaege')")
+ S save(S wahlvorschlaege);
+
+ @Override
+ @CacheEvict(value = CACHE, key = "#p0")
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_WLSWahlvorschlaege')")
+ void deleteById(UUID bezirkUndWahlID);
+
+ @Override
+ @CacheEvict(value = CACHE, key = "#p0.bezirkUndWahlID")
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_WLSWahlvorschlaege')")
+ void delete(Wahlvorschlaege entity);
+
+ @Override
+ @CacheEvict(value = CACHE, allEntries = true)
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_WLSWahlvorschlaege')")
+ void deleteAll(Iterable extends Wahlvorschlaege> entities);
+
+ @Override
+ @CacheEvict(value = CACHE, allEntries = true)
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_WLSWahlvorschlaege')")
+ void deleteAll();
+
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Wahlvorschlag.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Wahlvorschlag.java
new file mode 100644
index 000000000..eda6a09ee
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/Wahlvorschlag.java
@@ -0,0 +1,71 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain;
+
+import static java.sql.Types.VARCHAR;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.OneToMany;
+import jakarta.validation.constraints.NotNull;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.UUID;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import org.hibernate.annotations.JdbcTypeCode;
+import org.hibernate.annotations.NaturalId;
+import org.hibernate.annotations.UuidGenerator;
+
+@Entity
+@Getter
+@Setter
+@ToString(onlyExplicitlyIncluded = true)
+@EqualsAndHashCode
+@NoArgsConstructor
+@AllArgsConstructor
+public class Wahlvorschlag {
+
+ @Id
+ @GeneratedValue(generator = "uuid")
+ @UuidGenerator
+ @JdbcTypeCode(VARCHAR)
+ private UUID id;
+
+ // @Id
+ @NaturalId
+ @NotNull
+ @ToString.Include
+ private String identifikator;
+
+ @ManyToOne
+ @NotNull
+ @JoinColumn(name = "wahlvorschlaegeID")
+ @EqualsAndHashCode.Exclude
+ private Wahlvorschlaege wahlvorschlaeage;
+
+ @NotNull
+ @ToString.Include
+ private long ordnungszahl;
+
+ @NotNull
+ private String kurzname;
+
+ @NotNull
+ @ToString.Include
+ private boolean erhaeltStimmen;
+
+ @OneToMany(mappedBy = "wahlvorschlag", orphanRemoval = true)
+ @NotNull
+ private Set kandidaten = new LinkedHashSet<>();
+
+ public void addKandidat(final Kandidat kandidat) {
+ kandidat.setWahlvorschlag(this);
+ kandidaten.add(kandidat);
+ }
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlagRepository.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlagRepository.java
new file mode 100644
index 000000000..c52a21053
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/domain/WahlvorschlagRepository.java
@@ -0,0 +1,37 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.domain;
+
+import java.util.UUID;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.security.access.prepost.PreAuthorize;
+
+@PreAuthorize("hasAuthority('Basisdaten_READ_Wahlvorschlag')")
+public interface WahlvorschlagRepository extends CrudRepository {
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_WRITE_Wahlvorschlag')")
+ S save(S entity);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_WRITE_Wahlvorschlag')")
+ Iterable saveAll(Iterable entities);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Wahlvorschlag')")
+ void deleteById(UUID id);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Wahlvorschlag')")
+ void delete(Wahlvorschlag entity);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Wahlvorschlag')")
+ void deleteAllById(Iterable extends UUID> uuids);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Wahlvorschlag')")
+ void deleteAll(Iterable extends Wahlvorschlag> entities);
+
+ @Override
+ @PreAuthorize("hasAuthority('Basisdaten_DELETE_Wahlvorschlag')")
+ void deleteAll();
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/exception/ExceptionConstants.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/exception/ExceptionConstants.java
new file mode 100644
index 000000000..17477c786
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/exception/ExceptionConstants.java
@@ -0,0 +1,27 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.exception;
+
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionDataWrapper;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionKonstanten;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ExceptionConstants {
+
+ private static final String CODE_SUCHKRITERIEN_UNVOLLSTAENDIG = "310";
+ private static final String MSG_SUCHKRITERIEN_UNVOLLSTAENDIG = "getWahlvorschlaege: Suchkriterien unvollständig.";
+
+ private static final String CODE_UNSAVEABLE = "903";
+ private static final String MSG_UNSAVEABLE = "Fehler beim speichern: Daten konnten nicht gespeichert werden.";
+
+ public static ExceptionDataWrapper SUCHKRITERIEN_UNVOLLSTAENDIG = new ExceptionDataWrapper(CODE_SUCHKRITERIEN_UNVOLLSTAENDIG,
+ MSG_SUCHKRITERIEN_UNVOLLSTAENDIG);
+
+ public static ExceptionDataWrapper UNSAVEABLE = new ExceptionDataWrapper(CODE_UNSAVEABLE, MSG_UNSAVEABLE);
+
+ public static ExceptionDataWrapper NULL_FROM_CLIENT = new ExceptionDataWrapper(ExceptionKonstanten.CODE_ENTITY_NOT_FOUND, "not found");
+
+ public static ExceptionDataWrapper FAILED_COMMUNICATION_WITH_EAI = new ExceptionDataWrapper("100",
+ "Bei der Kommunikation mit dem Aoueai-Service ist ein Fehler aufgetreten. Es konnten daher keine Daten geladen werden.");
+
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/exception/GlobalExceptionHandler.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/exception/GlobalExceptionHandler.java
new file mode 100644
index 000000000..2d26d1ce7
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/exception/GlobalExceptionHandler.java
@@ -0,0 +1,33 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.exception;
+
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.errorhandler.AbstractExceptionHandler;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.rest.model.DTOMapper;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.rest.model.WlsExceptionDTO;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ServiceIDFormatter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+@ControllerAdvice
+@Slf4j
+public class GlobalExceptionHandler extends AbstractExceptionHandler {
+
+ private final ServiceIDFormatter serviceIDFormatter;
+
+ public GlobalExceptionHandler(final ServiceIDFormatter serviceIDFormatter, final DTOMapper dtoMapper) {
+ super(dtoMapper);
+ this.serviceIDFormatter = serviceIDFormatter;
+ }
+
+ @ExceptionHandler
+ public ResponseEntity handleThrowables(final Throwable throwable) {
+ log.info("handling throwable", throwable);
+ return createResponse(getWahlExceptionDTO(throwable));
+ }
+
+ @Override
+ protected String getService() {
+ return serviceIDFormatter.getId();
+ }
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/KandidatDTO.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/KandidatDTO.java
new file mode 100644
index 000000000..f71a7b7c5
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/KandidatDTO.java
@@ -0,0 +1,11 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahlvorschlag;
+
+import jakarta.validation.constraints.NotNull;
+
+public record KandidatDTO(@NotNull String identifikator,
+ @NotNull String name,
+ @NotNull Long listenposition,
+ @NotNull Boolean direktkandidat,
+ @NotNull Long tabellenSpalteInNiederschrift,
+ @NotNull Boolean einzelbewerber) {
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeController.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeController.java
new file mode 100644
index 000000000..94fe3e08d
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeController.java
@@ -0,0 +1,40 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeService;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+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 io.swagger.v3.oas.annotations.responses.ApiResponses;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/businessActions/wahlvorschlaege")
+@RequiredArgsConstructor
+@Slf4j
+public class WahlvorschlaegeController {
+
+ private final WahlvorschlaegeService wahlvorschlaegeService;
+ private final WahlvorschlaegeDTOMapper wahlvorschlaegeDTOMapper;
+
+ @Operation(description = "Laden der Wahlvorschlaege des Wahllokals {wahlbezirkID} für die Wahl {wahlID}.")
+ @ApiResponses(
+ value = {
+ @ApiResponse(
+ responseCode = "200", description = "OK",
+ content = { @Content(mediaType = "application/json", schema = @Schema(implementation = WahlvorschlaegeDTO.class)) }
+ )
+ }
+ )
+ @GetMapping("/{wahlID}/{wahlbezirkID}")
+ public WahlvorschlaegeDTO getWahlvorschlaege(@PathVariable("wahlID") String wahlID, @PathVariable("wahlbezirkID") String wahlbezirkID) {
+ return wahlvorschlaegeDTOMapper.toDTO(
+ wahlvorschlaegeService.getWahlvorschlaege(new BezirkUndWahlID(wahlID, wahlbezirkID)));
+ }
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTO.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTO.java
new file mode 100644
index 000000000..a35e0dbf0
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTO.java
@@ -0,0 +1,12 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahlvorschlag;
+
+import jakarta.validation.constraints.NotNull;
+import java.util.Set;
+import lombok.Builder;
+
+@Builder
+public record WahlvorschlaegeDTO(@NotNull String wahlID,
+ @NotNull String wahlbezirkID,
+ @NotNull String stimmzettelgebietID,
+ @NotNull Set wahlvorschlaege) {
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTOMapper.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTOMapper.java
new file mode 100644
index 000000000..d3c41badc
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTOMapper.java
@@ -0,0 +1,14 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper
+public interface WahlvorschlaegeDTOMapper {
+
+ @Mapping(source = "bezirkUndWahlID.wahlID", target = "wahlID")
+ @Mapping(source = "bezirkUndWahlID.wahlbezirkID", target = "wahlbezirkID")
+ WahlvorschlaegeDTO toDTO(WahlvorschlaegeModel wahlvorschlaegeModel);
+
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlagDTO.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlagDTO.java
new file mode 100644
index 000000000..19ac3af4d
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlagDTO.java
@@ -0,0 +1,11 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahlvorschlag;
+
+import jakarta.validation.constraints.NotNull;
+import java.util.Set;
+
+public record WahlvorschlagDTO(@NotNull String identifikator,
+ @NotNull Long ordnungszahl,
+ @NotNull String kurzname,
+ @NotNull Boolean erhaeltStimmen,
+ Set kandidaten) {
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/KandidatModel.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/KandidatModel.java
new file mode 100644
index 000000000..c23adbe54
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/KandidatModel.java
@@ -0,0 +1,15 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Builder;
+
+@Builder
+public record KandidatModel(@NotNull String identifikator,
+ @NotNull String name,
+ @NotNull long listenposition,
+ @NotNull boolean direktkandidat,
+ @NotNull long tabellenSpalteInNiederschrift,
+ @NotNull boolean einzelbewerber
+) {
+
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeClient.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeClient.java
new file mode 100644
index 000000000..53f722b62
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeClient.java
@@ -0,0 +1,19 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.WlsException;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+
+public interface WahlvorschlaegeClient {
+
+ /**
+ * @param bezirkUndWahlID Reference for requestes Wahlvorschlaege
+ * @return Model with Wahlvorschlaegen
+ * @throws WlsException
+ * {@link de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException} if
+ * return would be null
+ * {@link de.muenchen.oss.wahllokalsystem.wls.common.exception.TechnischeWlsException}
+ * if there were trouble during communication
+ */
+ WahlvorschlaegeModel getWahlvorschlaege(BezirkUndWahlID bezirkUndWahlID) throws WlsException;
+
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModel.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModel.java
new file mode 100644
index 000000000..14279a6fb
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModel.java
@@ -0,0 +1,13 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import jakarta.validation.constraints.NotNull;
+import java.util.Set;
+import lombok.Builder;
+
+@Builder
+public record WahlvorschlaegeModel(@NotNull BezirkUndWahlID bezirkUndWahlID,
+ @NotNull String stimmzettelgebietID,
+ @NotNull Set wahlvorschlaege) {
+
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModelMapper.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModelMapper.java
new file mode 100644
index 000000000..c83d6f444
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModelMapper.java
@@ -0,0 +1,26 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Kandidat;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Wahlvorschlaege;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Wahlvorschlag;
+import org.mapstruct.CollectionMappingStrategy;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
+public interface WahlvorschlaegeModelMapper {
+
+ @Mapping(target = "id", ignore = true)
+ Wahlvorschlaege toEntity(WahlvorschlaegeModel wahlvorschlaegeModel);
+
+ @Mapping(target = "wahlvorschlaeage", ignore = true)
+ @Mapping(target = "id", ignore = true)
+ Wahlvorschlag toEntity(WahlvorschlagModel wahlvorschlagModel);
+
+ @Mapping(target = "wahlvorschlag", ignore = true)
+ @Mapping(target = "id", ignore = true)
+ Kandidat toEntity(KandidatModel kandidatModel);
+
+ WahlvorschlaegeModel toModel(Wahlvorschlaege entity);
+
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeService.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeService.java
new file mode 100644
index 000000000..7726057c0
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeService.java
@@ -0,0 +1,62 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.KandidatRepository;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Wahlvorschlaege;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.WahlvorschlaegeRepository;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.WahlvorschlagRepository;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class WahlvorschlaegeService {
+
+ private final WahlvorschlaegeRepository wahlvorschlaegeRepository;
+ private final WahlvorschlagRepository wahlvorschlagRepository;
+ private final KandidatRepository kandidatRepository;
+ private final WahlvorschlaegeModelMapper wahlvorschlaegeModelMapper;
+ private final WahlvorschlaegeValidator wahlvorschlaegeValidator;
+ private final WahlvorschlaegeClient wahlvorschlaegeClient;
+
+ @PreAuthorize(
+ "hasAuthority('Basisdaten_BUSINESSACTION_GetWahlvorschlaege')"
+ )
+ @Transactional
+ public WahlvorschlaegeModel getWahlvorschlaege(final BezirkUndWahlID bezirkUndWahlID) {
+ log.debug("#getWahlvorschlaege bezirkUndWahlID > {}", bezirkUndWahlID);
+
+ wahlvorschlaegeValidator.validWahlIdUndWahlbezirkIDOrThrow(bezirkUndWahlID);
+ val wahlvorschlaegeFromRepo = wahlvorschlaegeRepository.findByBezirkUndWahlID(bezirkUndWahlID);
+ if (wahlvorschlaegeFromRepo.isEmpty()) {
+ log.debug("#getWahlvorschlaege: Für BezirkUndWahlID {} waren keine Wahlvorschlaege in der Datenbank", bezirkUndWahlID);
+ val importedWahlvorschlaegeModel = wahlvorschlaegeClient.getWahlvorschlaege(bezirkUndWahlID);
+ try {
+ val savedWahlvorschlaege = persistWahlvorschlagModel(importedWahlvorschlaegeModel);
+ return wahlvorschlaegeModelMapper.toModel(savedWahlvorschlaege);
+ } catch (final Exception exception) {
+ log.error("#getWahlvorschlaege: Fehler beim Cachen", exception);
+ return importedWahlvorschlaegeModel; // an exception on saving does prevent sending a response. We can use the imported object
+ }
+ } else {
+ return wahlvorschlaegeModelMapper.toModel(wahlvorschlaegeFromRepo.get());
+ }
+ }
+
+ protected Wahlvorschlaege persistWahlvorschlagModel(final WahlvorschlaegeModel wahlvorschlaegeModel) {
+ val entityToCreate = wahlvorschlaegeModelMapper.toEntity(wahlvorschlaegeModel);
+ val createdEntity = wahlvorschlaegeRepository.save(entityToCreate);
+ entityToCreate.getWahlvorschlaege().forEach(wahlvorschlag -> {
+ wahlvorschlagRepository.save(wahlvorschlag);
+ kandidatRepository.saveAll(wahlvorschlag.getKandidaten());
+ });
+
+ return createdEntity;
+ }
+
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeValidator.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeValidator.java
new file mode 100644
index 000000000..5d2e842a1
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeValidator.java
@@ -0,0 +1,21 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class WahlvorschlaegeValidator {
+
+ private final ExceptionFactory exceptionFactory;
+
+ public void validWahlIdUndWahlbezirkIDOrThrow(final BezirkUndWahlID bezirkUndWahlID) {
+ if (bezirkUndWahlID == null || StringUtils.isEmpty(bezirkUndWahlID.getWahlID()) || StringUtils.isEmpty(bezirkUndWahlID.getWahlbezirkID())) {
+ throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.SUCHKRITERIEN_UNVOLLSTAENDIG);
+ }
+ }
+}
diff --git a/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlagModel.java b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlagModel.java
new file mode 100644
index 000000000..c04fb79f9
--- /dev/null
+++ b/wls-basisdaten-service/src/main/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlagModel.java
@@ -0,0 +1,16 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import jakarta.validation.constraints.NotNull;
+import java.util.Set;
+import lombok.Builder;
+
+@Builder
+public record WahlvorschlagModel(
+ @NotNull String identifikator,
+ @NotNull Long ordnungszahl,
+ @NotNull String kurzname,
+ @NotNull Boolean erhaeltStimmen,
+ Set kandidaten
+) {
+
+}
diff --git a/wls-basisdaten-service/src/main/resources/application.yml b/wls-basisdaten-service/src/main/resources/application.yml
index 82eae7f41..a81482fa3 100644
--- a/wls-basisdaten-service/src/main/resources/application.yml
+++ b/wls-basisdaten-service/src/main/resources/application.yml
@@ -5,6 +5,7 @@ spring:
group:
local:
- db-h2
+ - dummy.clients
flyway:
locations:
- classpath:db/migrations/{vendor}
@@ -24,6 +25,10 @@ security:
oauth2:
resource.user-info-uri: http://kubernetes.docker.internal:8100/auth/realms/${realm}/protocol/openid-connect/userinfo
+service:
+ info:
+ oid: WLS-BASISDATEN
+
# Define the local keycloak realm here
realm: wls_realm
diff --git a/wls-basisdaten-service/src/main/resources/db/migrations/h2/V1_0__createWahlvorschlaegeTable.sql b/wls-basisdaten-service/src/main/resources/db/migrations/h2/V1_0__createWahlvorschlaegeTable.sql
new file mode 100644
index 000000000..27e7d8ff6
--- /dev/null
+++ b/wls-basisdaten-service/src/main/resources/db/migrations/h2/V1_0__createWahlvorschlaegeTable.sql
@@ -0,0 +1,45 @@
+CREATE TABLE wahlvorschlaege
+(
+ id VARCHAR(255) NOT NULL,
+ stimmzettelgebietid VARCHAR(255) NOT NULL,
+ wahlID VARCHAR(255) NOT NULL,
+ wahlbezirkID VARCHAR(255) NOT NULL,
+
+ unique (wahlID, wahlbezirkID),
+
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE Wahlvorschlag
+(
+ id VARCHAR(255) NOT NULL,
+ identifikator VARCHAR(255) NOT NULL,
+ ordnungszahl BIGINT NOT NULL,
+ kurzname VARCHAR(255) NOT NULL,
+ erhaeltStimmen BOOLEAN NOT NULL,
+ wahlvorschlaegeID VARCHAR(255) NOT NULL,
+
+ unique (identifikator),
+
+ foreign key (wahlvorschlaegeID) REFERENCES wahlvorschlaege (id),
+
+ primary key (id)
+);
+
+CREATE TABLE Kandidat
+(
+ id VARCHAR(255) NOT NULL,
+ identifikator VARCHAR(255) NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ listenposition BIGINT NOT NULL,
+ direktkandidat BOOLEAN NOT NULL,
+ tabellenSpalteInNiederschrift BIGINT NOT NULL,
+ einzelbewerber BOOLEAN NOT NULL,
+ wahlvorschlagID VARCHAR(255) NOT NULL,
+
+ unique (identifikator),
+
+ foreign key (wahlvorschlagID) REFERENCES Wahlvorschlag (id),
+
+ primary key (id)
+)
\ No newline at end of file
diff --git a/wls-basisdaten-service/src/main/resources/db/migrations/oracle/V1_0__createWahlvorschlaegeTable.sql b/wls-basisdaten-service/src/main/resources/db/migrations/oracle/V1_0__createWahlvorschlaegeTable.sql
new file mode 100644
index 000000000..6cc9e204c
--- /dev/null
+++ b/wls-basisdaten-service/src/main/resources/db/migrations/oracle/V1_0__createWahlvorschlaegeTable.sql
@@ -0,0 +1,45 @@
+CREATE TABLE wahlvorschlaege
+(
+ id VARCHAR(255) NOT NULL,
+ stimmzettelgebietid VARCHAR(255) NOT NULL,
+ wahlID VARCHAR(255) NOT NULL,
+ wahlbezirkID VARCHAR(255) NOT NULL,
+
+ unique (wahlID, wahlbezirkID),
+
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE Wahlvorschlag
+(
+ id VARCHAR(255) NOT NULL,
+ identifikator VARCHAR(255) NOT NULL,
+ ordnungszahl NUMBER NOT NULL,
+ kurzname VARCHAR(255) NOT NULL,
+ erhaeltStimmen NUMBER NOT NULL,
+ wahlvorschlaegeID VARCHAR(255) NOT NULL,
+
+ unique (identifikator),
+
+ foreign key (wahlvorschlaegeID) REFERENCES wahlvorschlaege (id),
+
+ primary key (id)
+);
+
+CREATE TABLE Kandidat
+(
+ id VARCHAR(255) NOT NULL,
+ identifikator VARCHAR(255) NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ listenposition NUMBER NOT NULL,
+ direktkandidat NUMBER NOT NULL,
+ tabellenSpalteInNiederschrift NUMBER NOT NULL,
+ einzelbewerber NUMBER NOT NULL,
+ wahlvorschlagID VARCHAR(255) NOT NULL,
+
+ unique (identifikator),
+
+ foreign key (wahlvorschlagID) REFERENCES Wahlvorschlag (id),
+
+ primary key (id)
+)
\ No newline at end of file
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/ClientImplTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/ClientImplTest.java
new file mode 100644
index 000000000..fa4982b75
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/ClientImplTest.java
@@ -0,0 +1,68 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.clients;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.client.WahlvorschlagControllerApi;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlaegeDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class ClientImplTest {
+
+ @Mock
+ ExceptionFactory exceptionFactory;
+
+ @Mock
+ WahlvorschlagControllerApi wahlvorschlagControllerApi;
+
+ @Mock
+ WahlvorschlaegeClientMapper wahlvorschlaegeClientMapper;
+
+ @InjectMocks
+ ClientImpl unitUnderTest;
+
+ @Nested
+ class GetWahlvorschlaege {
+
+ @Test
+ void clientResponseIsMapped() {
+ val bezirkUndWahlID = new BezirkUndWahlID("wahlID", "wahlbezirkID");
+
+ val mockedClientResponse = new WahlvorschlaegeDTO();
+ val mockedMappedClientResponse = WahlvorschlaegeModel.builder().build();
+
+ Mockito.when(wahlvorschlagControllerApi.loadWahlvorschlaege(eq(bezirkUndWahlID.getWahlID()), eq(bezirkUndWahlID.getWahlbezirkID())))
+ .thenReturn(mockedClientResponse);
+ Mockito.when(wahlvorschlaegeClientMapper.toModel(mockedClientResponse)).thenReturn(mockedMappedClientResponse);
+
+ val result = unitUnderTest.getWahlvorschlaege(bezirkUndWahlID);
+
+ Assertions.assertThat(result).isSameAs(mockedMappedClientResponse);
+ }
+
+ @Test
+ void exceptionWhenClientResponseIsNull() {
+ val mockedWlsException = FachlicheWlsException.withCode("").buildWithMessage("");
+
+ Mockito.when(wahlvorschlagControllerApi.loadWahlvorschlaege(any(), any())).thenReturn(null);
+ Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.NULL_FROM_CLIENT)).thenReturn(mockedWlsException);
+
+ Assertions.assertThatException().isThrownBy(() -> unitUnderTest.getWahlvorschlaege(new BezirkUndWahlID("", ""))).isSameAs(mockedWlsException);
+ }
+ }
+
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImplTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImplTest.java
new file mode 100644
index 000000000..b39c42dd2
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/DummyClientImplTest.java
@@ -0,0 +1,23 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.clients;
+
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class DummyClientImplTest {
+
+ private final DummyClientImpl unitUnderTest = new DummyClientImpl();
+
+ @Nested
+ class GetWahlvorschlaege {
+
+ @Test
+ void resultIsANonNullObject() {
+ val result = unitUnderTest.getWahlvorschlaege(new BezirkUndWahlID("wahlID", "wahlbezirkID"));
+
+ Assertions.assertThat(result).hasNoNullFieldsOrProperties();
+ }
+ }
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlvorschlaegeClientMapperTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlvorschlaegeClientMapperTest.java
new file mode 100644
index 000000000..23e590515
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/clients/WahlvorschlaegeClientMapperTest.java
@@ -0,0 +1,98 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.clients;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.KandidatDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlaegeDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlagDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.KandidatModel;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlagModel;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import java.util.Set;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+
+class WahlvorschlaegeClientMapperTest {
+
+ private final WahlvorschlaegeClientMapper unitUnderTest = Mappers.getMapper(WahlvorschlaegeClientMapper.class);
+
+ @Nested
+ class ToModel {
+
+ @Test
+ void isMapped() {
+ val stimmzettelgebietID = "stimmzettelgebietID";
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ val dtoToMap = new WahlvorschlaegeDTO();
+ dtoToMap.setStimmzettelgebietID(stimmzettelgebietID);
+ dtoToMap.setWahlID(wahlID);
+ dtoToMap.setWahlbezirkID(wahlbezirkID);
+
+ val wahlvorschlag1 = new WahlvorschlagDTO();
+ wahlvorschlag1.setErhaeltStimmen(true);
+ wahlvorschlag1.setIdentifikator("identifikator1");
+ wahlvorschlag1.setKurzname("kurzname1");
+ wahlvorschlag1.setOrdnungszahl(1L);
+
+ val kandidat11 = new KandidatDTO();
+ kandidat11.setIdentifikator("kandidat11");
+ kandidat11.setDirektkandidat(true);
+ kandidat11.setEinzelbewerber(true);
+ kandidat11.setName("name11");
+ kandidat11.setListenposition(1L);
+ kandidat11.setTabellenSpalteInNiederschrift(1L);
+
+ val kandidat12 = new KandidatDTO();
+ kandidat12.setIdentifikator("kandidat12");
+ kandidat12.setDirektkandidat(false);
+ kandidat12.setEinzelbewerber(false);
+ kandidat12.setName("name12");
+ kandidat12.setListenposition(2L);
+ kandidat12.setTabellenSpalteInNiederschrift(2L);
+ wahlvorschlag1.setKandidaten(Set.of(kandidat11, kandidat12));
+
+ val wahlvorschlag2 = new WahlvorschlagDTO();
+ wahlvorschlag2.setErhaeltStimmen(false);
+ wahlvorschlag2.setIdentifikator("identifikator2");
+ wahlvorschlag2.setKurzname("kurzname2");
+ wahlvorschlag2.setOrdnungszahl(2L);
+
+ val kandidat21 = new KandidatDTO();
+ kandidat21.setIdentifikator("kandidat21");
+ kandidat21.setDirektkandidat(true);
+ kandidat21.setEinzelbewerber(true);
+ kandidat21.setName("name21");
+ kandidat21.setListenposition(3L);
+ kandidat21.setTabellenSpalteInNiederschrift(3L);
+
+ val kandidat22 = new KandidatDTO();
+ kandidat22.setIdentifikator("kandidat22");
+ kandidat22.setDirektkandidat(false);
+ kandidat22.setEinzelbewerber(false);
+ kandidat22.setName("name22");
+ kandidat22.setListenposition(4L);
+ kandidat22.setTabellenSpalteInNiederschrift(4L);
+ wahlvorschlag2.setKandidaten(Set.of(kandidat21, kandidat22));
+
+ val wahlvorschlaege = Set.of(wahlvorschlag1, wahlvorschlag2);
+ dtoToMap.setWahlvorschlaege(wahlvorschlaege);
+ Assertions.assertThat(dtoToMap).hasNoNullFieldsOrProperties();
+
+ val result = unitUnderTest.toModel(dtoToMap);
+
+ val expectedWahlvorschlaege = Set.of(new WahlvorschlagModel("identifikator1", 1L, "kurzname1", true, Set.of(
+ new KandidatModel("kandidat11", "name11", 1L, true, 1L, true),
+ new KandidatModel("kandidat12", "name12", 2L, false, 2L, false))),
+ new WahlvorschlagModel("identifikator2", 2L, "kurzname2", false, Set.of(
+ new KandidatModel("kandidat21", "name21", 3L, true, 3L, true),
+ new KandidatModel("kandidat22", "name22", 4L, false, 4L, false))));
+ val expectedResult = new WahlvorschlaegeModel(new BezirkUndWahlID(wahlID, wahlbezirkID), stimmzettelgebietID, expectedWahlvorschlaege);
+
+ Assertions.assertThat(result).usingRecursiveComparison().isEqualTo(expectedResult);
+ }
+ }
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/SecurityConfigurationTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/SecurityConfigurationTest.java
index 5facfa0fd..2aa68c8cd 100644
--- a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/SecurityConfigurationTest.java
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/configuration/SecurityConfigurationTest.java
@@ -5,11 +5,16 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import de.muenchen.oss.wahllokalsystem.basisdatenservice.MicroServiceApplication;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeService;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.security.test.context.support.WithAnonymousUser;
+import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
@@ -22,6 +27,9 @@ class SecurityConfigurationTest {
@Autowired
MockMvc api;
+ @MockBean
+ WahlvorschlaegeService wahlvorschlaegeService;
+
@Test
void accessSecuredResourceRootThenUnauthorized() throws Exception {
api.perform(get("/"))
@@ -64,4 +72,20 @@ void accessUnsecuredResourceSwaggerUiThenOk() throws Exception {
.andExpect(status().isOk());
}
+ @Nested
+ class Wahlvorschlaege {
+
+ @Test
+ @WithAnonymousUser
+ void accessGetWahlvorstaendeUnauthorizedThenUnauthorized() throws Exception {
+ api.perform(get("/businessActions/wahlvorschlaege/wahlID/wahlbezirkID")).andExpect(status().isUnauthorized());
+ }
+
+ @Test
+ @WithMockUser
+ void accessGetWahlvorstaendeUnauthorizedThenOk() throws Exception {
+ api.perform(get("/businessActions/wahlvorschlaege/wahlID/wahlbezirkID")).andExpect(status().isOk());
+ }
+ }
+
}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeControllerIntegrationTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeControllerIntegrationTest.java
new file mode 100644
index 000000000..4cf19583b
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeControllerIntegrationTest.java
@@ -0,0 +1,243 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahlvorschlag;
+
+import static de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants.SPRING_NO_SECURITY_PROFILE;
+import static de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants.SPRING_TEST_PROFILE;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.MicroServiceApplication;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.clients.WahlvorschlaegeClientMapper;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.KandidatRepository;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.WahlvorschlaegeRepository;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.WahlvorschlagRepository;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.KandidatDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlagDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModelMapper;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeValidator;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.utils.Authorities;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.rest.model.WlsExceptionCategory;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.rest.model.WlsExceptionDTO;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import de.muenchen.oss.wahllokalsystem.wls.common.testing.SecurityUtils;
+import java.util.Set;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
+import org.springframework.http.HttpStatus;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.transaction.annotation.Transactional;
+
+@SpringBootTest(classes = MicroServiceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
+@AutoConfigureMockMvc
+@AutoConfigureWireMock
+@ActiveProfiles(profiles = { SPRING_TEST_PROFILE, SPRING_NO_SECURITY_PROFILE })
+public class WahlvorschlaegeControllerIntegrationTest {
+
+ @Value("${service.info.oid}")
+ String serviceID;
+
+ @Autowired
+ MockMvc api;
+
+ @Autowired
+ ObjectMapper objectMapper;
+
+ @Autowired
+ WahlvorschlaegeDTOMapper dtoMapper;
+
+ @Autowired
+ WahlvorschlaegeModelMapper modelMapper;
+
+ @Autowired
+ WahlvorschlaegeClientMapper wahlvorschlaegeClientMapper;
+
+ @Autowired
+ WahlvorschlaegeRepository wahlvorschlaegeRepository;
+
+ @Autowired
+ WahlvorschlagRepository wahlvorschlagRepository;
+
+ @Autowired
+ KandidatRepository kandidatRepository;
+
+ @SpyBean
+ WahlvorschlaegeValidator wahlvorschlaegeValidator;
+
+ @AfterEach
+ void tearDown() {
+ SecurityUtils.runWith(Authorities.ALL_AUTHORITIES_DELETE_WAHLVORSCHLAEGE);
+ wahlvorschlaegeRepository.deleteAll();
+ }
+
+ @BeforeEach
+ void setup() {
+ WireMock.resetAllRequests();
+ }
+
+ @Nested
+ class GetWahlvorschlaege {
+
+ @Test
+ void loadedFromExternal() throws Exception {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ val eaiWahlvorschlaege = createClientWahlvorschlaegeDTO(wahlID, wahlbezirkID);
+ WireMock.stubFor(WireMock.get("/vorschlaege/wahl/" + wahlID + "/" + wahlbezirkID)
+ .willReturn(WireMock.aResponse().withHeader("Content-Type", "application/json").withStatus(HttpStatus.OK.value())
+ .withBody(objectMapper.writeValueAsBytes(eaiWahlvorschlaege))));
+
+ val request = MockMvcRequestBuilders.get("/businessActions/wahlvorschlaege/" + wahlID + "/" + wahlbezirkID);
+
+ val response = api.perform(request).andExpect(status().isOk()).andReturn();
+ val responseBodyAsDTO = objectMapper.readValue(response.getResponse().getContentAsString(), WahlvorschlaegeDTO.class);
+
+ val expectedResponseBody = dtoMapper.toDTO(wahlvorschlaegeClientMapper.toModel(eaiWahlvorschlaege));
+
+ Assertions.assertThat(responseBodyAsDTO).isEqualTo(expectedResponseBody);
+ }
+
+ @Test
+ @Transactional
+ void externalDataIsPersisted() throws Exception {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ val eaiWahlvorschlaege = createClientWahlvorschlaegeDTO(wahlID, wahlbezirkID);
+ WireMock.stubFor(WireMock.get("/vorschlaege/wahl/" + wahlID + "/" + wahlbezirkID)
+ .willReturn(WireMock.aResponse().withHeader("Content-Type", "application/json").withStatus(HttpStatus.OK.value())
+ .withBody(objectMapper.writeValueAsBytes(eaiWahlvorschlaege))));
+
+ val request = MockMvcRequestBuilders.get("/businessActions/wahlvorschlaege/" + wahlID + "/" + wahlbezirkID);
+
+ api.perform(request).andExpect(status().isOk());
+
+ val dataFromRepo = wahlvorschlaegeRepository.findByBezirkUndWahlID(new BezirkUndWahlID(wahlID, wahlbezirkID)).get();
+
+ val expectedEntity = modelMapper.toEntity(wahlvorschlaegeClientMapper.toModel(eaiWahlvorschlaege));
+
+ Assertions.assertThat(dataFromRepo).usingRecursiveComparison().ignoringCollectionOrder()
+ .ignoringFields("id", "wahlvorschlaege.id", "wahlvorschlaege.wahlvorschlaeage",
+ "wahlvorschlaege.kandidaten.id", "wahlvorschlaege.kandidaten.wahlvorschlag")
+ .isEqualTo(expectedEntity);
+ }
+
+ @Test
+ void loadFromRepository() throws Exception {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ val entityToFind = modelMapper.toEntity(
+ wahlvorschlaegeClientMapper.toModel(createClientWahlvorschlaegeDTO(wahlID, wahlbezirkID)));
+ val savedEntity = wahlvorschlaegeRepository.save(entityToFind);
+ entityToFind.getWahlvorschlaege().forEach(wahlvorschlag -> {
+ wahlvorschlagRepository.save(wahlvorschlag);
+ kandidatRepository.saveAll(wahlvorschlag.getKandidaten());
+ });
+
+ val request = MockMvcRequestBuilders.get("/businessActions/wahlvorschlaege/" + wahlID + "/" + wahlbezirkID);
+
+ val response = api.perform(request).andExpect(status().isOk()).andReturn();
+ val responseBodyAsDTO = objectMapper.readValue(response.getResponse().getContentAsString(), WahlvorschlaegeDTO.class);
+
+ val expectedResponseBody = dtoMapper.toDTO(modelMapper.toModel(savedEntity));
+
+ Assertions.assertThat(responseBodyAsDTO).isEqualTo(expectedResponseBody);
+ WireMock.verify(0, WireMock.anyRequestedFor(WireMock.anyUrl()));
+ }
+
+ @Test
+ void technischeWlsExceptionWhenNoExternalDataFound() throws Exception {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ WireMock.stubFor(WireMock.get("/vorschlaege/wahl/" + wahlID + "/" + wahlbezirkID)
+ .willReturn(WireMock.aResponse().withHeader("Content-Type", "application/json").withStatus(HttpStatus.NOT_FOUND.value())));
+
+ val request = MockMvcRequestBuilders.get("/businessActions/wahlvorschlaege/" + wahlID + "/" + wahlbezirkID);
+
+ val response = api.perform(request).andExpect(status().isInternalServerError()).andReturn();
+ val responseBodyAsWlsExceptionDTO = objectMapper.readValue(response.getResponse().getContentAsString(), WlsExceptionDTO.class);
+
+ val expectedWlsExceptionDTO = new WlsExceptionDTO(WlsExceptionCategory.T,
+ ExceptionConstants.FAILED_COMMUNICATION_WITH_EAI.code(), serviceID,
+ ExceptionConstants.FAILED_COMMUNICATION_WITH_EAI.message());
+ Assertions.assertThat(responseBodyAsWlsExceptionDTO).isEqualTo(expectedWlsExceptionDTO);
+ }
+ }
+
+ private de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlaegeDTO createClientWahlvorschlaegeDTO(final String wahlID,
+ final String wahlbezirkID) {
+ val stimmzettelgebietID = "stimmzettelgebietID";
+
+ val clientWahlvorschlaegeDTO = new de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlaegeDTO();
+ clientWahlvorschlaegeDTO.setStimmzettelgebietID(stimmzettelgebietID);
+ clientWahlvorschlaegeDTO.setWahlID(wahlID);
+ clientWahlvorschlaegeDTO.setWahlbezirkID(wahlbezirkID);
+
+ val wahlvorschlag1 = new de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlagDTO();
+ wahlvorschlag1.setErhaeltStimmen(true);
+ wahlvorschlag1.setIdentifikator("identifikator1");
+ wahlvorschlag1.setKurzname("kurzname1");
+ wahlvorschlag1.setOrdnungszahl(1L);
+
+ val kandidat11 = new de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.KandidatDTO();
+ kandidat11.setIdentifikator("kandidat11");
+ kandidat11.setDirektkandidat(true);
+ kandidat11.setEinzelbewerber(true);
+ kandidat11.setName("name11");
+ kandidat11.setListenposition(1L);
+ kandidat11.setTabellenSpalteInNiederschrift(1L);
+
+ val kandidat12 = new de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.KandidatDTO();
+ kandidat12.setIdentifikator("kandidat12");
+ kandidat12.setDirektkandidat(false);
+ kandidat12.setEinzelbewerber(false);
+ kandidat12.setName("name12");
+ kandidat12.setListenposition(2L);
+ kandidat12.setTabellenSpalteInNiederschrift(2L);
+ wahlvorschlag1.setKandidaten(Set.of(kandidat11, kandidat12));
+
+ val wahlvorschlag2 = new WahlvorschlagDTO();
+ wahlvorschlag2.setErhaeltStimmen(false);
+ wahlvorschlag2.setIdentifikator("identifikator2");
+ wahlvorschlag2.setKurzname("kurzname2");
+ wahlvorschlag2.setOrdnungszahl(2L);
+
+ val kandidat21 = new de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.KandidatDTO();
+ kandidat21.setIdentifikator("kandidat21");
+ kandidat21.setDirektkandidat(true);
+ kandidat21.setEinzelbewerber(true);
+ kandidat21.setName("name21");
+ kandidat21.setListenposition(3L);
+ kandidat21.setTabellenSpalteInNiederschrift(3L);
+
+ val kandidat22 = new KandidatDTO();
+ kandidat22.setIdentifikator("kandidat22");
+ kandidat22.setDirektkandidat(false);
+ kandidat22.setEinzelbewerber(false);
+ kandidat22.setName("name22");
+ kandidat22.setListenposition(4L);
+ kandidat22.setTabellenSpalteInNiederschrift(4L);
+ wahlvorschlag2.setKandidaten(Set.of(kandidat21, kandidat22));
+
+ val wahlvorschlaege = Set.of(wahlvorschlag1, wahlvorschlag2);
+ clientWahlvorschlaegeDTO.setWahlvorschlaege(wahlvorschlaege);
+
+ return clientWahlvorschlaegeDTO;
+ }
+
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeControllerTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeControllerTest.java
new file mode 100644
index 000000000..d0c6bdfcb
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeControllerTest.java
@@ -0,0 +1,47 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeService;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class WahlvorschlaegeControllerTest {
+
+ @Mock
+ WahlvorschlaegeService wahlvorschlaegeService;
+
+ @Mock
+ WahlvorschlaegeDTOMapper wahlvorschlaegeDTOMapper;
+
+ @InjectMocks
+ WahlvorschlaegeController wahlvorschlaegeController;
+
+ @Nested
+ class GetWahlvorschlaege {
+
+ @Test
+ void serviceIsCalledAndObjectsAreMapped() {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ val wahlvorschlaegeModel = WahlvorschlaegeModel.builder().build();
+ val wahlvorschlaegeDTO = WahlvorschlaegeDTO.builder().build();
+
+ Mockito.when(wahlvorschlaegeService.getWahlvorschlaege(new BezirkUndWahlID(wahlID, wahlbezirkID))).thenReturn(wahlvorschlaegeModel);
+ Mockito.when(wahlvorschlaegeDTOMapper.toDTO(wahlvorschlaegeModel)).thenReturn(wahlvorschlaegeDTO);
+
+ val result = wahlvorschlaegeController.getWahlvorschlaege(wahlID, wahlbezirkID);
+
+ Assertions.assertThat(result).isEqualTo(wahlvorschlaegeDTO);
+ }
+ }
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTOMapperTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTOMapperTest.java
new file mode 100644
index 000000000..37766bc5b
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/rest/wahlvorschlag/WahlvorschlaegeDTOMapperTest.java
@@ -0,0 +1,60 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.rest.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.KandidatModel;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlaegeModel;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag.WahlvorschlagModel;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import java.util.Set;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+
+class WahlvorschlaegeDTOMapperTest {
+
+ private final WahlvorschlaegeDTOMapper unitUnderTest = Mappers.getMapper(WahlvorschlaegeDTOMapper.class);
+
+ @Nested
+ class FromWahlvorschlagModelToWLSDTO {
+
+ @Test
+ void nullInNullOut() {
+ Assertions.assertThat(unitUnderTest.toDTO(null)).isNull();
+ }
+
+ @Test
+ void isMappedToDTO() {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ val modelInput = createWahlvorschlaegeModel(wahlID, wahlbezirkID);
+ val dtoExpected = createWahlvorschlaegeDTO(wahlID, wahlbezirkID);
+
+ val result = unitUnderTest.toDTO(modelInput);
+ Assertions.assertThat(result).isEqualTo(dtoExpected);
+ }
+
+ private WahlvorschlaegeDTO createWahlvorschlaegeDTO(final String wahlID, final String wahlbezirkID) {
+ return new WahlvorschlaegeDTO(wahlID, wahlbezirkID, "stimmzettelgebietID",
+ Set.of(
+ new WahlvorschlagDTO("id1", 1L, "kurzname1", true, Set.of(
+ new KandidatDTO("kandidatID1", "name1", 1L, true, 1L, true),
+ new KandidatDTO("kandidatID2", "name2", 2L, false, 2L, false))),
+ new WahlvorschlagDTO("id2", 2L, "kurzname2", false, Set.of(
+ new KandidatDTO("kandidatID3", "name3", 1L, true, 1L, true),
+ new KandidatDTO("kandidatID4", "name4", 2L, false, 2L, false)))));
+ }
+
+ private WahlvorschlaegeModel createWahlvorschlaegeModel(final String wahlID, final String wahlbezirkID) {
+ return new WahlvorschlaegeModel(new BezirkUndWahlID(wahlID, wahlbezirkID), "stimmzettelgebietID",
+ Set.of(
+ new WahlvorschlagModel("id1", 1L, "kurzname1", true, Set.of(
+ new KandidatModel("kandidatID1", "name1", 1L, true, 1L, true),
+ new KandidatModel("kandidatID2", "name2", 2L, false, 2L, false))),
+ new WahlvorschlagModel("id2", 2L, "kurzname2", false, Set.of(
+ new KandidatModel("kandidatID3", "name3", 1L, true, 1L, true),
+ new KandidatModel("kandidatID4", "name4", 2L, false, 2L, false)))));
+ }
+ }
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModelMapperTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModelMapperTest.java
new file mode 100644
index 000000000..622f86bb5
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeModelMapperTest.java
@@ -0,0 +1,66 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Kandidat;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Wahlvorschlaege;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Wahlvorschlag;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import java.util.Set;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mapstruct.factory.Mappers;
+
+class WahlvorschlaegeModelMapperTest {
+
+ private final WahlvorschlaegeModelMapper unitUnderTest = Mappers.getMapper(WahlvorschlaegeModelMapper.class);
+
+ @Test
+ void modelIsMappedToEntity() {
+ val modelToMap = createWahlvorschlaegeModel();
+
+ val result = unitUnderTest.toEntity(modelToMap);
+
+ val expectedResult = createWahlvorschlaegeEntity();
+ Assertions.assertThat(result).isEqualTo(expectedResult);
+ }
+
+ @Test
+ void entityIsMappedToModel() {
+ val entityToMap = createWahlvorschlaegeEntity();
+
+ val result = unitUnderTest.toModel(entityToMap);
+ val expectedResult = createWahlvorschlaegeModel();
+
+ Assertions.assertThat(result).isEqualTo(expectedResult);
+ }
+
+ private Wahlvorschlaege createWahlvorschlaegeEntity() {
+ val entity = new Wahlvorschlaege(null, new BezirkUndWahlID("wahlID", "wahlbezirkID"), "stimmzettelgebietID",
+ null);
+ val wahlvorschlag1 = new Wahlvorschlag(null, "id1", entity, 1L, "kurzname1", true, null);
+ val kandidat1 = new Kandidat(null, "kandidatID1", wahlvorschlag1, "name1", 1L, true, 1L, true);
+ val kandidat2 = new Kandidat(null, "kandidatID2", wahlvorschlag1, "name2", 2L, false, 2L, false);
+ wahlvorschlag1.setKandidaten(Set.of(kandidat1, kandidat2));
+
+ val wahlvorschlag2 = new Wahlvorschlag(null, "id2", entity, 2L, "kurzname2", false, null);
+ val kandidat3 = new Kandidat(null, "kandidatID3", wahlvorschlag2, "name3", 1L, true, 1L, true);
+ val kandidat4 = new Kandidat(null, "kandidatID4", wahlvorschlag2, "name4", 2L, false, 2L, false);
+ wahlvorschlag2.setKandidaten(Set.of(kandidat3, kandidat4));
+
+ entity.setWahlvorschlaege(Set.of(wahlvorschlag1, wahlvorschlag2));
+
+ return entity;
+ }
+
+ private WahlvorschlaegeModel createWahlvorschlaegeModel() {
+ return new WahlvorschlaegeModel(new BezirkUndWahlID("wahlID", "wahlbezirkID"), "stimmzettelgebietID",
+ Set.of(
+ new WahlvorschlagModel("id1", 1L, "kurzname1", true, Set.of(
+ new KandidatModel("kandidatID1", "name1", 1L, true, 1L, true),
+ new KandidatModel("kandidatID2", "name2", 2L, false, 2L, false))),
+ new WahlvorschlagModel("id2", 2L, "kurzname2", false, Set.of(
+ new KandidatModel("kandidatID3", "name3", 1L, true, 1L, true),
+ new KandidatModel("kandidatID4", "name4", 2L, false, 2L, false)))));
+ }
+
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeServiceSecurityTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeServiceSecurityTest.java
new file mode 100644
index 000000000..9cfc5ad02
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeServiceSecurityTest.java
@@ -0,0 +1,117 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.MicroServiceApplication;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.TestConstants;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.WahlvorschlaegeRepository;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.KandidatDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlaegeDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.eai.aou.model.WahlvorschlagDTO;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.utils.Authorities;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import de.muenchen.oss.wahllokalsystem.wls.common.testing.SecurityUtils;
+import java.util.Set;
+import java.util.stream.Stream;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.aggregator.ArgumentsAccessor;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.test.context.ActiveProfiles;
+
+@SpringBootTest(classes = MicroServiceApplication.class)
+@ActiveProfiles(TestConstants.SPRING_TEST_PROFILE)
+@AutoConfigureWireMock
+public class WahlvorschlaegeServiceSecurityTest {
+
+ @Autowired
+ WahlvorschlaegeService wahlvorschlaegeService;
+
+ @Autowired
+ WahlvorschlaegeRepository wahlvorschlaegeRepository;
+
+ @Autowired
+ ObjectMapper objectMapper;
+
+ @Nested
+ class GetWahlvorschlaege {
+
+ @AfterEach
+ void tearDown() {
+ SecurityUtils.runWith(Authorities.ALL_AUTHORITIES_DELETE_WAHLVORSCHLAEGE);
+ wahlvorschlaegeRepository.deleteAll();
+ }
+
+ @Test
+ void accessGranted() throws Exception {
+ SecurityUtils.runWith(Authorities.ALL_AUTHORITIES_GET_WAHLVORSCHLAEGE);
+
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ val eaiWahlvorschlaege = createClientWahlvorschlaegeDTO();
+ WireMock.stubFor(WireMock.get("/vorschlaege/wahl/" + wahlID + "/" + wahlbezirkID)
+ .willReturn(WireMock.aResponse().withHeader("Content-Type", "application/json").withStatus(HttpStatus.OK.value())
+ .withBody(objectMapper.writeValueAsBytes(eaiWahlvorschlaege))));
+
+ Assertions.assertThatNoException().isThrownBy(() -> wahlvorschlaegeService.getWahlvorschlaege(new BezirkUndWahlID(wahlID, wahlbezirkID)));
+ }
+
+ @ParameterizedTest(name = "{index} - {1} missing")
+ @MethodSource("getMissingAuthoritiesVariations")
+ void missingAuthorityCausesFailWithAccessDenied(final ArgumentsAccessor argumentsAccessor) throws Exception {
+ SecurityUtils.runWith(argumentsAccessor.get(0, String[].class));
+
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+
+ val eaiWahlvorschlaege = createClientWahlvorschlaegeDTO();
+ WireMock.stubFor(WireMock.get("/vorschlaege/wahl/" + wahlID + "/" + wahlbezirkID)
+ .willReturn(WireMock.aResponse().withHeader("Content-Type", "application/json").withStatus(HttpStatus.OK.value())
+ .withBody(objectMapper.writeValueAsBytes(eaiWahlvorschlaege))));
+
+ Assertions.assertThatException().isThrownBy(() -> wahlvorschlaegeService.getWahlvorschlaege(new BezirkUndWahlID(wahlID, wahlbezirkID)))
+ .isInstanceOf(
+ AccessDeniedException.class);
+ }
+
+ private static Stream getMissingAuthoritiesVariations() {
+ return SecurityUtils.buildArgumentsForMissingAuthoritiesVariations(Authorities.ALL_AUTHORITIES_DELETE_WAHLVORSCHLAEGE);
+ }
+
+ private WahlvorschlaegeDTO createClientWahlvorschlaegeDTO() {
+ val dto = new WahlvorschlaegeDTO();
+
+ dto.setStimmzettelgebietID("stimmzettelgebietID");
+ dto.setWahlbezirkID("wahlbezirkID");
+ dto.setWahlID("wahlID");
+
+ val wahlvorschlag1 = new WahlvorschlagDTO();
+ wahlvorschlag1.setIdentifikator("wahlvorschlagID");
+ wahlvorschlag1.setKurzname("kurzname");
+ wahlvorschlag1.setOrdnungszahl(1L);
+ wahlvorschlag1.setErhaeltStimmen(true);
+
+ val kandidat1 = new KandidatDTO();
+ kandidat1.setName("kandidat");
+ kandidat1.setListenposition(1L);
+ kandidat1.setEinzelbewerber(true);
+ kandidat1.setDirektkandidat(true);
+ kandidat1.setIdentifikator("kandidatID");
+ wahlvorschlag1.setKandidaten(Set.of(kandidat1));
+ dto.setWahlvorschlaege(Set.of(wahlvorschlag1));
+
+ return dto;
+ }
+ }
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeServiceTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeServiceTest.java
new file mode 100644
index 000000000..d75e67f05
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeServiceTest.java
@@ -0,0 +1,156 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Kandidat;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.KandidatRepository;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Wahlvorschlaege;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.WahlvorschlaegeRepository;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.Wahlvorschlag;
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.domain.WahlvorschlagRepository;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import lombok.val;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class WahlvorschlaegeServiceTest {
+
+ @Mock
+ WahlvorschlaegeRepository wahlvorschlaegeRepository;
+ @Mock
+ WahlvorschlagRepository wahlvorschlagRepository;
+ @Mock
+ KandidatRepository kandidatRepository;
+ @Mock
+ WahlvorschlaegeModelMapper wahlvorschlaegeModelMapper;
+ @Mock
+ WahlvorschlaegeValidator wahlvorschlaegeValidator;
+ @Mock
+ WahlvorschlaegeClient wahlvorschlaegeClient;
+
+ @InjectMocks
+ WahlvorschlaegeService unitUnderTest;
+
+ @Nested
+ class GetWahlvorschlaege {
+
+ @Test
+ void missingDataIsLoadedAndStored() {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+ val wahlUndBezirkID = new BezirkUndWahlID(wahlID, wahlbezirkID);
+
+ val mockedClientResponse = WahlvorschlaegeModel.builder().build();
+ val mockedWahlvorschlagEntity1 = new Wahlvorschlag();
+
+ val mockedKandidatEntity1 = new Kandidat();
+ mockedKandidatEntity1.setId(UUID.randomUUID());
+ val mockedKandidatEntity2 = new Kandidat();
+ mockedKandidatEntity2.setId(UUID.randomUUID());
+ mockedWahlvorschlagEntity1.setKandidaten(Set.of(mockedKandidatEntity1, mockedKandidatEntity2));
+ val mockedWahlvorschlagEntity2 = new Wahlvorschlag();
+
+ val mockedKandidatEntity3 = new Kandidat();
+ mockedKandidatEntity3.setId(UUID.randomUUID());
+ val mockedKandidatEntity4 = new Kandidat();
+ mockedKandidatEntity4.setId(UUID.randomUUID());
+ mockedWahlvorschlagEntity2.setKandidaten(Set.of(mockedKandidatEntity3, mockedKandidatEntity4));
+ val mockedMappedEntity = new Wahlvorschlaege();
+
+ mockedMappedEntity.setWahlvorschlaege(Set.of(mockedWahlvorschlagEntity1, mockedWahlvorschlagEntity2));
+
+ val mockedMappedSavedEntity = WahlvorschlaegeModel.builder().build();
+
+ Mockito.when(wahlvorschlaegeRepository.findByBezirkUndWahlID(wahlUndBezirkID)).thenReturn(Optional.empty());
+ Mockito.when(wahlvorschlaegeRepository.save(mockedMappedEntity)).thenReturn(mockedMappedEntity);
+ Mockito.when(wahlvorschlaegeClient.getWahlvorschlaege(wahlUndBezirkID)).thenReturn(mockedClientResponse);
+ Mockito.when(wahlvorschlaegeModelMapper.toEntity(mockedClientResponse)).thenReturn(mockedMappedEntity);
+ Mockito.when(wahlvorschlaegeModelMapper.toModel(mockedMappedEntity)).thenReturn(mockedMappedSavedEntity);
+
+ val result = unitUnderTest.getWahlvorschlaege(wahlUndBezirkID);
+
+ Assertions.assertThat(result).isSameAs(mockedMappedSavedEntity);
+ Mockito.verify(wahlvorschlaegeRepository).save(mockedMappedEntity);
+ Mockito.verify(wahlvorschlagRepository).save(mockedWahlvorschlagEntity1);
+ Mockito.verify(wahlvorschlagRepository).save(mockedWahlvorschlagEntity2);
+ Mockito.verify(kandidatRepository).saveAll(mockedWahlvorschlagEntity1.getKandidaten());
+ Mockito.verify(kandidatRepository).saveAll(mockedWahlvorschlagEntity2.getKandidaten());
+ }
+
+ @Test
+ void existingDataIsLoaded() {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+ val wahlUndBezirkID = new BezirkUndWahlID(wahlID, wahlbezirkID);
+
+ val mockedWahlvorschlaegeFromRepo = new Wahlvorschlaege();
+ val mockedMappedWahlvorschlaegeAsModel = WahlvorschlaegeModel.builder().build();
+
+ Mockito.when(wahlvorschlaegeRepository.findByBezirkUndWahlID(wahlUndBezirkID)).thenReturn(Optional.of(mockedWahlvorschlaegeFromRepo));
+ Mockito.when(wahlvorschlaegeModelMapper.toModel(mockedWahlvorschlaegeFromRepo)).thenReturn(mockedMappedWahlvorschlaegeAsModel);
+
+ val result = unitUnderTest.getWahlvorschlaege(wahlUndBezirkID);
+
+ Assertions.assertThat(result).isSameAs(mockedMappedWahlvorschlaegeAsModel);
+ Mockito.verify(wahlvorschlaegeClient, times(0)).getWahlvorschlaege(any());
+ }
+
+ @Test
+ void validationExceptionGotThrown() {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+ val wahlUndBezirkID = new BezirkUndWahlID(wahlID, wahlbezirkID);
+
+ val mockedValidationException = new RuntimeException("validation failed");
+
+ Mockito.doThrow(mockedValidationException).when(wahlvorschlaegeValidator).validWahlIdUndWahlbezirkIDOrThrow(wahlUndBezirkID);
+
+ Assertions.assertThatException().isThrownBy(() -> unitUnderTest.getWahlvorschlaege(wahlUndBezirkID)).isSameAs(mockedValidationException);
+ }
+
+ @Test
+ void clientExceptionGotThrown() {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+ val wahlUndBezirkID = new BezirkUndWahlID(wahlID, wahlbezirkID);
+
+ val mockedClientException = new RuntimeException("client failed");
+
+ Mockito.doThrow(mockedClientException).when(wahlvorschlaegeClient).getWahlvorschlaege(wahlUndBezirkID);
+
+ Assertions.assertThatException().isThrownBy(() -> unitUnderTest.getWahlvorschlaege(wahlUndBezirkID)).isSameAs(mockedClientException);
+ }
+
+ @Test
+ void persistingExceptionDoesntPreventFromResultObject() {
+ val wahlID = "wahlID";
+ val wahlbezirkID = "wahlbezirkID";
+ val wahlUndBezirkID = new BezirkUndWahlID(wahlID, wahlbezirkID);
+
+ val mockedWahlvorschlaegeModel = WahlvorschlaegeModel.builder().build();
+ val mockedWahlvorschlaegeEntity = new Wahlvorschlaege();
+ val mockedPersistingException = new RuntimeException("persisting failed");
+
+ Mockito.when(wahlvorschlaegeClient.getWahlvorschlaege(wahlUndBezirkID)).thenReturn(mockedWahlvorschlaegeModel);
+ Mockito.when(wahlvorschlaegeModelMapper.toEntity(mockedWahlvorschlaegeModel)).thenReturn(mockedWahlvorschlaegeEntity);
+ Mockito.doThrow(mockedPersistingException).when(wahlvorschlaegeRepository).save(mockedWahlvorschlaegeEntity);
+
+ val result = unitUnderTest.getWahlvorschlaege(wahlUndBezirkID);
+
+ Assertions.assertThat(result).isSameAs(mockedWahlvorschlaegeModel);
+ }
+
+ }
+
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeValidatorTest.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeValidatorTest.java
new file mode 100644
index 000000000..6920dacfa
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/services/wahlvorschlag/WahlvorschlaegeValidatorTest.java
@@ -0,0 +1,70 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.services.wahlvorschlag;
+
+import de.muenchen.oss.wahllokalsystem.basisdatenservice.exception.ExceptionConstants;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException;
+import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory;
+import de.muenchen.oss.wahllokalsystem.wls.common.security.domain.BezirkUndWahlID;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+@ExtendWith(MockitoExtension.class)
+class WahlvorschlaegeValidatorTest {
+
+ @Mock
+ ExceptionFactory exceptionFactory;
+
+ @InjectMocks
+ WahlvorschlaegeValidator unitUnderTest;
+
+ @Nested
+ class ValidWahlIdUndWahlbezirkIDOrThrow {
+
+ private final FachlicheWlsException mockedFachlicheWlsException = FachlicheWlsException.withCode("").buildWithMessage("");
+
+ @Test
+ void noExceptionWhenValid() {
+ Assertions.assertThatNoException().isThrownBy(() -> unitUnderTest.validWahlIdUndWahlbezirkIDOrThrow(new BezirkUndWahlID("wahlID", "wahlbezirkID")));
+ }
+
+ @Test
+ void exceptionWhenParameterIsNull() {
+ Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SUCHKRITERIEN_UNVOLLSTAENDIG)).thenReturn(mockedFachlicheWlsException);
+ Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validWahlIdUndWahlbezirkIDOrThrow(null)).isSameAs(mockedFachlicheWlsException);
+ }
+
+ @Test
+ void exceptionWhenWahlIDIsNull() {
+ Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SUCHKRITERIEN_UNVOLLSTAENDIG)).thenReturn(mockedFachlicheWlsException);
+ Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validWahlIdUndWahlbezirkIDOrThrow(new BezirkUndWahlID(null, "wahlbezirkID")))
+ .isSameAs(mockedFachlicheWlsException);
+ }
+
+ @Test
+ void exceptionWhenWahlIDIsEmptyString() {
+ Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SUCHKRITERIEN_UNVOLLSTAENDIG)).thenReturn(mockedFachlicheWlsException);
+ Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validWahlIdUndWahlbezirkIDOrThrow(new BezirkUndWahlID("", "wahlbezirkID")))
+ .isSameAs(mockedFachlicheWlsException);
+ }
+
+ @Test
+ void exceptionWhenWahlbezirkIDIsNull() {
+ Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SUCHKRITERIEN_UNVOLLSTAENDIG)).thenReturn(mockedFachlicheWlsException);
+ Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validWahlIdUndWahlbezirkIDOrThrow(new BezirkUndWahlID("wahlID", null)))
+ .isSameAs(mockedFachlicheWlsException);
+ }
+
+ @Test
+ void exceptionWhenWahlbezirkIDIsEmptyString() {
+ Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SUCHKRITERIEN_UNVOLLSTAENDIG)).thenReturn(mockedFachlicheWlsException);
+ Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validWahlIdUndWahlbezirkIDOrThrow(new BezirkUndWahlID("wahlID", "")))
+ .isSameAs(mockedFachlicheWlsException);
+ }
+ }
+
+}
diff --git a/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/utils/Authorities.java b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/utils/Authorities.java
new file mode 100644
index 000000000..e5f3b74d3
--- /dev/null
+++ b/wls-basisdaten-service/src/test/java/de/muenchen/oss/wahllokalsystem/basisdatenservice/utils/Authorities.java
@@ -0,0 +1,40 @@
+package de.muenchen.oss.wahllokalsystem.basisdatenservice.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class Authorities {
+
+ public static final String SERVICE_GET_WAHLVORSCHLAEGE = "Basisdaten_BUSINESSACTION_GetWahlvorschlaege";
+
+ public static final String REPOSITORY_READ_WAHLVORSCHLAEGE = "Basisdaten_READ_WLSWahlvorschlaege";
+ public static final String REPOSITORY_DELETE_WAHLVORSCHLAEGE = "Basisdaten_DELETE_WLSWahlvorschlaege";
+ public static final String REPOSITORY_WRITE_WAHLVORSCHLAEGE = "Basisdaten_WRITE_WLSWahlvorschlaege";
+
+ public static final String REPOSITORY_READ_WAHLVORSCHLAG = "Basisdaten_READ_Wahlvorschlag";
+ public static final String REPOSITORY_WRITE_WAHLVORSCHLAG = "Basisdaten_WRITE_Wahlvorschlag";
+ public static final String REPOSITORY_DELETE_WAHLVORSCHLAG = "Basisdaten_DELETE_Wahlvorschlag";
+
+ public static final String REPOSITORY_READ_KANDIDAT = "Basisdaten_READ_Kandidat";
+ public static final String REPOSITORY_WRITE_KANDIDAT = "Basisdaten_WRITE_Kandidat";
+ public static final String REPOSITORY_DELETE_KANDIDAT = "Basisdaten_DELETE_Kandidat";
+
+ public static final String[] ALL_AUTHORITIES_GET_WAHLVORSCHLAEGE = new String[] {
+ SERVICE_GET_WAHLVORSCHLAEGE,
+ REPOSITORY_READ_WAHLVORSCHLAEGE,
+ REPOSITORY_WRITE_WAHLVORSCHLAEGE,
+ REPOSITORY_WRITE_WAHLVORSCHLAG,
+ REPOSITORY_WRITE_KANDIDAT
+ };
+ public static final String[] ALL_AUTHORITIES_SET_WAHLVORSCHLAEGE = new String[] {
+ SERVICE_GET_WAHLVORSCHLAEGE,
+ REPOSITORY_READ_WAHLVORSCHLAEGE,
+ REPOSITORY_WRITE_WAHLVORSCHLAEGE
+ };
+
+ public static final String[] ALL_AUTHORITIES_DELETE_WAHLVORSCHLAEGE = new String[] {
+ REPOSITORY_DELETE_WAHLVORSCHLAEGE
+ };
+
+}
diff --git a/wls-basisdaten-service/src/main/resources/application-test.yml b/wls-basisdaten-service/src/test/resources/application-test.yml
similarity index 78%
rename from wls-basisdaten-service/src/main/resources/application-test.yml
rename to wls-basisdaten-service/src/test/resources/application-test.yml
index 562b25f44..7b6942275 100644
--- a/wls-basisdaten-service/src/main/resources/application-test.yml
+++ b/wls-basisdaten-service/src/test/resources/application-test.yml
@@ -1,5 +1,9 @@
-spring:
+app:
+ clients:
+ eai:
+ basePath: http://localhost:${wiremock.server.port}/
+spring:
# Spring JPA
h2.console.enabled: true
jpa:
@@ -9,10 +13,13 @@ spring:
# configuration for local (development) mode. this
# is also the default, that spring offers by convention.
# but here explicite:
- ddl-auto: create-drop
+ ddl-auto: validate
naming.physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# Logging for database operation
show-sql: true
properties:
hibernate:
format_sql: true
+wiremock:
+ server:
+ port: 0
diff --git a/wls-basisdaten-service/src/test/resources/http-client.env.json b/wls-basisdaten-service/src/test/resources/http-client.env.json
new file mode 100644
index 000000000..5efb2e017
--- /dev/null
+++ b/wls-basisdaten-service/src/test/resources/http-client.env.json
@@ -0,0 +1,6 @@
+{
+ "nonDocker": {
+ "WLS_BASISDATEN_SERVICE_URL": "http://localhost:39151",
+ "SSO_URL": "http://kubernetes.docker.internal:8100"
+ }
+}
\ No newline at end of file
diff --git a/wls-basisdaten-service/src/test/resources/wahlvorstand.http b/wls-basisdaten-service/src/test/resources/wahlvorstand.http
new file mode 100644
index 000000000..ceec5e39b
--- /dev/null
+++ b/wls-basisdaten-service/src/test/resources/wahlvorstand.http
@@ -0,0 +1,22 @@
+### Get token wls_all
+POST {{ SSO_URL }}/auth/realms/wls_realm/protocol/openid-connect/token
+Content-Type: application/x-www-form-urlencoded
+
+password = test &
+grant_type = password &
+client_secret = top-secret &
+client_id = wls &
+username = wls_all
+
+> {%
+ client.global.set("auth_token", response.body.access_token);
+ client.global.set("token_type", response.body.token_type);
+%}
+
+### get userinfo with auth_token
+GET {{ SSO_URL }}/auth/realms/wls_realm/protocol/openid-connect/userinfo
+Authorization: {{ token_type }} {{ auth_token }}
+
+### Get Basisdaten - working with dummy.client
+GET {{ WLS_BASISDATEN_SERVICE_URL }}/businessActions/wahlvorschlaege/wahlID/wahlbezirkID
+Authorization: {{ token_type }} {{ auth_token }}
\ No newline at end of file