From b02e40de7e068aad7f3bebd284e1c9d20d6d33bd Mon Sep 17 00:00:00 2001 From: Garrett Arant Date: Sun, 8 Apr 2018 17:15:48 -0400 Subject: [PATCH] Completed --- src/main/java/dtos/OptionCount.java | 22 +++++ src/main/java/dtos/VoteResult.java | 24 +++++ src/main/java/dtos/error/ErrorDetail.java | 68 ++++++++++++++ .../java/dtos/error/RestExceptionHandler.java | 73 +++++++++++++++ src/main/java/dtos/error/ValidationError.java | 23 +++++ .../controller/ComputeResultController.java | 28 ++++++ .../controller/PollController.java | 66 ++++++++++++++ .../controller/VoteController.java | 38 ++++++++ .../domain/Option.java | 34 +++++++ .../domain/Poll.java | 50 +++++++++++ .../domain/Vote.java | 32 +++++++ .../exception/ResourceNotFoundException.java | 19 ++++ .../repositories/OptionRepository.java | 7 ++ .../repositories/PollRepository.java | 7 ++ .../repositories/VoteRepository.java | 14 +++ src/main/resources/import.sql | 89 +++++++++++++++++++ src/main/resources/messages.properties | 2 + 17 files changed, 596 insertions(+) create mode 100644 src/main/java/dtos/OptionCount.java create mode 100644 src/main/java/dtos/VoteResult.java create mode 100644 src/main/java/dtos/error/ErrorDetail.java create mode 100644 src/main/java/dtos/error/RestExceptionHandler.java create mode 100644 src/main/java/dtos/error/ValidationError.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/controller/PollController.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/domain/Vote.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/exception/ResourceNotFoundException.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/repositories/OptionRepository.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/repositories/PollRepository.java create mode 100644 src/main/java/io/zipcoder/tc_spring_poll_application/repositories/VoteRepository.java create mode 100644 src/main/resources/import.sql create mode 100644 src/main/resources/messages.properties diff --git a/src/main/java/dtos/OptionCount.java b/src/main/java/dtos/OptionCount.java new file mode 100644 index 0000000..c0984a9 --- /dev/null +++ b/src/main/java/dtos/OptionCount.java @@ -0,0 +1,22 @@ +package dtos; + +public class OptionCount { + private Long optionId; + private int count; + + public Long getOptionId() { + return optionId; + } + + public void setOptionId(Long optionId) { + this.optionId = optionId; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } +} \ No newline at end of file diff --git a/src/main/java/dtos/VoteResult.java b/src/main/java/dtos/VoteResult.java new file mode 100644 index 0000000..b3d873d --- /dev/null +++ b/src/main/java/dtos/VoteResult.java @@ -0,0 +1,24 @@ +package dtos; + +import java.util.Collection; + +public class VoteResult { + private int totalVotes; + private Collection results; + + public int getTotalVotes() { + return totalVotes; + } + + public void setTotalVotes(int totalVotes) { + this.totalVotes = totalVotes; + } + + public Collection getResults() { + return results; + } + + public void setResults(Collection results) { + this.results = results; + } +} diff --git a/src/main/java/dtos/error/ErrorDetail.java b/src/main/java/dtos/error/ErrorDetail.java new file mode 100644 index 0000000..f17635f --- /dev/null +++ b/src/main/java/dtos/error/ErrorDetail.java @@ -0,0 +1,68 @@ +package dtos.error; + + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ErrorDetail { + + private String title; + private int status; + private String detail; + private long timeStamp; + private String developerMessage; + + private Map> errors = new HashMap<>(); + + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public long getTimeStamp() { + return timeStamp; + } + + public void setTimeStamp(long timeStamp) { + this.timeStamp = timeStamp; + } + + public String getDeveloperMessage() { + return developerMessage; + } + + public void setDeveloperMessage(String developerMessage) { + this.developerMessage = developerMessage; + } + + public Map> getErrors() { + return errors; + } + + public void setErrors(Map> errors) { + this.errors = errors; + } + + +} diff --git a/src/main/java/dtos/error/RestExceptionHandler.java b/src/main/java/dtos/error/RestExceptionHandler.java new file mode 100644 index 0000000..2475aa0 --- /dev/null +++ b/src/main/java/dtos/error/RestExceptionHandler.java @@ -0,0 +1,73 @@ +package dtos.error; + +import io.zipcoder.tc_spring_poll_application.exception.ResourceNotFoundException; +import org.springframework.context.MessageSource; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@ControllerAdvice +public class RestExceptionHandler extends ResponseEntityExceptionHandler { + + @Inject + private MessageSource messageSource; + + @ExceptionHandler(ResourceNotFoundException.class) + @ResponseStatus + public ResponseEntity handlerResourceNotFoundException( + ResourceNotFoundException rnfe, HttpServletRequest request) { + ErrorDetail errorDetail = new ErrorDetail(); + errorDetail.setTimeStamp(new Date().getTime()); + errorDetail.setStatus(HttpStatus.NOT_FOUND.value()); + errorDetail.setTitle("Resource Not Found"); + errorDetail.setDetail(rnfe.getMessage()); + errorDetail.setDeveloperMessage(rnfe.getClass().getName()); + + return new ResponseEntity<>(errorDetail, null, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public @ResponseBody + ErrorDetail handleValidationError(MethodArgumentNotValidException manve, HttpServletRequest request) { + ErrorDetail errorDetail = new ErrorDetail(); + errorDetail.setTitle("Validation Failed"); + errorDetail.setStatus(HttpStatus.BAD_REQUEST.value()); + errorDetail.setDetail("Input validation failed"); + errorDetail.setTimeStamp(new Date().getTime()); + errorDetail.setDeveloperMessage(manve.getClass().getName()); + + String requestPath = (String) request.getAttribute("javax.servlet.error.request_uri"); + + if (requestPath == null) { + requestPath = request.getRequestURI(); + } + + List fieldErrors = manve.getBindingResult().getFieldErrors(); + for (FieldError fe : fieldErrors) { + List validationErrorList = errorDetail.getErrors().get(fe.getField()); + if (validationErrorList == null) { + validationErrorList = new ArrayList(); + errorDetail.getErrors().put(fe.getField(), validationErrorList); + } + ValidationError validationError = new ValidationError(); + validationError.setCode(fe.getCode()); + validationError.setMessage(messageSource.getMessage(fe, null)); + validationErrorList.add(validationError); + + } + return errorDetail; + } +} diff --git a/src/main/java/dtos/error/ValidationError.java b/src/main/java/dtos/error/ValidationError.java new file mode 100644 index 0000000..2a64ec9 --- /dev/null +++ b/src/main/java/dtos/error/ValidationError.java @@ -0,0 +1,23 @@ +package dtos.error; + +public class ValidationError { + + private String code; + private String message; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java new file mode 100644 index 0000000..a1090f3 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java @@ -0,0 +1,28 @@ +package io.zipcoder.tc_spring_poll_application.controller; + +import dtos.VoteResult; +import io.zipcoder.tc_spring_poll_application.domain.Vote; +import io.zipcoder.tc_spring_poll_application.repositories.VoteRepository; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.inject.Inject; + +@RestController +public class ComputeResultController { + @Inject + private VoteRepository voteRepository; + + @RequestMapping(value = "/computeresult", method = RequestMethod.GET) + public ResponseEntity computeResult(@RequestParam Long pollId) { + VoteResult voteResult = new VoteResult(); + Iterable allVotes = voteRepository.findVotesByPoll(pollId); + + //TODO: Implement algorithm to count votes + return new ResponseEntity(voteResult, HttpStatus.OK); + } +} \ No newline at end of file diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/controller/PollController.java b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/PollController.java new file mode 100644 index 0000000..9a3121f --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/PollController.java @@ -0,0 +1,66 @@ +package io.zipcoder.tc_spring_poll_application.controller; + +import io.zipcoder.tc_spring_poll_application.domain.Poll; +import io.zipcoder.tc_spring_poll_application.exception.ResourceNotFoundException; +import io.zipcoder.tc_spring_poll_application.repositories.PollRepository; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import javax.inject.Inject; +import javax.validation.Valid; +import java.net.URI; + +@RestController +public class PollController { + + @Inject + private PollRepository pollRepository; + + @RequestMapping(value="/polls", method= RequestMethod.GET) + public ResponseEntity> getAllPolls() { + Iterable allPolls = pollRepository.findAll(); + return new ResponseEntity<>(allPolls, HttpStatus.OK); + } + + @RequestMapping(value="/polls", method=RequestMethod.POST) + public ResponseEntity createPoll(@Valid @RequestBody Poll poll) { + poll = pollRepository.save(poll); + HttpHeaders responseHeaders = new HttpHeaders(); + URI newPollUri = ServletUriComponentsBuilder + .fromCurrentRequest() + .path("/{id}") + .buildAndExpand(poll.getId()) + .toUri(); + responseHeaders.setLocation(newPollUri); + return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED); + } + + @RequestMapping(value="/polls/{pollId}", method=RequestMethod.GET) + public ResponseEntity getPoll(@PathVariable Long pollId) { + Poll p = pollRepository.findOne(pollId); + return new ResponseEntity<> (p, HttpStatus.OK); + } + + @RequestMapping(value="/polls/{pollId}", method=RequestMethod.PUT) + public ResponseEntity updatePoll(@Valid @RequestBody Poll poll, @PathVariable Long pollId) { + // Save the entity + Poll p = pollRepository.save(poll); + return new ResponseEntity<>(HttpStatus.OK); + } + + @RequestMapping(value="/polls/{pollId}", method=RequestMethod.DELETE) + public ResponseEntity deletePoll(@PathVariable Long pollId) { + pollRepository.delete(pollId); + return new ResponseEntity<>(HttpStatus.OK); + } + + void verifyPoll(Long pollId) throws ResourceNotFoundException { + Poll poll = pollRepository.findOne(pollId); + if (poll == null){ + throw new ResourceNotFoundException("Poll with id "+ pollId + " not found"); + } + } +} diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java new file mode 100644 index 0000000..ff72779 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java @@ -0,0 +1,38 @@ +package io.zipcoder.tc_spring_poll_application.controller; + +import io.zipcoder.tc_spring_poll_application.domain.Vote; +import io.zipcoder.tc_spring_poll_application.repositories.VoteRepository; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import javax.inject.Inject; + +@RestController +public class VoteController { + @Inject + private VoteRepository voteRepository; + + @RequestMapping(value = "/polls/{pollId}/votes", method = RequestMethod.POST) + public ResponseEntity createVote(@PathVariable Long pollId, @RequestBody Vote + vote) { + vote = voteRepository.save(vote); + // Set the headers for the newly created resource + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setLocation(ServletUriComponentsBuilder. + fromCurrentRequest().path("/{id}").buildAndExpand(vote.getId()).toUri()); + return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED); + } + + @RequestMapping(value="/polls/votes", method=RequestMethod.GET) + public Iterable getAllVotes() { + return voteRepository.findAll(); + } + + @RequestMapping(value="/polls/{pollId}/votes", method=RequestMethod.GET) + public Iterable getVote(@PathVariable Long pollId) { + return voteRepository.findVotesByPoll(pollId); + } +} diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java new file mode 100644 index 0000000..1e59587 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java @@ -0,0 +1,34 @@ +package io.zipcoder.tc_spring_poll_application.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Option { + + @Id + @GeneratedValue + @Column(name = "OPTION_ID") + private Long id; + + @Column(name = "OPTION_VALUE") + private String option; + + public Long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getOption() { + return option; + } + + public void setOption(String option) { + this.option = option; + } +} diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java new file mode 100644 index 0000000..8f5c4a5 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java @@ -0,0 +1,50 @@ +package io.zipcoder.tc_spring_poll_application.domain; + +import org.hibernate.validator.constraints.NotEmpty; + +import javax.persistence.*; +import javax.validation.constraints.Size; +import java.util.Set; + +@Entity +public class Poll { + + @Id + @GeneratedValue + @Column(name = "POLL_ID") + private Long id; + + @Column(name = "QUESTION") + @NotEmpty + private String question; + + @OneToMany(cascade = CascadeType.ALL) + @JoinColumn(name = "POLL_ID") + @OrderBy + @Size(min=2, max=6) + private Set