diff --git a/stack/keycloak/migration/add-authorities-eai-wahlvorstand.yml b/stack/keycloak/migration/add-authorities-eai-wahlvorstand.yml new file mode 100644 index 000000000..a5b5c17e1 --- /dev/null +++ b/stack/keycloak/migration/add-authorities-eai-wahlvorstand.yml @@ -0,0 +1,21 @@ +id: add authorities eai wahlvorstand +author: MrSebastian +realm: ${SSO_REALM} +changes: + - addRole: + name: aoueai_BUSINESSACTION_LoadWahlvorstand + clientRole: true + clientId: ${SSO_CLIENT_ID} + - assignRoleToGroup: + group: allEaiAuthorities + role: aoueai_BUSINESSACTION_LoadWahlvorstand + clientId: ${SSO_CLIENT_ID} + + - addRole: + name: aoueai_BUSINESSACTION_SaveAnwesenheit + clientRole: true + clientId: ${SSO_CLIENT_ID} + - assignRoleToGroup: + group: allEaiAuthorities + role: aoueai_BUSINESSACTION_SaveAnwesenheit + clientId: ${SSO_CLIENT_ID} \ No newline at end of file diff --git a/stack/keycloak/migration/create-group-all-eai-authorities.yml b/stack/keycloak/migration/create-group-all-eai-authorities.yml new file mode 100644 index 000000000..015b47dc9 --- /dev/null +++ b/stack/keycloak/migration/create-group-all-eai-authorities.yml @@ -0,0 +1,15 @@ +id: create group allEaiAuthorities and link wls_all* +author: MrSebastian +realm: ${SSO_REALM} +changes: + - addGroup: + name: allEaiAuthorities + - assignGroup: + user: wls_all + group: allEaiAuthorities + - assignGroup: + user: wls_all_uwb + group: allEaiAuthorities + - assignGroup: + user: wls_all_bwb + group: allEaiAuthorities \ No newline at end of file diff --git a/stack/keycloak/migration/keycloak-changelog.yml b/stack/keycloak/migration/keycloak-changelog.yml index ea3d31327..35b17808c 100644 --- a/stack/keycloak/migration/keycloak-changelog.yml +++ b/stack/keycloak/migration/keycloak-changelog.yml @@ -26,3 +26,5 @@ includes: - path: add-authorities-wahlvorbereitung-fortsetzungsuhrzeit.yml - path: add-authorities-wahlvorbereitung-eroeffnungsuhrzeit.yml - path: add-authorities-wahlvorbereitung-urnenwahlschliessungsuhrzeit.yml + - path: create-group-all-eai-authorities.yml + - path: add-authorities-eai-wahlvorstand.yml \ No newline at end of file diff --git a/wls-eai-service/checkstyle.xml b/wls-eai-service/checkstyle.xml index 37f7f0e7b..14f0ae031 100644 --- a/wls-eai-service/checkstyle.xml +++ b/wls-eai-service/checkstyle.xml @@ -14,6 +14,11 @@ + + + + + diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/MicroServiceApplication.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/MicroServiceApplication.java index 114c80e4c..bdafd4223 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/MicroServiceApplication.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/MicroServiceApplication.java @@ -18,7 +18,8 @@ @ComponentScan( basePackages = { "org.springframework.data.jpa.convert.threeten", - "de.muenchen.oss.wahllokalsystem.eaiservice" + "de.muenchen.oss.wahllokalsystem.eaiservice", + "de.muenchen.oss.wahllokalsystem.wls.common.exception" } ) @EntityScan( diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/BaseEntity.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/BaseEntity.java index 48ec8a46f..d5d7ceca5 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/BaseEntity.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/BaseEntity.java @@ -6,7 +6,6 @@ import static java.sql.Types.VARCHAR; -import jakarta.persistence.Column; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.MappedSuperclass; @@ -17,24 +16,24 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.annotations.UuidGenerator; @MappedSuperclass @NoArgsConstructor @Getter @Setter -@ToString +@ToString(onlyExplicitlyIncluded = true) @EqualsAndHashCode public abstract class BaseEntity implements Cloneable, Serializable { private static final long serialVersionUID = 1L; - @Column(name = "id", length = 36) @Id @GeneratedValue(generator = "uuid") - @GenericGenerator(name = "uuid", strategy = "uuid2") + @UuidGenerator @JdbcTypeCode(VARCHAR) + @ToString.Include private UUID id; } diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/Wahlvorstand.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/Wahlvorstand.java new file mode 100644 index 000000000..0ba36db9d --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/Wahlvorstand.java @@ -0,0 +1,39 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand; + +import static java.sql.Types.VARCHAR; + +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.BaseEntity; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.validation.constraints.NotNull; +import java.util.Collection; +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; + +@Entity +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@ToString(onlyExplicitlyIncluded = true, callSuper = true) +public class Wahlvorstand extends BaseEntity { + + @NotNull + @ToString.Include + @JdbcTypeCode(VARCHAR) + private UUID wahlbezirkID; + + @OneToMany(cascade = CascadeType.ALL) + @JoinColumn(name = "wahlvorstandid") + private Collection mitglieder; + +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/WahlvorstandRepository.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/WahlvorstandRepository.java new file mode 100644 index 000000000..ed57b93d5 --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/WahlvorstandRepository.java @@ -0,0 +1,10 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand; + +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.repository.CrudRepository; + +public interface WahlvorstandRepository extends CrudRepository { + + Optional findFirstByWahlbezirkID(UUID wahlbezirkID); +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/Wahlvorstandsmitglied.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/Wahlvorstandsmitglied.java new file mode 100644 index 000000000..897ee8720 --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/Wahlvorstandsmitglied.java @@ -0,0 +1,43 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.BaseEntity; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Entity +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +@ToString(onlyExplicitlyIncluded = true) +public class Wahlvorstandsmitglied extends BaseEntity { + + @NotNull + @ToString.Include + private String vorname; + + @NotNull + @ToString.Include + private String nachname; + + @NotNull + @ToString.Include + @Enumerated(EnumType.STRING) + private WahlvorstandsmitgliedsFunktion funktion; + + @ToString.Include + private boolean anwesend; + + @ToString.Include + private LocalDateTime anwesenheitUpdatedOn; +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/WahlvorstandsmitgliedsFunktion.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/WahlvorstandsmitgliedsFunktion.java new file mode 100644 index 000000000..d25698de8 --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/domain/wahlvorstand/WahlvorstandsmitgliedsFunktion.java @@ -0,0 +1,9 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand; + +public enum WahlvorstandsmitgliedsFunktion { + W, //Wahlvorsteher*in + SB, //Schriftführer*in + SWB, //Stellvertretung Wahlvorsteher*in + SSB, //Stellvertretung Schriftführer*in + B //Beisitzer*in +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/GlobalExceptionHandler.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/GlobalExceptionHandler.java new file mode 100644 index 000000000..e88960d3d --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/GlobalExceptionHandler.java @@ -0,0 +1,38 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.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)); + } + + @ExceptionHandler + public ResponseEntity handleNotFoundException(final NotFoundException notFoundException) { + log.debug("not found entity {} with id {}", notFoundException.getEntityClass(), notFoundException.getRequestedID()); + return ResponseEntity.notFound().build(); + } + + @Override + protected String getService() { + return serviceIDFormatter.getId(); + } +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/NotFoundException.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/NotFoundException.java new file mode 100644 index 000000000..3a144d606 --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/NotFoundException.java @@ -0,0 +1,17 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.exception; + +import java.util.UUID; +import lombok.Getter; + +@Getter +public class NotFoundException extends RuntimeException { + + private final UUID requestedID; + + private final Class entityClass; + + public NotFoundException(UUID requestID, Class entityClass) { + this.requestedID = requestID; + this.entityClass = entityClass; + } +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/common/exception/ExceptionConstants.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/common/exception/ExceptionConstants.java index 81382e8ff..16096ad26 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/common/exception/ExceptionConstants.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/common/exception/ExceptionConstants.java @@ -1,15 +1,21 @@ package de.muenchen.oss.wahllokalsystem.eaiservice.rest.common.exception; -public class ExceptionConstants { +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionDataWrapper; - public static final String CODE_DATENALLGEMEIN_ID_NICHT_KONVERTIERBAR = "103"; +public class ExceptionConstants { public static final String CODE_FEHLER_BEI_KOMMUNIKATIONS_MIT_FREMDSYSTEM = "901"; public static final String MESSAGE_FEHLER_BEI_KOMMUNIKATIONS_MIT_FREMDSYSTEM = "Fremdsystem hat Fehler geworfen"; public static final String MESSAGE_FEHLER_BEI_KOMMUNIKATIONS_MIT_FREMDSYSTEM_MIT_MESSAGE = "Fremdsystem hat Fehler geworfen: %s"; - public static final String CODE_DATENALLGEMEIN_PARAMETER_FEHLEN = "102"; - public static final String MESSAGE_DATENALLGEMEIN_PARAMETER_FEHLEN = "Anfrage ist ungueltig da notwendige Anfragedaten fehlen"; + private static final String CODE_DATENALLGEMEIN_PARAMETER_FEHLEN = "102"; + private static final String MESSAGE_DATENALLGEMEIN_PARAMETER_FEHLEN = "Anfrage ist ungueltig da notwendige Anfragedaten fehlen"; + public static final ExceptionDataWrapper DATENALLGEMEIN_PARAMETER_FEHLEN = new ExceptionDataWrapper(CODE_DATENALLGEMEIN_PARAMETER_FEHLEN, + MESSAGE_DATENALLGEMEIN_PARAMETER_FEHLEN); + + private static final String CODE_DATENALLGEMEIN_ID_NICHT_KONVERTIERBAR = "103"; + public static final ExceptionDataWrapper ID_NICHT_KONVERTIERBAR = new ExceptionDataWrapper( + CODE_DATENALLGEMEIN_ID_NICHT_KONVERTIERBAR, ""); /** * @throws IllegalAccessException when constructor is used diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandController.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandController.java index 740b3fb84..b6140507d 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandController.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandController.java @@ -2,29 +2,33 @@ import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandDTO; import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; -import jakarta.validation.Valid; -import org.springframework.http.HttpStatus; +import de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand.WahlvorstandService; +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/wahlvorstaende") +@RequiredArgsConstructor public class WahlvorstandController { + private final WahlvorstandService wahlvorstandService; + @GetMapping - @ResponseStatus(HttpStatus.OK) - public WahlvorstandDTO loadWahlvorstand(@RequestParam("wahlbezirkID") String wahlbezirkID) { - throw new UnsupportedOperationException("Not supported yet."); + @Operation(description = "Abrufen des Wahlvorstandes für einen bestimmten Wahlbezirk") + public WahlvorstandDTO loadWahlvorstand(final @RequestParam("wahlbezirkID") + String wahlbezirkID) { + return wahlvorstandService.getWahlvorstandForWahlbezirk(wahlbezirkID); } - @PostMapping - @ResponseStatus(HttpStatus.OK) - public void saveAnwesenheit(@Valid @RequestBody WahlvorstandsaktualisierungDTO wahlvorstand) { - throw new UnsupportedOperationException("Not supported yet."); + @PutMapping("anwesenheit") + @Operation(description = "Aktualisieren der Anwesenheit der Wahlvorstandsmitglieder eines bestimmten Wahlbezirkes") + public void saveAnwesenheit(@RequestBody WahlvorstandsaktualisierungDTO wahlvorstand) { + wahlvorstandService.setAnwesenheit(wahlvorstand); } } diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandDTO.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandDTO.java index 7b7d3b8dc..99f807cf8 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandDTO.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandDTO.java @@ -2,10 +2,8 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; -import java.time.LocalDateTime; import java.util.Set; -public record WahlvorstandDTO(@NotNull LocalDateTime anwesenheitBeginn, - @NotNull String wahlbezirkID, +public record WahlvorstandDTO(@NotNull String wahlbezirkID, @NotNull @Size(min = 1) Set mitglieder) { } diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsaktualisierungDTO.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsaktualisierungDTO.java index 7183cb596..a04462a06 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsaktualisierungDTO.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsaktualisierungDTO.java @@ -4,7 +4,9 @@ import jakarta.validation.constraints.Size; import java.time.LocalDateTime; import java.util.Set; +import lombok.Builder; +@Builder public record WahlvorstandsaktualisierungDTO(@NotNull String wahlbezirkID, @NotNull @Size(min = 1) Set mitglieder, @NotNull LocalDateTime anwesenheitBeginn) { diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedAktualisierungDTO.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedAktualisierungDTO.java index a11a7276d..a021d9439 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedAktualisierungDTO.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedAktualisierungDTO.java @@ -2,7 +2,9 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import lombok.Builder; +@Builder public record WahlvorstandsmitgliedAktualisierungDTO(@NotNull String identifikator, @Schema(requiredMode = Schema.RequiredMode.REQUIRED) boolean anwesend) { } diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedDTO.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedDTO.java index 16476c667..1218eb5e0 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedDTO.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedDTO.java @@ -2,10 +2,12 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; +import lombok.Builder; +@Builder public record WahlvorstandsmitgliedDTO(@NotNull String identifikator, @NotNull String vorname, @NotNull String nachname, - @NotNull String funktion, + @NotNull WahlvorstandsmitgliedsFunktionDTO funktion, @Schema(requiredMode = Schema.RequiredMode.REQUIRED) boolean anwesend) { } diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedsFunktionDTO.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedsFunktionDTO.java new file mode 100644 index 000000000..8959983e7 --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/dto/WahlvorstandsmitgliedsFunktionDTO.java @@ -0,0 +1,9 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto; + +public enum WahlvorstandsmitgliedsFunktionDTO { + W, //Wahlvorsteher*in + SB, //Schriftführer*in + SWB, //Stellvertretung Wahlvorsteher*in + SSB, //Stellvertretung Schriftführer*in + B //Beisitzer*in +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/exception/ExceptionConstants.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/exception/ExceptionConstants.java index c6a90747e..364f168a4 100644 --- a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/exception/ExceptionConstants.java +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/exception/ExceptionConstants.java @@ -1,21 +1,33 @@ package de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.exception; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionDataWrapper; + public class ExceptionConstants { //loadWahlvorstand - public static final String CODE_LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG = "001"; - public static final String MESSAGE_LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG = "Wahlvorstandskriterien sind nicht vollständig"; + private static final String CODE_LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG = "001"; + private static final String MESSAGE_LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG = "Wahlvorstandskriterien sind nicht vollständig"; + public static final ExceptionDataWrapper LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG = new ExceptionDataWrapper( + CODE_LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG, MESSAGE_LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG); //saveAnwesenheit - public static final String CODE_SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT = "002"; - public static final String MESSAGE_SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT = "Mindestens ein Identifikator für eine Aktualisierung fehlt"; + private static final String CODE_SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT = "002"; + private static final String MESSAGE_SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT = "Mindestens ein Identifikator für eine Aktualisierung fehlt"; + public static final ExceptionDataWrapper SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT = new ExceptionDataWrapper(CODE_SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT, + MESSAGE_SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT); - public static final String CODE_SAVEANWESENHEIT_BEZIRKID_FEHLT = "003"; - public static final String MESSAGE_SAVEANWESENHEIT_BEZIRKID_FEHLT = "Bezirk fehlt"; + private static final String CODE_SAVEANWESENHEIT_BEZIRKID_FEHLT = "003"; + private static final String MESSAGE_SAVEANWESENHEIT_BEZIRKID_FEHLT = "Bezirk fehlt"; + public static final ExceptionDataWrapper SAVEANWESENHEIT_BEZIRKID_FEHLT = new ExceptionDataWrapper(CODE_SAVEANWESENHEIT_BEZIRKID_FEHLT, + MESSAGE_SAVEANWESENHEIT_BEZIRKID_FEHLT); - public static final String CODE_SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT = "004"; - public static final String MESSAGE_SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT = "Es ist keine Information hinterlegt seit wann diese Anwesenheit gilt"; + private static final String CODE_SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT = "004"; + private static final String MESSAGE_SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT = "Es ist keine Information hinterlegt seit wann diese Anwesenheit gilt"; + public static final ExceptionDataWrapper SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT = new ExceptionDataWrapper(CODE_SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT, + MESSAGE_SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT); - public static final String CODE_DATENALLGEMEIN_WAHLVORSTANDSMITGLIEDFUNKTION_UNGUELTIGE_FUNKTION = "101"; - public static final String MESSAGE_DATENALLGEMEIN_WAHLVORSTANDSMITGLIEDFUNKTION_UNGUELTIGE_FUNKTION = "Die definierte Funktion des Wahlvorstandsmitgliedes ist nicht gueltig"; + private static final String CODE_DATENALLGEMEIN_WAHLVORSTANDSMITGLIEDFUNKTION_UNGUELTIGE_FUNKTION = "101"; + private static final String MESSAGE_DATENALLGEMEIN_WAHLVORSTANDSMITGLIEDFUNKTION_UNGUELTIGE_FUNKTION = "Die definierte Funktion des Wahlvorstandsmitgliedes ist nicht gueltig"; + public static final ExceptionDataWrapper DATENALLGEMEIN_WAHLVORSTANDSMITGLIEDFUNKTION_UNGUELTIGE_FUNKTION = new ExceptionDataWrapper( + CODE_DATENALLGEMEIN_WAHLVORSTANDSMITGLIEDFUNKTION_UNGUELTIGE_FUNKTION, MESSAGE_DATENALLGEMEIN_WAHLVORSTANDSMITGLIEDFUNKTION_UNGUELTIGE_FUNKTION); /** * @throws IllegalAccessException when constructor is used diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandMapper.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandMapper.java new file mode 100644 index 000000000..6c626471b --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandMapper.java @@ -0,0 +1,17 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstand; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstandsmitglied; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedDTO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper +public interface WahlvorstandMapper { + + WahlvorstandDTO toDTO(Wahlvorstand wahlvorstand); + + @Mapping(target = "identifikator", source = "id") + WahlvorstandsmitgliedDTO toDTO(Wahlvorstandsmitglied wahlvorstandsmitglied); +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandService.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandService.java new file mode 100644 index 000000000..3b2c971ca --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandService.java @@ -0,0 +1,75 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstand; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.WahlvorstandRepository; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstandsmitglied; +import de.muenchen.oss.wahllokalsystem.eaiservice.exception.NotFoundException; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.common.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedAktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; +import java.time.LocalDateTime; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class WahlvorstandService { + + private final WahlvorstandRepository wahlvorstandRepository; + + private final ExceptionFactory exceptionFactory; + + private final WahlvorstandMapper wahlvorstandMapper; + + private final WahlvorstandValidator wahlvorstandValidator; + + @PreAuthorize("hasAuthority('aoueai_BUSINESSACTION_LoadWahlvorstand')") + public WahlvorstandDTO getWahlvorstandForWahlbezirk(final String wahlbezirkID) { + wahlvorstandValidator.validateWahlbezirkIDOrThrow(wahlbezirkID); + val wahlbezirkUUID = convertIDToUUIDOrThrow(wahlbezirkID); + return wahlvorstandMapper.toDTO(findByWahlbezirkIDOrThrow(wahlbezirkUUID)); + } + + @PreAuthorize("hasAuthority('aoueai_BUSINESSACTION_SaveAnwesenheit')") + public void setAnwesenheit(final WahlvorstandsaktualisierungDTO aktualisierung) { + wahlvorstandValidator.validateSaveAnwesenheitDataOrThrow(aktualisierung); + + val wahlvorstandToUpdate = findByWahlbezirkIDOrThrow(convertIDToUUIDOrThrow(aktualisierung.wahlbezirkID())); + updateAnwesenheitOfWahlvorstand(aktualisierung, wahlvorstandToUpdate); + wahlvorstandRepository.save(wahlvorstandToUpdate); + } + + private void updateAnwesenheitOfWahlvorstand(final WahlvorstandsaktualisierungDTO updateData, final Wahlvorstand existingWahlvorstand) { + updateData.mitglieder().forEach(mitgliedUpdateData -> { + val mitgliedToUpdate = existingWahlvorstand.getMitglieder().stream() + .filter(setElement -> setElement.getId().toString().equals(mitgliedUpdateData.identifikator())).findFirst(); + mitgliedToUpdate.ifPresent(mitglied -> updateAnwesenheitOfWahlvorstandsmitglied(updateData.anwesenheitBeginn(), mitgliedUpdateData, mitglied)); + }); + } + + private void updateAnwesenheitOfWahlvorstandsmitglied(final LocalDateTime timeOfUpdate, WahlvorstandsmitgliedAktualisierungDTO mitgliedUpdateData, + Wahlvorstandsmitglied mitglied) { + mitglied.setAnwesenheitUpdatedOn(timeOfUpdate); + mitglied.setAnwesend(mitgliedUpdateData.anwesend()); + } + + //CHECKSTYLE.OFF: AbbreviationAsWordInName - illegal match cause UUID should not be shortened + private UUID convertIDToUUIDOrThrow(final String id) { + //CHECKSTYLE.ON: AbbreviationAsWordInName + try { + return UUID.fromString(id); + } catch (final IllegalArgumentException illegalArgumentException) { + throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.ID_NICHT_KONVERTIERBAR); + } + } + + private Wahlvorstand findByWahlbezirkIDOrThrow(final UUID wahlbezirkID) { + return wahlvorstandRepository.findFirstByWahlbezirkID(wahlbezirkID).orElseThrow(() -> new NotFoundException(wahlbezirkID, Wahlvorstand.class)); + } + +} diff --git a/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandValidator.java b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandValidator.java new file mode 100644 index 000000000..9bf8fa606 --- /dev/null +++ b/wls-eai-service/src/main/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandValidator.java @@ -0,0 +1,41 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class WahlvorstandValidator { + + private final ExceptionFactory exceptionFactory; + + public void validateWahlbezirkIDOrThrow(final String wahlbezirkID) { + if (StringUtils.isBlank(wahlbezirkID)) { + throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG); + } + } + + public void validateSaveAnwesenheitDataOrThrow(final WahlvorstandsaktualisierungDTO saveAnwesenheitData) { + if (saveAnwesenheitData == null) { + throw exceptionFactory.createFachlicheWlsException( + de.muenchen.oss.wahllokalsystem.eaiservice.rest.common.exception.ExceptionConstants.DATENALLGEMEIN_PARAMETER_FEHLEN); + } + + if (StringUtils.isBlank(saveAnwesenheitData.wahlbezirkID())) { + throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_BEZIRKID_FEHLT); + } + + if (saveAnwesenheitData.anwesenheitBeginn() == null) { + throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT); + } + + if (saveAnwesenheitData.mitglieder() != null && saveAnwesenheitData.mitglieder().stream() + .anyMatch(mitglied -> StringUtils.isBlank(mitglied.identifikator()))) { + throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT); + } + } +} diff --git a/wls-eai-service/src/main/resources/application-db-dummydata.yml b/wls-eai-service/src/main/resources/application-db-dummydata.yml new file mode 100644 index 000000000..41e67be65 --- /dev/null +++ b/wls-eai-service/src/main/resources/application-db-dummydata.yml @@ -0,0 +1,5 @@ +spring: + flyway: + locations: + - classpath:db/migrations/{vendor} + - classpath:db/dummydata/{vendor} \ No newline at end of file diff --git a/wls-eai-service/src/main/resources/application.yml b/wls-eai-service/src/main/resources/application.yml index f19584667..7e2751c2f 100644 --- a/wls-eai-service/src/main/resources/application.yml +++ b/wls-eai-service/src/main/resources/application.yml @@ -14,7 +14,8 @@ spring: oauth2: resourceserver: jwt: - jwk-set-uri: http://kubernetes.docker.internal:8100/auth/realms/${realm}/protocol/openid-connect/userinfo + jwk-set-uri: http://kubernetes.docker.internal:8100/auth/realms/${realm}/protocol/openid-connect/certs + @@ -24,6 +25,9 @@ security: oauth2: resource.user-info-uri: http://kubernetes.docker.internal:8100/auth/realms/${realm}/protocol/openid-connect/userinfo +service: + info: + oid: EAI-SERVICE # Define the local keycloak realm here realm: wls_realm @@ -36,6 +40,7 @@ server: include-stacktrace: never whitelabel: enabled: false + max-http-request-header-size: 32KB # Config for spring actuator endpoints management: diff --git a/wls-eai-service/src/main/resources/db/dummydata/h2/V1_1__wahlvorstandTestdaten.sql b/wls-eai-service/src/main/resources/db/dummydata/h2/V1_1__wahlvorstandTestdaten.sql new file mode 100644 index 000000000..ce912857a --- /dev/null +++ b/wls-eai-service/src/main/resources/db/dummydata/h2/V1_1__wahlvorstandTestdaten.sql @@ -0,0 +1,74 @@ +INSERT INTO wahlvorstand +VALUES ('00000000-0000-0000-0001-000000000001', '00000000-0000-0000-0000-000000000001'); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000001', 'Homer', 'Simpson', 'W', false, '00000000-0000-0000-0001-000000000001', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000002', 'Marge', 'Simpson', 'SB', false, '00000000-0000-0000-0001-000000000001', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000003', 'Bart', 'Simpson', 'SWB', false, + '00000000-0000-0000-0001-000000000001', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000004', 'Lisa', 'Simpson', 'SSB', false, '00000000-0000-0000-0001-000000000001', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000005', 'Maggie', 'Simpson', 'B', false, '00000000-0000-0000-0001-000000000001', + null); + +INSERT INTO wahlvorstand +VALUES ('00000000-0000-0000-0001-000000000002', '00000000-0000-0000-0000-000000000002'); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000001', 'Peter', 'Griffin', 'W', false, '00000000-0000-0000-0001-000000000002', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000002', 'Lois', 'Griffin', 'SB', false, '00000000-0000-0000-0001-000000000002', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000003', 'Megan', 'Griffin', 'SWB', false, + '00000000-0000-0000-0001-000000000002', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000004', 'Christopher', 'Griffin', 'SSB', false, + '00000000-0000-0000-0001-000000000002', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000005', 'Stewie', 'Griffin', 'B', false, '00000000-0000-0000-0001-000000000002', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000006', 'Brian', 'Griffin', 'B', false, '00000000-0000-0000-0001-000000000002', + null); + +INSERT INTO wahlvorstand +VALUES ('00000000-0000-0000-0001-000000000003', '00000000-0000-0000-0000-000000000003'); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000001', 'Grace', 'Hopper', 'W', false, '00000000-0000-0000-0001-000000000003', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000002', 'Ada', 'Lovelace', 'SB', false, + '00000000-0000-0000-0001-000000000003', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000003', 'Konrad', 'Zuse', 'SWB', false, + '00000000-0000-0000-0001-000000000003', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000004', 'Alan', 'Turing', 'SSB', false, + '00000000-0000-0000-0001-000000000003', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000005', 'Hedy', 'Lamarr', 'B', false, + '00000000-0000-0000-0001-000000000003', null); + +INSERT INTO wahlvorstand +VALUES ('00000000-0000-0000-0001-000000000004', '00000000-0000-0000-0000-000000000004'); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000001', 'Diana', 'Prince', 'W', false, '00000000-0000-0000-0001-000000000004', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000002', 'Clark', 'Kent', 'SB', false, '00000000-0000-0000-0001-000000000004', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000003', 'Bruce', 'Wayne', 'SWB', false, + '00000000-0000-0000-0001-000000000004', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000004', 'Barry', 'Allen', 'SSB', false, '00000000-0000-0000-0001-000000000004', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000005', 'Arthur', 'Curry', 'B', false, '00000000-0000-0000-0001-000000000004', + null); \ No newline at end of file diff --git a/wls-eai-service/src/main/resources/db/dummydata/oracle/V1_1__wahlvorstandTestdaten.sql b/wls-eai-service/src/main/resources/db/dummydata/oracle/V1_1__wahlvorstandTestdaten.sql new file mode 100644 index 000000000..b84ba42b2 --- /dev/null +++ b/wls-eai-service/src/main/resources/db/dummydata/oracle/V1_1__wahlvorstandTestdaten.sql @@ -0,0 +1,74 @@ +INSERT INTO wahlvorstand +VALUES ('00000000-0000-0000-0001-000000000001', '00000000-0000-0000-0000-000000000001'); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000001', 'Homer', 'Simpson', 'W', 0, '00000000-0000-0000-0001-000000000001', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000002', 'Marge', 'Simpson', 'SB', 0, '00000000-0000-0000-0001-000000000001', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000003', 'Bart', 'Simpson', 'SWB', 0, + '00000000-0000-0000-0001-000000000001', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000004', 'Lisa', 'Simpson', 'SSB', 0, '00000000-0000-0000-0001-000000000001', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0001-000000000005', 'Maggie', 'Simpson', 'B', 0, '00000000-0000-0000-0001-000000000001', + null); + +INSERT INTO wahlvorstand +VALUES ('00000000-0000-0000-0001-000000000002', '00000000-0000-0000-0000-000000000002'); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000001', 'Peter', 'Griffin', 'W', 0, '00000000-0000-0000-0001-000000000002', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000002', 'Lois', 'Griffin', 'SB', 0, '00000000-0000-0000-0001-000000000002', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000003', 'Megan', 'Griffin', 'SWB', 0, + '00000000-0000-0000-0001-000000000002', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000004', 'Christopher', 'Griffin', 'SSB', 0, + '00000000-0000-0000-0001-000000000002', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000005', 'Stewie', 'Griffin', 'B', 0, '00000000-0000-0000-0001-000000000002', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0002-000000000006', 'Brian', 'Griffin', 'B', 0, '00000000-0000-0000-0001-000000000002', + null); + +INSERT INTO wahlvorstand +VALUES ('00000000-0000-0000-0001-000000000003', '00000000-0000-0000-0000-000000000003'); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000001', 'Grace', 'Hopper', 'W', 0, '00000000-0000-0000-0001-000000000003', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000002', 'Ada', 'Lovelace', 'SB', 0, + '00000000-0000-0000-0001-000000000003', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000003', 'Konrad', 'Zuse', 'SWB', 0, + '00000000-0000-0000-0001-000000000003', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000004', 'Alan', 'Turing', 'SSB', 0, + '00000000-0000-0000-0001-000000000003', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0003-000000000005', 'Hedy', 'Lamarr', 'B', 0, + '00000000-0000-0000-0001-000000000003', null); + +INSERT INTO wahlvorstand +VALUES ('00000000-0000-0000-0001-000000000004', '00000000-0000-0000-0000-000000000004'); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000001', 'Diana', 'Prince', 'W', 0, '00000000-0000-0000-0001-000000000004', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000002', 'Clark', 'Kent', 'SB', 0, '00000000-0000-0000-0001-000000000004', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000003', 'Bruce', 'Wayne', 'SWB', 0, + '00000000-0000-0000-0001-000000000004', null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000004', 'Barry', 'Allen', 'SSB', 0, '00000000-0000-0000-0001-000000000004', + null); +INSERT INTO wahlvorstandsmitglied +VALUES ('00000000-0000-0000-0004-000000000005', 'Arthur', 'Curry', 'B', 0, '00000000-0000-0000-0001-000000000004', + null); \ No newline at end of file diff --git a/wls-eai-service/src/main/resources/db/migrations/h2/V1_0__createWahlvorstand.sql b/wls-eai-service/src/main/resources/db/migrations/h2/V1_0__createWahlvorstand.sql new file mode 100644 index 000000000..fdab5b2c3 --- /dev/null +++ b/wls-eai-service/src/main/resources/db/migrations/h2/V1_0__createWahlvorstand.sql @@ -0,0 +1,22 @@ +CREATE TABLE wahlvorstand +( + id VARCHAR2(36) NOT NULL, + wahlbezirkID VARCHAR2(36) NOT NULL, + + PRIMARY KEY (id) +); + +CREATE TABLE wahlvorstandsmitglied +( + id VARCHAR2(36) NOT NULL, + vorname VARCHAR2(255) NOT NULL, + nachname VARCHAR2(255) NOT NULL, + funktion VARCHAR2(512) NOT NULL, + anwesend boolean NOT NULL, + wahlvorstandID VARCHAR2(36) NOT NULL, + anwesenheitUpdatedOn TIMESTAMP, + + FOREIGN KEY (wahlvorstandID) REFERENCES wahlvorstand (id), + + PRIMARY KEY (id) +) \ No newline at end of file diff --git a/wls-eai-service/src/main/resources/db/migrations/oracle/V1_0__createWahlvorstand.sql b/wls-eai-service/src/main/resources/db/migrations/oracle/V1_0__createWahlvorstand.sql new file mode 100644 index 000000000..4d48f5af7 --- /dev/null +++ b/wls-eai-service/src/main/resources/db/migrations/oracle/V1_0__createWahlvorstand.sql @@ -0,0 +1,22 @@ +CREATE TABLE wahlvorstand +( + id VARCHAR2(36) NOT NULL, + wahlbezirkID VARCHAR2(36) NOT NULL, + + PRIMARY KEY (id) +); + +CREATE TABLE wahlvorstandsmitglied +( + id VARCHAR2(36) NOT NULL, + vorname VARCHAR2(255) NOT NULL, + nachname VARCHAR2(255) NOT NULL, + funktion VARCHAR2(512) NOT NULL, + anwesend NUMBER NOT NULL, + wahlvorstandID VARCHAR2(36) NOT NULL, + anwesenheitUpdatedOn TIMESTAMP, + + FOREIGN KEY (wahlvorstandID) REFERENCES wahlvorstand (id), + + PRIMARY KEY (id) +) \ No newline at end of file diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/Authorities.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/Authorities.java new file mode 100644 index 000000000..148ecb28b --- /dev/null +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/Authorities.java @@ -0,0 +1,18 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Authorities { + + public static final String SERVICE_LOAD_WAHLVORSTAND = "aoueai_BUSINESSACTION_LoadWahlvorstand"; + public static final String SERVICE_SAVE_ANWESENHEIT = "aoueai_BUSINESSACTION_SaveAnwesenheit"; + + public static final String[] ALL_AUTHORITIES_GETWAHLVORSTANDFORWAHLBEZIRK = { + SERVICE_LOAD_WAHLVORSTAND + }; + public static final String[] ALL_AUTHORIRITES_SETANWESENHEIT = { + SERVICE_SAVE_ANWESENHEIT + }; +} diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/configuration/SecurityConfigurationTest.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/configuration/SecurityConfigurationTest.java index e5099fb80..08edbc339 100644 --- a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/configuration/SecurityConfigurationTest.java +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/configuration/SecurityConfigurationTest.java @@ -1,15 +1,29 @@ package de.muenchen.oss.wahllokalsystem.eaiservice.configuration; import static de.muenchen.oss.wahllokalsystem.eaiservice.TestConstants.SPRING_TEST_PROFILE; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.fasterxml.jackson.databind.ObjectMapper; import de.muenchen.oss.wahllokalsystem.eaiservice.MicroServiceApplication; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedAktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand.WahlvorstandService; +import java.time.LocalDateTime; +import java.util.Set; +import lombok.val; +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.http.MediaType; +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 +36,12 @@ class SecurityConfigurationTest { @Autowired MockMvc api; + @Autowired + ObjectMapper objectMapper; + + @MockBean + WahlvorstandService wahlvorstandService; + @Test void accessSecuredResourceRootThenUnauthorized() throws Exception { api.perform(get("/")) @@ -64,4 +84,39 @@ void accessUnsecuredResourceSwaggerUiThenOk() throws Exception { .andExpect(status().isOk()); } + @Nested + class Wahlvorstand { + @Test + @WithAnonymousUser + void accessGetWahlvorstandForWahlbezirkIDUnauthorizedThenUnauthorized() throws Exception { + api.perform(get("/wahlvorstaende?wahlbezirkID=wbzID")).andExpect(status().isUnauthorized()); + } + + @Test + @WithMockUser + void accessGetWahlvorstandForWahlbezirkIDAuthorizedThenOk() throws Exception { + api.perform(get("/wahlvorstaende?wahlbezirkID=wbzID")).andExpect(status().isOk()); + } + + @Test + @WithAnonymousUser + void accessSaveAnwesenheitUnauthorizedThenUnauthorized() throws Exception { + val wahlvorstandAktualisierung = new WahlvorstandsaktualisierungDTO("wbzID", Set.of(new WahlvorstandsmitgliedAktualisierungDTO("id", true)), + LocalDateTime.now()); + + api.perform(put("/wahlvorstaende/anwesenheit").with(csrf()).contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(wahlvorstandAktualisierung))).andExpect(status().isUnauthorized()); + } + + @Test + @WithMockUser + void accessSaveAnwesenheitAuthorizedThenOk() throws Exception { + val wahlvorstandAktualisierung = new WahlvorstandsaktualisierungDTO("wbzID", Set.of(new WahlvorstandsmitgliedAktualisierungDTO("id", true)), + LocalDateTime.now()); + + api.perform(put("/wahlvorstaende/anwesenheit").with(csrf()).contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(wahlvorstandAktualisierung))).andExpect(status().isOk()); + } + } + } diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/GlobalExceptionHandlerTest.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/GlobalExceptionHandlerTest.java new file mode 100644 index 000000000..6933e67f2 --- /dev/null +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/exception/GlobalExceptionHandlerTest.java @@ -0,0 +1,34 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.exception; + +import de.muenchen.oss.wahllokalsystem.wls.common.exception.rest.model.DTOMapper; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ServiceIDFormatter; +import java.util.UUID; +import lombok.val; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.ResponseEntity; + +@ExtendWith(MockitoExtension.class) +class GlobalExceptionHandlerTest { + + @Mock + DTOMapper dtoMapper; + + @Mock + ServiceIDFormatter serviceIDFormatter; + + @InjectMocks + GlobalExceptionHandler unitUnderTest; + + @Test + void handleNotFoundException() { + val result = unitUnderTest.handleNotFoundException(new NotFoundException(UUID.randomUUID(), Object.class)); + + Assertions.assertThat(result).isEqualTo(ResponseEntity.notFound().build()); + } + +} diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandControllerIntegrationTest.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandControllerIntegrationTest.java new file mode 100644 index 000000000..bd96fb513 --- /dev/null +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandControllerIntegrationTest.java @@ -0,0 +1,191 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand; + +import static de.muenchen.oss.wahllokalsystem.eaiservice.TestConstants.SPRING_TEST_PROFILE; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import de.muenchen.oss.wahllokalsystem.eaiservice.Authorities; +import de.muenchen.oss.wahllokalsystem.eaiservice.MicroServiceApplication; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstand; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.WahlvorstandRepository; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstandsmitglied; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.WahlvorstandsmitgliedsFunktion; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.common.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedAktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand.WahlvorstandMapper; +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.exception.util.ExceptionFactory; +import jakarta.persistence.EntityManager; +import java.time.LocalDateTime; +import java.util.Set; +import java.util.UUID; +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.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.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +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) +@AutoConfigureMockMvc +@ActiveProfiles(profiles = { SPRING_TEST_PROFILE }) +public class WahlvorstandControllerIntegrationTest { + + @Value("${service.info.oid}") + String serviceInfoOid; + + @Autowired + MockMvc api; + + @Autowired + ObjectMapper objectMapper; + + @Autowired + WahlvorstandRepository wahlvorstandRepository; + + @Autowired + WahlvorstandMapper wahlvorstandMapper; + + @Autowired + ExceptionFactory exceptionFactory; + + @Autowired + EntityManager entityManager; + + @AfterEach + void tearDown() { + wahlvorstandRepository.deleteAll(); + } + + @Nested + class LoadWahlvorstand { + + @Test + @WithMockUser(authorities = Authorities.SERVICE_LOAD_WAHLVORSTAND) + void noDataFound() throws Exception { + val request = MockMvcRequestBuilders.get("/wahlvorstaende?wahlbezirkID=" + UUID.randomUUID()); + + val response = api.perform(request).andExpect(status().isNotFound()).andReturn(); + + Assertions.assertThat(response.getResponse().getContentAsString()).isEmpty(); + } + + @Test + @WithMockUser(authorities = Authorities.SERVICE_LOAD_WAHLVORSTAND) + @Transactional + void dataFound() throws Exception { + val wahlbezirkID1 = UUID.randomUUID(); + val wahlvorstand1 = new Wahlvorstand(wahlbezirkID1, + Set.of(new Wahlvorstandsmitglied("vorname11", "nachname11", WahlvorstandsmitgliedsFunktion.B, true, LocalDateTime.now()), + new Wahlvorstandsmitglied("vorname12", "nachname12", WahlvorstandsmitgliedsFunktion.SWB, false, LocalDateTime.now()))); + val wahlvorstandToLoad = wahlvorstandRepository.save(wahlvorstand1); + + val wahlbezirkID2 = UUID.randomUUID(); + val wahlvorstand2 = new Wahlvorstand(wahlbezirkID2, + Set.of(new Wahlvorstandsmitglied("vorname21", "nachname21", WahlvorstandsmitgliedsFunktion.B, true, LocalDateTime.now()), + new Wahlvorstandsmitglied("vorname22", "nachname22", WahlvorstandsmitgliedsFunktion.SWB, false, LocalDateTime.now()))); + wahlvorstandRepository.save(wahlvorstand2); + + val request = MockMvcRequestBuilders.get("/wahlvorstaende?wahlbezirkID=" + wahlvorstandToLoad.getWahlbezirkID()); + + val response = api.perform(request).andExpect(status().isOk()).andReturn(); + val responseBodyAsDTO = objectMapper.readValue(response.getResponse().getContentAsString(), WahlvorstandDTO.class); + + val expectedResponseDTO = wahlvorstandMapper.toDTO(wahlvorstandToLoad); + + Assertions.assertThat(responseBodyAsDTO).isEqualTo(expectedResponseDTO); + } + + @Test + @WithMockUser(authorities = Authorities.SERVICE_LOAD_WAHLVORSTAND) + void wlsExceptionOnInvalidWahlbezirkIDFormat() throws Exception { + val request = MockMvcRequestBuilders.get("/wahlvorstaende?wahlbezirkID=wrongFormat"); + + val response = api.perform(request).andExpect(status().isBadRequest()).andReturn(); + val wlsExceptionDTO = objectMapper.readValue(response.getResponse().getContentAsString(), WlsExceptionDTO.class); + + val expectedWlsException = new WlsExceptionDTO(WlsExceptionCategory.F, ExceptionConstants.ID_NICHT_KONVERTIERBAR.code(), serviceInfoOid, + ExceptionConstants.ID_NICHT_KONVERTIERBAR.message()); + + Assertions.assertThat(wlsExceptionDTO).isEqualTo(expectedWlsException); + } + } + + @Nested + class SaveAnwesenheit { + + @Test + @WithMockUser(authorities = Authorities.SERVICE_SAVE_ANWESENHEIT) + @Transactional + void personsAreUpdated() throws Exception { + val wahlbezirkID = UUID.randomUUID(); + val oldUpdatedDate = LocalDateTime.now().minusDays(1); + val mitglied1 = new Wahlvorstandsmitglied("vorname11", "nachname11", WahlvorstandsmitgliedsFunktion.B, true, oldUpdatedDate); + val mitglied2 = new Wahlvorstandsmitglied("vorname12", "nachname12", WahlvorstandsmitgliedsFunktion.SWB, false, oldUpdatedDate); + val mitglied3 = new Wahlvorstandsmitglied("vorname13", "nachname13", WahlvorstandsmitgliedsFunktion.SWB, false, oldUpdatedDate); + val wahlvorstand1 = new Wahlvorstand(wahlbezirkID, + Set.of(mitglied1, mitglied2, mitglied3)); + val wahlvorstandToUpdate = wahlvorstandRepository.save(wahlvorstand1); + + val updateDateTime = LocalDateTime.now(); + val mitglieder = Set.of(new WahlvorstandsmitgliedAktualisierungDTO(mitglied1.getId().toString(), false), + new WahlvorstandsmitgliedAktualisierungDTO(mitglied2.getId().toString(), true)); + val aktualisierung = new WahlvorstandsaktualisierungDTO(wahlbezirkID.toString(), mitglieder, updateDateTime); + val request = MockMvcRequestBuilders.put("/wahlvorstaende/anwesenheit").with(csrf()).contentType(MediaType.APPLICATION_JSON).content( + objectMapper.writeValueAsString(aktualisierung)); + + api.perform(request).andExpect(status().isOk()); + + val updatedEntity = wahlvorstandRepository.findById(wahlvorstandToUpdate.getId()); + val expectedEntityMitglied1 = new Wahlvorstandsmitglied("vorname11", "nachname11", WahlvorstandsmitgliedsFunktion.B, false, updateDateTime); + expectedEntityMitglied1.setId(mitglied1.getId()); + val expectedEntityMitglied2 = new Wahlvorstandsmitglied("vorname12", "nachname12", WahlvorstandsmitgliedsFunktion.SWB, true, updateDateTime); + expectedEntityMitglied2.setId(mitglied2.getId()); + val expectedEntityMitglied3 = new Wahlvorstandsmitglied("vorname13", "nachname13", WahlvorstandsmitgliedsFunktion.SWB, false, oldUpdatedDate); + expectedEntityMitglied3.setId(mitglied3.getId()); + val expectedUpdatedEntity = new Wahlvorstand(wahlbezirkID, Set.of(expectedEntityMitglied1, expectedEntityMitglied2, expectedEntityMitglied3)); + expectedUpdatedEntity.setId(wahlvorstandToUpdate.getId()); + + Assertions.assertThat(updatedEntity.get()).usingRecursiveComparison().isEqualTo(expectedUpdatedEntity); + } + + @Test + @WithMockUser(authorities = Authorities.SERVICE_SAVE_ANWESENHEIT) + void HttpStatusNotFoundWhenWahlvorstandDoesNotExists() throws Exception { + val updateDateTime = LocalDateTime.now(); + val mitglieder = Set.of(new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), false), + new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), true)); + val aktualisierung = new WahlvorstandsaktualisierungDTO(UUID.randomUUID().toString(), mitglieder, updateDateTime); + val request = MockMvcRequestBuilders.put("/wahlvorstaende/anwesenheit").with(csrf()).contentType(MediaType.APPLICATION_JSON).content( + objectMapper.writeValueAsString(aktualisierung)); + + api.perform(request).andExpect(status().isNotFound()); + } + + @Test + @WithMockUser(authorities = Authorities.SERVICE_SAVE_ANWESENHEIT) + void HttpStatusBadRequestWhenRequestIsInvalid() throws Exception { + val mitglieder = Set.of(new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), false), + new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), true)); + val aktualisierung = new WahlvorstandsaktualisierungDTO(UUID.randomUUID().toString(), mitglieder, null); + val request = MockMvcRequestBuilders.put("/wahlvorstaende/anwesenheit").with(csrf()).contentType(MediaType.APPLICATION_JSON).content( + objectMapper.writeValueAsString(aktualisierung)); + + api.perform(request).andExpect(status().isBadRequest()); + } + } + +} diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandControllerTest.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandControllerTest.java new file mode 100644 index 000000000..ae18b74a4 --- /dev/null +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/rest/wahlvorstand/WahlvorstandControllerTest.java @@ -0,0 +1,51 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand.WahlvorstandService; +import java.time.LocalDateTime; +import java.util.Collections; +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 WahlvorstandControllerTest { + + @Mock + WahlvorstandService wahlvorstandService; + + @InjectMocks + WahlvorstandController unitUnderTest; + + @Nested + class LoadWahlvorstand { + + @Test + void gotDataFromService() { + val wahlbezirkID = "wahlbezirkID"; + val wahlvorstandFromService = new WahlvorstandDTO("wahlbezirkID", Collections.emptySet()); + + Mockito.when(wahlvorstandService.getWahlvorstandForWahlbezirk(wahlbezirkID)).thenReturn(wahlvorstandFromService); + + Assertions.assertThat(unitUnderTest.loadWahlvorstand(wahlbezirkID)).isSameAs(wahlvorstandFromService); + } + + } + + @Test + void saveAnwesenheit() { + val updateData = new WahlvorstandsaktualisierungDTO("id", Collections.emptySet(), LocalDateTime.now()); + + unitUnderTest.saveAnwesenheit(updateData); + + Mockito.verify(wahlvorstandService).setAnwesenheit(updateData); + } + +} diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandMapperTest.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandMapperTest.java new file mode 100644 index 000000000..9c2cef973 --- /dev/null +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandMapperTest.java @@ -0,0 +1,43 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstand; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstandsmitglied; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.WahlvorstandsmitgliedsFunktion; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedsFunktionDTO; +import java.time.LocalDateTime; +import java.util.Set; +import java.util.UUID; +import lombok.val; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +class WahlvorstandMapperTest { + + private final WahlvorstandMapper unitUnderTest = Mappers.getMapper(WahlvorstandMapper.class); + + @Test + void toDTO() { + val wahlbezirkID = UUID.randomUUID(); + val mitglied1 = new Wahlvorstandsmitglied("vorname1", "nachname1", WahlvorstandsmitgliedsFunktion.SWB, true, LocalDateTime.now()); + mitglied1.setId(UUID.randomUUID()); + val mitglied2 = new Wahlvorstandsmitglied("vorname2", "nachname2", WahlvorstandsmitgliedsFunktion.B, false, LocalDateTime.now().minusDays(1)); + mitglied2.setId(UUID.randomUUID()); + val mitglieder = Set.of(mitglied1, mitglied2); + val entityToMap = new Wahlvorstand(wahlbezirkID, mitglieder); + + val result = unitUnderTest.toDTO(entityToMap); + + val expectedMitglieder = Set.of( + new WahlvorstandsmitgliedDTO(mitglied1.getId().toString(), mitglied1.getVorname(), mitglied1.getNachname(), + WahlvorstandsmitgliedsFunktionDTO.SWB, true), + new WahlvorstandsmitgliedDTO(mitglied2.getId().toString(), mitglied2.getVorname(), mitglied2.getNachname(), WahlvorstandsmitgliedsFunktionDTO.B, + false)); + val expectedResult = new WahlvorstandDTO(wahlbezirkID.toString(), expectedMitglieder); + + Assertions.assertThat(result).isEqualTo(expectedResult); + } + +} diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandServiceSecurityTest.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandServiceSecurityTest.java new file mode 100644 index 000000000..6b22a2f2c --- /dev/null +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandServiceSecurityTest.java @@ -0,0 +1,91 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.Authorities; +import de.muenchen.oss.wahllokalsystem.eaiservice.MicroServiceApplication; +import de.muenchen.oss.wahllokalsystem.eaiservice.TestConstants; +import de.muenchen.oss.wahllokalsystem.eaiservice.exception.NotFoundException; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedAktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.wls.common.testing.SecurityUtils; +import java.time.LocalDateTime; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Stream; +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.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.security.access.AccessDeniedException; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(classes = MicroServiceApplication.class) + +@ActiveProfiles({ TestConstants.SPRING_TEST_PROFILE }) +public class WahlvorstandServiceSecurityTest { + + @Autowired + WahlvorstandService wahlvorstandService; + + @Nested + class GetWahlvorstandForWahlbezirk { + + @Test + void accessGranted() { + SecurityUtils.runWith(Authorities.ALL_AUTHORITIES_GETWAHLVORSTANDFORWAHLBEZIRK); + + Assertions.assertThatException().isThrownBy(() -> wahlvorstandService.getWahlvorstandForWahlbezirk(UUID.randomUUID().toString())).isInstanceOf( + NotFoundException.class); + } + + @ParameterizedTest(name = "{index} - {1} missing") + @MethodSource("getMissingAuthoritiesVariations") + void anyMissingAuthorityCausesFail(final ArgumentsAccessor argumentsAccessor) { + SecurityUtils.runWith(argumentsAccessor.get(0, String[].class)); + + Assertions.assertThatThrownBy(() -> wahlvorstandService.getWahlvorstandForWahlbezirk(UUID.randomUUID().toString())) + .isInstanceOf(AccessDeniedException.class); + } + + private static Stream getMissingAuthoritiesVariations() { + return SecurityUtils.buildArgumentsForMissingAuthoritiesVariations(Authorities.ALL_AUTHORITIES_GETWAHLVORSTANDFORWAHLBEZIRK); + } + } + + @Nested + class SetAnwesenheit { + + @Test + void accessGranted() { + SecurityUtils.runWith(Authorities.ALL_AUTHORIRITES_SETANWESENHEIT); + + val aktualisierung = new WahlvorstandsaktualisierungDTO(UUID.randomUUID().toString(), + Set.of(new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), false)), LocalDateTime.now()); + + Assertions.assertThatException().isThrownBy(() -> wahlvorstandService.setAnwesenheit(aktualisierung)).isInstanceOf(NotFoundException.class); + } + + @ParameterizedTest(name = "{index} - {1} missing") + @MethodSource("getMissingAuthoritiesVariations") + void anyMissingAuthorityCausesFail(final ArgumentsAccessor argumentsAccessor) { + SecurityUtils.runWith(argumentsAccessor.get(0, String[].class)); + + val aktualisierung = new WahlvorstandsaktualisierungDTO(UUID.randomUUID().toString(), + Set.of(new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), false)), LocalDateTime.now()); + + Assertions.assertThatThrownBy(() -> wahlvorstandService.setAnwesenheit(aktualisierung)) + .isInstanceOf(AccessDeniedException.class); + } + + private static Stream getMissingAuthoritiesVariations() { + return SecurityUtils.buildArgumentsForMissingAuthoritiesVariations(Authorities.ALL_AUTHORIRITES_SETANWESENHEIT); + } + + } + +} diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandServiceTest.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandServiceTest.java new file mode 100644 index 000000000..6587d788c --- /dev/null +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandServiceTest.java @@ -0,0 +1,174 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstand; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.WahlvorstandRepository; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.Wahlvorstandsmitglied; +import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlvorstand.WahlvorstandsmitgliedsFunktion; +import de.muenchen.oss.wahllokalsystem.eaiservice.exception.NotFoundException; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.common.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedAktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; +import java.time.LocalDateTime; +import java.util.Collections; +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.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class WahlvorstandServiceTest { + + @Mock + WahlvorstandRepository wahlvorstandRepository; + + @Mock + ExceptionFactory exceptionFactory; + + @Mock + WahlvorstandMapper wahlvorstandMapper; + + @Mock + WahlvorstandValidator wahlvorstandValidator; + + @InjectMocks + WahlvorstandService unitUnderTest; + + @Nested + class GetWahlvorstandForWahlbezirk { + + @Test + void foundData() { + val wahlbezirkID = UUID.randomUUID(); + + val mockedEntity = new Wahlvorstand(); + val mockedMappedEntity = new WahlvorstandDTO("wahlbezirkID", Collections.emptySet()); + + Mockito.when(wahlvorstandRepository.findFirstByWahlbezirkID(wahlbezirkID)).thenReturn(Optional.of(mockedEntity)); + Mockito.when(wahlvorstandMapper.toDTO(mockedEntity)).thenReturn(mockedMappedEntity); + + val result = unitUnderTest.getWahlvorstandForWahlbezirk(wahlbezirkID.toString()); + + Assertions.assertThat(result).isSameAs(mockedMappedEntity); + } + + @Test + void foundNoData() { + val wahlbezirkID = UUID.randomUUID(); + + Mockito.when(wahlvorstandRepository.findFirstByWahlbezirkID(wahlbezirkID)).thenReturn(Optional.empty()); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.getWahlvorstandForWahlbezirk(wahlbezirkID.toString())) + .usingRecursiveComparison().isEqualTo(new NotFoundException(wahlbezirkID, Wahlvorstand.class)); + } + + @Test + void exceptionForMalformedWahlbezirkID() { + val wahlbezirkID = "noAUUID"; + + val mockedException = FachlicheWlsException.withCode("").buildWithMessage(""); + + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.ID_NICHT_KONVERTIERBAR)).thenReturn(mockedException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.getWahlvorstandForWahlbezirk(wahlbezirkID)).isSameAs(mockedException); + } + + @Test + void exceptionWhenWahlbezirkIDIsNotValid() { + val wahlbezirkID = UUID.randomUUID(); + + val mockedValidationException = new RuntimeException("validation failed"); + + Mockito.doThrow(mockedValidationException).when(wahlvorstandValidator).validateWahlbezirkIDOrThrow(wahlbezirkID.toString()); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.getWahlvorstandForWahlbezirk(wahlbezirkID.toString())) + .isSameAs(mockedValidationException); + } + } + + @Nested + class SetAnwesenheit { + + @Test + void existingDataIsUpdated() { + val wahlbezirkID = UUID.randomUUID(); + val mitglied1 = new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), true); + val mitglied2 = new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), false); + val mitgliederAktualisierung = Set.of(mitglied1, mitglied2); + val aktualisierung = new WahlvorstandsaktualisierungDTO(wahlbezirkID.toString(), mitgliederAktualisierung, LocalDateTime.now()); + + val mockedEntityLastSavedDateTime = LocalDateTime.now().minusDays(1); + val mockedEntityMitglied1 = new Wahlvorstandsmitglied("", "", WahlvorstandsmitgliedsFunktion.B, false, mockedEntityLastSavedDateTime); + mockedEntityMitglied1.setId(UUID.fromString(mitglied1.identifikator())); + // no mitglied2 is intended because request should match only a subset of existing data + val mockedEntityMitglied3 = new Wahlvorstandsmitglied("", "", WahlvorstandsmitgliedsFunktion.SWB, true, mockedEntityLastSavedDateTime); + mockedEntityMitglied3.setId(UUID.randomUUID()); + val mockedEntity = new Wahlvorstand(wahlbezirkID, Set.of(mockedEntityMitglied1, mockedEntityMitglied3)); + + Mockito.when(wahlvorstandRepository.findFirstByWahlbezirkID(wahlbezirkID)).thenReturn(Optional.of(mockedEntity)); + + unitUnderTest.setAnwesenheit(aktualisierung); + + val saveArgumentCaptor = ArgumentCaptor.forClass(Wahlvorstand.class); + Mockito.verify(wahlvorstandRepository).save(saveArgumentCaptor.capture()); + + val capturedSavedArgument = saveArgumentCaptor.getValue(); + val expectedMitglied1 = new Wahlvorstandsmitglied("", "", WahlvorstandsmitgliedsFunktion.B, true, aktualisierung.anwesenheitBeginn()); + expectedMitglied1.setId(UUID.fromString(mitglied1.identifikator())); + val expectedMitglied3 = new Wahlvorstandsmitglied("", "", WahlvorstandsmitgliedsFunktion.SWB, true, mockedEntityLastSavedDateTime); + expectedMitglied3.setId(mockedEntityMitglied3.getId()); + val expectedSavedArgument = new Wahlvorstand(wahlbezirkID, Set.of(expectedMitglied1, expectedMitglied3)); + Assertions.assertThat(capturedSavedArgument).isEqualTo(expectedSavedArgument); + } + + @Test + void exceptionWhenWahlvorstandDoesNotExists() { + val wahlbezirkID = UUID.randomUUID(); + val mitglied1 = new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), true); + val mitglied2 = new WahlvorstandsmitgliedAktualisierungDTO(UUID.randomUUID().toString(), false); + val mitgliederAktualisierung = Set.of(mitglied1, mitglied2); + val aktualisierung = new WahlvorstandsaktualisierungDTO(wahlbezirkID.toString(), mitgliederAktualisierung, LocalDateTime.now()); + + Mockito.when(wahlvorstandRepository.findFirstByWahlbezirkID(wahlbezirkID)).thenReturn(Optional.empty()); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.setAnwesenheit(aktualisierung)).usingRecursiveComparison() + .isEqualTo(new NotFoundException(wahlbezirkID, Wahlvorstand.class)); + + Mockito.verify(wahlvorstandRepository, Mockito.times(0)).save(Mockito.any(Wahlvorstand.class)); + } + + @Test + void validationFailed() { + val aktualisierung = new WahlvorstandsaktualisierungDTO(UUID.randomUUID().toString(), Collections.emptySet(), LocalDateTime.now()); + + val mockedValidationException = new RuntimeException("validation failed"); + + Mockito.doThrow(mockedValidationException).when(wahlvorstandValidator).validateSaveAnwesenheitDataOrThrow(aktualisierung); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.setAnwesenheit(aktualisierung)).isSameAs(mockedValidationException); + } + + @Test + void exceptionBecauseOfWahlbezirkIDOfParameterIsInvalid() { + val mockedWlsException = FachlicheWlsException.withCode("").buildWithMessage(""); + + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.ID_NICHT_KONVERTIERBAR)).thenReturn(mockedWlsException); + + Assertions.assertThatException().isThrownBy( + () -> unitUnderTest.setAnwesenheit(new WahlvorstandsaktualisierungDTO("malformedID", Collections.emptySet(), LocalDateTime.now()))) + .isSameAs(mockedWlsException); + } + } + +} diff --git a/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandValidatorTest.java b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandValidatorTest.java new file mode 100644 index 000000000..ba43dba84 --- /dev/null +++ b/wls-eai-service/src/test/java/de/muenchen/oss/wahllokalsystem/eaiservice/service/wahlvorstand/WahlvorstandValidatorTest.java @@ -0,0 +1,185 @@ +package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlvorstand; + +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsaktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.dto.WahlvorstandsmitgliedAktualisierungDTO; +import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlvorstand.exception.ExceptionConstants; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.FachlicheWlsException; +import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ExceptionFactory; +import java.time.LocalDateTime; +import java.util.Collections; +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 WahlvorstandValidatorTest { + + @Mock + ExceptionFactory exceptionFactory; + + @InjectMocks + WahlvorstandValidator unitUnderTest; + + @Nested + class ValidateWahlbezirkIDOrThrow { + + @Test + void noExceptionWhenIdIsValid() { + Assertions.assertThatNoException().isThrownBy(() -> unitUnderTest.validateWahlbezirkIDOrThrow(UUID.randomUUID().toString())); + } + + @Test + void exceptionWhenIDIsNUll() { + val mockedFachlicheWlsException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG)) + .thenReturn(mockedFachlicheWlsException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateWahlbezirkIDOrThrow(null)).isSameAs(mockedFachlicheWlsException); + } + + @Test + void exceptionWhenIDIsEmptyString() { + val mockedFachlicheWlsException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG)) + .thenReturn(mockedFachlicheWlsException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateWahlbezirkIDOrThrow("")).isSameAs(mockedFachlicheWlsException); + } + + @Test + void exceptionWhenIDIsBlankString() { + val mockedFachlicheWlsException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.LOADWAHLVORSTAND_SUCHKRITERIEN_UNVOLLSTAENDIG)) + .thenReturn(mockedFachlicheWlsException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateWahlbezirkIDOrThrow(" ")).isSameAs(mockedFachlicheWlsException); + } + } + + @Nested + class ValidateSaveAnwesenheitDataOrThrow { + + @Test + void noExceptionWhenAktualisierungIsValid() { + val validDTO = initValidAktualisierung().build(); + + Assertions.assertThatNoException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(validDTO)); + } + + @Test + void exceptionWhenAktualisierungIsNull() { + val mockedValidationException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException( + de.muenchen.oss.wahllokalsystem.eaiservice.rest.common.exception.ExceptionConstants.DATENALLGEMEIN_PARAMETER_FEHLEN)) + .thenReturn(mockedValidationException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(null)).isSameAs(mockedValidationException); + } + + @Test + void exceptionWhenWahlbezirkIdIsNull() { + val invalidDTO = initValidAktualisierung().wahlbezirkID(null).build(); + + val mockedValidationException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_BEZIRKID_FEHLT)) + .thenReturn(mockedValidationException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(invalidDTO)).isSameAs(mockedValidationException); + } + + @Test + void exceptionWhenWahlbezirkIdIsEmpty() { + val invalidDTO = initValidAktualisierung().wahlbezirkID("").build(); + + val mockedValidationException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_BEZIRKID_FEHLT)) + .thenReturn(mockedValidationException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(invalidDTO)).isSameAs(mockedValidationException); + } + + @Test + void exceptionWhenWahlbezirkIdIsBlank() { + val invalidDTO = initValidAktualisierung().wahlbezirkID(" ").build(); + + val mockedValidationException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_BEZIRKID_FEHLT)) + .thenReturn(mockedValidationException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(invalidDTO)).isSameAs(mockedValidationException); + } + + @Test + void exceptionWhenAnwesenheitBeginnIsNull() { + val invalidDTO = initValidAktualisierung().anwesenheitBeginn(null).build(); + + val mockedValidationException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_ANWESENHEITBEGINN_FEHLT)) + .thenReturn(mockedValidationException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(invalidDTO)).isSameAs(mockedValidationException); + + } + + @Nested + class ExceptionWhenMitgliederIdIsInvalid { + + @Test + void isNull() { + val invalidDTO = initValidAktualisierung().mitglieder( + Set.of(initValidMitgliedAktualisierung().build(), initValidMitgliedAktualisierung().identifikator(null).build())).build(); + + val mockedValidationException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT)) + .thenReturn(mockedValidationException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(invalidDTO)) + .isSameAs(mockedValidationException); + } + + @Test + void isEmptyString() { + val invalidDTO = initValidAktualisierung().mitglieder( + Set.of(initValidMitgliedAktualisierung().build(), initValidMitgliedAktualisierung().identifikator("").build())).build(); + + val mockedValidationException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT)) + .thenReturn(mockedValidationException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(invalidDTO)) + .isSameAs(mockedValidationException); + } + + @Test + void isBankString() { + val invalidDTO = initValidAktualisierung().mitglieder( + Set.of(initValidMitgliedAktualisierung().build(), initValidMitgliedAktualisierung().identifikator(" ").build())).build(); + + val mockedValidationException = FachlicheWlsException.withCode("").buildWithMessage(""); + Mockito.when(exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEANWESENHEIT_IDENTIFIKATOR_FEHLT)) + .thenReturn(mockedValidationException); + + Assertions.assertThatException().isThrownBy(() -> unitUnderTest.validateSaveAnwesenheitDataOrThrow(invalidDTO)) + .isSameAs(mockedValidationException); + } + } + + private WahlvorstandsaktualisierungDTO.WahlvorstandsaktualisierungDTOBuilder initValidAktualisierung() { + return WahlvorstandsaktualisierungDTO.builder().anwesenheitBeginn(LocalDateTime.now()).wahlbezirkID("wahlbezirkID") + .mitglieder(Collections.emptySet()); + } + + private WahlvorstandsmitgliedAktualisierungDTO.WahlvorstandsmitgliedAktualisierungDTOBuilder initValidMitgliedAktualisierung() { + return WahlvorstandsmitgliedAktualisierungDTO.builder().identifikator("mitgliedId"); + } + } + +} diff --git a/wls-eai-service/src/test/resources/httpRequests/http-client.env.json b/wls-eai-service/src/test/resources/httpRequests/http-client.env.json new file mode 100644 index 000000000..9f20d0ca1 --- /dev/null +++ b/wls-eai-service/src/test/resources/httpRequests/http-client.env.json @@ -0,0 +1,10 @@ +{ + "docker": { + "WLS_EAI_SERVICE_URL": "http://localhost:8300", + "SSO_URL": "http://kubernetes.docker.internal:8100" + }, + "nonDocker": { + "WLS_EAI_SERVICE_URL": "http://localhost:39146", + "SSO_URL": "http://kubernetes.docker.internal:8100" + } +} \ No newline at end of file diff --git a/wls-eai-service/src/test/resources/httpRequests/wahlvorstand.http b/wls-eai-service/src/test/resources/httpRequests/wahlvorstand.http new file mode 100644 index 000000000..bf8e60612 --- /dev/null +++ b/wls-eai-service/src/test/resources/httpRequests/wahlvorstand.http @@ -0,0 +1,146 @@ +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 Wahlvorstand wbz1 +GET {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende?wahlbezirkID=00000000-0000-0000-0000-000000000001 +Authorization: {{ token_type }} {{ auth_token }} + +### GET Wahlvorstand wbz2 +GET {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende?wahlbezirkID=00000000-0000-0000-0000-000000000002 +Authorization: {{ token_type }} {{ auth_token }} + +### GET Wahlvorstand wbz3 +GET {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende?wahlbezirkID=00000000-0000-0000-0000-000000000003 +Authorization: {{ token_type }} {{ auth_token }} + +### GET Wahlvorstand wbz4 +GET {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende?wahlbezirkID=00000000-0000-0000-0000-000000000004 +Authorization: {{ token_type }} {{ auth_token }} + +### GET Wahlvorstand not found +GET {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende?wahlbezirkID=00000000-9999-0000-0000-000000000000 +Authorization: {{ token_type }} {{ auth_token }} + +### PUT Update Wahlvorstand wbz4 +PUT {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende/anwesenheit +Authorization: {{ token_type }} {{ auth_token }} +Content-Type: application/json + +{ + "wahlbezirkID": "00000000-0000-0000-0000-000000000004", + "anwesenheitBeginn": "2024-06-14T19:01:12.456", + "mitglieder": [ + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000001" + }, + { + "anwesend": false, + "identifikator": "00000000-0000-0000-0004-000000000002" + }, + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000003" + }, + { + "anwesend": false, + "identifikator": "00000000-0000-0000-0004-000000000004" + }, + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000005" + } + ] +} + +### PUT Update - bezirkID fehlt +PUT {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende/anwesenheit +Authorization: {{ token_type }} {{ auth_token }} +Content-Type: application/json + +{ + "anwesenheitBeginn": "2024-06-14T19:01:12.456", + "mitglieder": [ + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000001" + }, + { + "anwesend": false, + "identifikator": "00000000-0000-0000-0004-000000000002" + }, + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000003" + }, + { + "anwesend": false, + "identifikator": "00000000-0000-0000-0004-000000000004" + }, + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000005" + } + ] +} + +### PUT Update - anwesenheitBeginn fehlt +PUT {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende/anwesenheit +Authorization: {{ token_type }} {{ auth_token }} +Content-Type: application/json + +{ + "wahlbezirkID": "00000000-0000-0000-0000-000000000004", + "mitglieder": [ + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000001" + }, + { + "anwesend": false, + "identifikator": "00000000-0000-0000-0004-000000000002" + }, + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000003" + }, + { + "anwesend": false, + "identifikator": "00000000-0000-0000-0004-000000000004" + }, + { + "anwesend": true, + "identifikator": "00000000-0000-0000-0004-000000000005" + } + ] +} + +### PUT Update - Identifikator fehlt +PUT {{ WLS_EAI_SERVICE_URL }}/wahlvorstaende/anwesenheit +Authorization: {{ token_type }} {{ auth_token }} +Content-Type: application/json + +{ + "wahlbezirkID": "00000000-0000-0000-0000-000000000004", + "anwesenheitBeginn": "2024-06-14T19:01:12.456", + "mitglieder": [ + { + "anwesend": true + } + ] +} \ No newline at end of file