Added ability to add election results to DB
This commit is contained in:
+88
@@ -0,0 +1,88 @@
|
|||||||
|
package de.twomartens.wahlrecht.controller.v1;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.mapper.v1.ElectionResultMapper;
|
||||||
|
import de.twomartens.wahlrecht.model.dto.ErrorMessage;
|
||||||
|
import de.twomartens.wahlrecht.model.dto.v1.ElectionResult;
|
||||||
|
import de.twomartens.wahlrecht.service.ElectionResultService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
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.RestController;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping(value = "/wahlrecht/v1")
|
||||||
|
@Tag(name = "ElectionResults", description = "all requests relating to election results")
|
||||||
|
public class ElectionResultController {
|
||||||
|
|
||||||
|
private final ElectionResultMapper mapper = Mappers.getMapper(ElectionResultMapper.class);
|
||||||
|
private final ElectionResultService service;
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Returns election result for given election name",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(responseCode = "200",
|
||||||
|
description = "Returns stored election result for given election name",
|
||||||
|
content = {@Content(
|
||||||
|
mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = ElectionResult.class))}
|
||||||
|
),
|
||||||
|
@ApiResponse(responseCode = "404",
|
||||||
|
description = "No election result found",
|
||||||
|
content = {
|
||||||
|
@Content(
|
||||||
|
mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = ErrorMessage.class)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@GetMapping(value = "/electionResult/by-election-name/{electionName}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ResponseEntity<ElectionResult> getElectionByName(
|
||||||
|
@PathVariable @Parameter(description = "the election name", example = "Bezirkswahl 2019") String electionName) {
|
||||||
|
ElectionResult result = mapper.mapToExternal(service.getElectionResult(electionName));
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.body(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Stores a new election",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(responseCode = "201",
|
||||||
|
description = "Election was created"),
|
||||||
|
@ApiResponse(responseCode = "200",
|
||||||
|
description = "Election was modified"),
|
||||||
|
@ApiResponse(responseCode = "401",
|
||||||
|
description = "Unauthorized",
|
||||||
|
content = {@Content(
|
||||||
|
mediaType = "plain/text")}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@PutMapping("/electionResult")
|
||||||
|
@SecurityRequirement(name = "basicAuth")
|
||||||
|
public ResponseEntity<?> putElection(@RequestBody ElectionResult electionResult) {
|
||||||
|
boolean createdNew = service.storeResult(mapper.mapToDB(electionResult));
|
||||||
|
return createdNew
|
||||||
|
? new ResponseEntity<>(HttpStatus.CREATED)
|
||||||
|
: new ResponseEntity<>(HttpStatus.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package de.twomartens.wahlrecht.mapper.v1;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.model.internal.ElectionResult;
|
||||||
|
import de.twomartens.wahlrecht.model.internal.VotingResult;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.mapstruct.CollectionMappingStrategy;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.NullValueCheckStrategy;
|
||||||
|
import org.mapstruct.ReportingPolicy;
|
||||||
|
|
||||||
|
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
||||||
|
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||||
|
unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||||
|
public interface ElectionResultMapper {
|
||||||
|
|
||||||
|
de.twomartens.wahlrecht.model.dto.v1.ElectionResult mapToExternal(de.twomartens.wahlrecht.model.db.ElectionResult result);
|
||||||
|
|
||||||
|
Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult> mapToExternal(
|
||||||
|
Collection<de.twomartens.wahlrecht.model.db.VotingResult> results);
|
||||||
|
|
||||||
|
Map<Integer, Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult>> mapToExternal(
|
||||||
|
Map<Integer, Collection<de.twomartens.wahlrecht.model.db.VotingResult>> results);
|
||||||
|
|
||||||
|
@Mapping(target = "id", ignore = true)
|
||||||
|
@Mapping(target = "created", ignore = true)
|
||||||
|
@Mapping(target = "lastModified", ignore = true)
|
||||||
|
de.twomartens.wahlrecht.model.db.ElectionResult mapToDB(de.twomartens.wahlrecht.model.dto.v1.ElectionResult result);
|
||||||
|
|
||||||
|
Collection<de.twomartens.wahlrecht.model.db.VotingResult> mapToDB(
|
||||||
|
Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult> results);
|
||||||
|
|
||||||
|
Map<Integer, Collection<de.twomartens.wahlrecht.model.db.VotingResult>> mapToDB(
|
||||||
|
Map<Integer, Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult>> results);
|
||||||
|
|
||||||
|
ElectionResult mapToInternal(de.twomartens.wahlrecht.model.dto.v1.ElectionResult result);
|
||||||
|
|
||||||
|
Collection<VotingResult> mapToInternal(
|
||||||
|
Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult> results);
|
||||||
|
|
||||||
|
Map<Integer, Collection<VotingResult>> mapToInternal(
|
||||||
|
Map<Integer, Collection<de.twomartens.wahlrecht.model.dto.v1.VotingResult>> results);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package de.twomartens.wahlrecht.model.db;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldDefaults;
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.annotation.LastModifiedDate;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
|
@Document
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||||
|
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class ElectionResult {
|
||||||
|
@EqualsAndHashCode.Exclude
|
||||||
|
@Id
|
||||||
|
ObjectId id;
|
||||||
|
@EqualsAndHashCode.Exclude
|
||||||
|
@CreatedDate
|
||||||
|
Instant created;
|
||||||
|
@EqualsAndHashCode.Exclude
|
||||||
|
@LastModifiedDate
|
||||||
|
Instant lastModified;
|
||||||
|
|
||||||
|
String electionName;
|
||||||
|
Collection<VotingResult> overallResults;
|
||||||
|
Map<Integer, Collection<VotingResult>> constituencyResults;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package de.twomartens.wahlrecht.model.db;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.FieldDefaults;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||||
|
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class VotingResult {
|
||||||
|
String electionName;
|
||||||
|
String partyAbbreviation;
|
||||||
|
String nominationName;
|
||||||
|
int votesOnNomination;
|
||||||
|
int votesThroughHealing;
|
||||||
|
Map<Integer, Integer> votesPerPosition;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package de.twomartens.wahlrecht.model.dto.v1;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public record ElectionResult(String electionName, Collection<VotingResult> overallResults,
|
||||||
|
Map<Integer, Collection<VotingResult>> constituencyResults) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package de.twomartens.wahlrecht.model.internal;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public record ElectionResult(String electionName, Collection<VotingResult> overallResults,
|
||||||
|
Map<Integer, Collection<VotingResult>> constituencyResults) {
|
||||||
|
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package de.twomartens.wahlrecht.repository;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.model.db.ElectionResult;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
|
||||||
|
public interface ElectionResultRepository extends MongoRepository<ElectionResult, String> {
|
||||||
|
Optional<ElectionResult> findByElectionName(String name);
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
package de.twomartens.wahlrecht.repository;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.model.db.VotingResult;
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||||
|
|
||||||
|
public interface VotingResultRepository extends MongoRepository<VotingResult, String> {
|
||||||
|
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
package de.twomartens.wahlrecht.service;
|
||||||
|
|
||||||
|
import de.twomartens.wahlrecht.model.db.ElectionResult;
|
||||||
|
import de.twomartens.wahlrecht.repository.ElectionResultRepository;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class ElectionResultService {
|
||||||
|
|
||||||
|
private final ElectionResultRepository repository;
|
||||||
|
|
||||||
|
private Map<String, ElectionResult> electionResults;
|
||||||
|
|
||||||
|
public ElectionResult getElectionResult(String electionName) {
|
||||||
|
if (electionResults == null) {
|
||||||
|
fetchResults();
|
||||||
|
}
|
||||||
|
ElectionResult electionResult = electionResults.get(electionName);
|
||||||
|
if (electionResult == null) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
|
||||||
|
"no election result found for %s".formatted(electionName));
|
||||||
|
}
|
||||||
|
return electionResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean storeResult(ElectionResult result) {
|
||||||
|
if (electionResults == null) {
|
||||||
|
fetchResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = result.getElectionName();
|
||||||
|
ElectionResult existing = electionResults.get(id);
|
||||||
|
boolean needsUpdate = !result.equals(existing);
|
||||||
|
|
||||||
|
if (!needsUpdate) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean createdNew = true;
|
||||||
|
if (existing != null) {
|
||||||
|
existing.setOverallResults(result.getOverallResults());
|
||||||
|
existing.setConstituencyResults(result.getConstituencyResults());
|
||||||
|
result = existing;
|
||||||
|
createdNew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElectionResult stored = repository.save(result);
|
||||||
|
electionResults.put(id, stored);
|
||||||
|
|
||||||
|
return createdNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchResults() {
|
||||||
|
electionResults = repository.findAll().stream()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
ElectionResult::getElectionName,
|
||||||
|
Function.identity()));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user