Skip to content

Commit

Permalink
Merge pull request #382 from it-at-m/155-implementierung-wahlbeteiligung
Browse files Browse the repository at this point in the history
155 implementierung wahlbeteiligung
  • Loading branch information
dragonfly28 authored Jul 24, 2024
2 parents 8d9f2d4 + fa4941c commit 3025cb1
Show file tree
Hide file tree
Showing 21 changed files with 743 additions and 32 deletions.
12 changes: 12 additions & 0 deletions stack/keycloak/migration/add-authorities-eai-wahlbeteiligung.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
id: add authorities eai wahlbeteiligung
author: dragonfly28
realm: ${SSO_REALM}
changes:
- addRole:
name: aoueai_BUSINESSACTION_SaveWahlbeteiligung
clientRole: true
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allEaiAuthorities
role: aoueai_BUSINESSACTION_SaveWahlbeteiligung
clientId: ${SSO_CLIENT_ID}
3 changes: 2 additions & 1 deletion stack/keycloak/migration/keycloak-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ includes:
- path: add-authorities-eai-wahldaten.yml
- path: add-authorities-basisdaten-handbuch.yml
- path: add-authorities-basisdaten-wahltage.yml
- path: add-authorities-basisdaten-ungueltigewahlscheine.yml
- path: add-authorities-basisdaten-ungueltigewahlscheine.yml
- path: add-authorities-eai-wahlbeteiligung.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlbeteiligung;

import de.muenchen.oss.wahllokalsystem.eaiservice.domain.BaseEntity;
import jakarta.persistence.Entity;
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)
@ToString(onlyExplicitlyIncluded = true, callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class Wahlbeteiligung extends BaseEntity {

@NotNull
@ToString.Include
String wahlID;

@NotNull
@ToString.Include
String wahlbezirkID;

@NotNull
@ToString.Include
long anzahlWaehler;

@NotNull
@ToString.Include
LocalDateTime meldeZeitpunkt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlbeteiligung;

import java.util.UUID;
import org.springframework.data.repository.CrudRepository;

public interface WahlbeteiligungRepository extends CrudRepository<Wahlbeteiligung, UUID> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public class ExceptionConstants {
public static final ExceptionDataWrapper LOADWAHLEN_WAHLTAG_FEHLT = new ExceptionDataWrapper("001", "Es ist kein Wahltag angegeben");
public static final ExceptionDataWrapper LOADWAHLEN_NUMMER_FEHLT = new ExceptionDataWrapper("001_1", "Es ist keine Wahlnummer angegeben");

//saveWahlbeteiligung
public static final ExceptionDataWrapper SAVEWAHLBETEILIGUNG_WAHLBEZIRKID_FEHLT = new ExceptionDataWrapper(CODE_BEZIRKID_FEHLT, MESSAGE_BEZIRKID_FEHLT);
public static final ExceptionDataWrapper SAVEWAHLBETEILIGUNG_WAHLID_FEHLT = new ExceptionDataWrapper(CODE_WAHLID_FEHLT, MESSAGE_WAHLID_FEHLT);
public static final ExceptionDataWrapper SAVEWAHLBETEILIGUNG_MELDEZEITPUNKT_FEHLT = new ExceptionDataWrapper("003", "Der Meldezeitpunkt fehlt");

/**
* @throws IllegalAccessException when constructor is used
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlbeteiligung;

import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlbeteiligung.dto.WahlbeteiligungsMeldungDTO;
import jakarta.validation.Valid;
import de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlbeteiligung.WahlbeteiligungService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -11,11 +12,14 @@

@RestController
@RequestMapping("/wahlbeteiligung")
@RequiredArgsConstructor
public class WahlbeteiligungController {

private final WahlbeteiligungService wahlbeteiligungService;

@PostMapping
@ResponseStatus(HttpStatus.OK)
public void saveWahlbeteiligung(@Valid @RequestBody WahlbeteiligungsMeldungDTO wahlbeteiligung) {
throw new UnsupportedOperationException("Not supported yet.");
public void saveWahlbeteiligung(@RequestBody WahlbeteiligungsMeldungDTO wahlbeteiligung) {
wahlbeteiligungService.saveWahlbeteiligung(wahlbeteiligung);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import lombok.Builder;

@Builder
public record WahlbeteiligungsMeldungDTO(@NotNull String wahlID,
@NotNull String wahlbezirkID,
@Schema(requiredMode = Schema.RequiredMode.REQUIRED) long anzahlWaehler,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlbeteiligung;

import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlbeteiligung.Wahlbeteiligung;
import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlbeteiligung.dto.WahlbeteiligungsMeldungDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper
public interface WahlbeteiligungMapper {

WahlbeteiligungsMeldungDTO toDTO(Wahlbeteiligung entity);

@Mapping(target = "id", ignore = true)
Wahlbeteiligung toEntity(WahlbeteiligungsMeldungDTO dto);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlbeteiligung;

import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlbeteiligung.WahlbeteiligungRepository;
import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlbeteiligung.dto.WahlbeteiligungsMeldungDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@RequiredArgsConstructor
public class WahlbeteiligungService {

private final WahlbeteiligungRepository wahlbeteiligungRepository;

private final WahlbeteiligungMapper wahlbeteiligungMapper;

private final WahlbeteiligungValidator wahlbeteiligungValidator;

@PreAuthorize("hasAuthority('aoueai_BUSINESSACTION_SaveWahlbeteiligung')")
public void saveWahlbeteiligung(@P("wahlbeteiligungToSet") final WahlbeteiligungsMeldungDTO wahlbeteiligungToSet) {
log.debug("#saveWahlbeteiligung");

wahlbeteiligungValidator.validDTOToSetOrThrow(wahlbeteiligungToSet);

wahlbeteiligungRepository.save(wahlbeteiligungMapper.toEntity(wahlbeteiligungToSet));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlbeteiligung;

import de.muenchen.oss.wahllokalsystem.eaiservice.exception.ExceptionConstants;
import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlbeteiligung.dto.WahlbeteiligungsMeldungDTO;
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 WahlbeteiligungValidator {

private final ExceptionFactory exceptionFactory;

public void validDTOToSetOrThrow(WahlbeteiligungsMeldungDTO wahlbeteiligungToSet) {
if (wahlbeteiligungToSet == null) {
throw exceptionFactory.createFachlicheWlsException(
de.muenchen.oss.wahllokalsystem.eaiservice.rest.common.exception.ExceptionConstants.DATENALLGEMEIN_PARAMETER_FEHLEN);
}

if (StringUtils.isBlank(wahlbeteiligungToSet.wahlbezirkID())) {
throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEWAHLBETEILIGUNG_WAHLBEZIRKID_FEHLT);
}

if (StringUtils.isBlank(wahlbeteiligungToSet.wahlID())) {
throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEWAHLBETEILIGUNG_WAHLID_FEHLT);
}

if (wahlbeteiligungToSet.meldeZeitpunkt() == null) {
throw exceptionFactory.createFachlicheWlsException(ExceptionConstants.SAVEWAHLBETEILIGUNG_MELDEZEITPUNKT_FEHLT);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CREATE TABLE wahlbeteiligung
(
id VARCHAR2(36) NOT NULL,
wahlbezirkID VARCHAR2(36) NOT NULL,
wahlID VARCHAR2(36) NOT NULL,
anzahlWaehler BIGINT NOT NULL,
meldeZeitpunkt TIMESTAMP NOT NULL,

PRIMARY KEY (id)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CREATE TABLE wahlbeteiligung
(
id VARCHAR2(36) NOT NULL,
wahlbezirkID VARCHAR2(36) NOT NULL,
wahlID VARCHAR2(36) NOT NULL,
anzahlWaehler NUMBER NOT NULL,
meldeZeitpunkt TIMESTAMP NOT NULL,

PRIMARY KEY (id)
);
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class Authorities {
public static final String SERVICE_LOAD_WAHLEN = "aoueai_BUSINESSACTION_LoadWahlen";
public static final String SERVICE_LOAD_BASISDATEN = "aoueai_BUSINESSACTION_LoadBasisdaten";

public static final String SERVICE_SAVE_WAHLBETEILIGUNG = "aoueai_BUSINESSACTION_SaveWahlbeteiligung";

public static final String[] ALL_AUTHORITIES_GETWAHLVORSTANDFORWAHLBEZIRK = {
SERVICE_LOAD_WAHLVORSTAND
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlbeteiligung;

import static de.muenchen.oss.wahllokalsystem.eaiservice.TestConstants.SPRING_TEST_PROFILE;
import static org.mockito.ArgumentMatchers.any;
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.wahlbeteiligung.Wahlbeteiligung;
import de.muenchen.oss.wahllokalsystem.eaiservice.domain.wahlbeteiligung.WahlbeteiligungRepository;
import de.muenchen.oss.wahllokalsystem.eaiservice.rest.wahlbeteiligung.dto.WahlbeteiligungsMeldungDTO;
import de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlbeteiligung.WahlbeteiligungMapper;
import de.muenchen.oss.wahllokalsystem.eaiservice.service.wahlbeteiligung.WahlbeteiligungValidator;
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 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.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.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 WahlbeteiligungControllerIntegrationTest {

@Value("${service.info.oid}")
String serviceInfoOid;

@Autowired
MockMvc api;

@Autowired
ObjectMapper objectMapper;

@Autowired
WahlbeteiligungRepository wahlbeteiligungRepository;

@Autowired
WahlbeteiligungMapper wahlbeteiligungMapper;

@SpyBean
WahlbeteiligungValidator wahlbeteiligungValidator;

@Autowired
ExceptionFactory exceptionFactory;

@Autowired
EntityManager entityManager;

@AfterEach
void tearDown() {
wahlbeteiligungRepository.deleteAll();
}

@Nested
class SaveWahlbeteiligungsMeldung {

@Test
@WithMockUser(authorities = Authorities.SERVICE_SAVE_WAHLBETEILIGUNG)
@Transactional
void meldungIsSaved() throws Exception {
val wahlID = "wahlID1";
val wahlbezirkID = "00000000-0000-0000-0000-000000000001";
val anzahlWaehler = 150;
val meldeZeitpunkt = LocalDateTime.now();

val requestBody = new WahlbeteiligungsMeldungDTO(wahlID, wahlbezirkID, anzahlWaehler, meldeZeitpunkt);
val request = MockMvcRequestBuilders.post("/wahlbeteiligung").with(csrf()).contentType(MediaType.APPLICATION_JSON).content(
objectMapper.writeValueAsString(requestBody));

val response = api.perform(request).andExpect(status().isOk()).andReturn();

val savedWahlbeteiligung = wahlbeteiligungRepository.findAll().iterator().next();

Assertions.assertThat(response.getResponse().getContentAsString()).isEmpty();

val expectedSavedWahlbeteiligung = new Wahlbeteiligung(requestBody.wahlID(), requestBody.wahlbezirkID(), requestBody.anzahlWaehler(),
requestBody.meldeZeitpunkt());

Assertions.assertThat(savedWahlbeteiligung).usingRecursiveComparison().ignoringFields("id").isEqualTo(expectedSavedWahlbeteiligung);
}

@Test
@WithMockUser(authorities = Authorities.SERVICE_SAVE_WAHLBETEILIGUNG)
@Transactional
void validationExceptionOccurredAndIsMapped() throws Exception {

val wahlbezirkID = "00000000-0000-0000-0000-000000000001";
val anzahlWaehler = 150;
val meldeZeitpunkt = LocalDateTime.now();

val requestBody = new WahlbeteiligungsMeldungDTO(null, wahlbezirkID, anzahlWaehler, meldeZeitpunkt);
val request = MockMvcRequestBuilders.post("/wahlbeteiligung").with(csrf()).contentType(MediaType.APPLICATION_JSON).content(
objectMapper.writeValueAsString(requestBody));

val mockedExceptionMessage = "mocked null pointer exception";
val mockedValidationException = new NullPointerException(mockedExceptionMessage);
Mockito.doThrow(mockedValidationException).when(wahlbeteiligungValidator).validDTOToSetOrThrow(any());

val response = api.perform(request).andExpect(status().isInternalServerError()).andReturn();
val responseBodyDTO = objectMapper.readValue(response.getResponse().getContentAsString(), WlsExceptionDTO.class);

val expectedWlsExceptionDTO = new WlsExceptionDTO(WlsExceptionCategory.T, "999", "EAI-SERVICE", "");

Assertions.assertThat(responseBodyDTO).usingRecursiveComparison().ignoringFields("message").isEqualTo(expectedWlsExceptionDTO);
Assertions.assertThat(responseBodyDTO.message()).contains(mockedExceptionMessage);
}

}

}
Loading

0 comments on commit 3025cb1

Please sign in to comment.