diff --git a/README.md b/README.md index 2c6950e..21a1c87 100644 --- a/README.md +++ b/README.md @@ -358,7 +358,7 @@ public Iterable getVote(@PathVariable Long pollId) { * The final piece remaining for us is the implementation of the ComputeResult resource. * Because we don’t have any domain objects that can directly help generate this resource representation, we implement two Data Transfer Objects or DTOs—OptionCount and VoteResult -* Create a sub package of `java` named `dtos` +* Create a sub package of `java` named `io.zipcoder.tc_spring_poll_application.dto.error.dtos` ## Part 4.1 - Create class `OptionCount` 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..3fc71fe --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java @@ -0,0 +1,30 @@ +package io.zipcoder.tc_spring_poll_application.controller; + +import io.zipcoder.tc_spring_poll_application.dto.VoteResult; +import io.zipcoder.tc_spring_poll_application.domain.Vote; +import io.zipcoder.tc_spring_poll_application.repositories.VoteRepository; +import org.springframework.beans.factory.annotation.Autowired; +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; + +@RestController +public class ComputeResultController { + private VoteRepository voteRepository; + + @Autowired + public ComputeResultController(VoteRepository voteRepository) { + this.voteRepository = voteRepository; + } + + @RequestMapping(value = "/computeresult", method = RequestMethod.GET) + public ResponseEntity computeResult(@RequestParam Long pollId) { + VoteResult voteResult = new VoteResult(); + Iterable allVotes = voteRepository.findVotesByPoll(pollId); + voteResult.mapVotes(allVotes); + return new ResponseEntity(voteResult, HttpStatus.OK); + } +} 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..fbb7a9c --- /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.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +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.validation.Valid; +import java.net.URI; + +@RestController +public class PollController { + @Autowired + PollRepository pollRepository; + + +// public PollController(PollRepository pollRepository) { +// this.pollRepository = pollRepository; +// } + + @RequestMapping(value = "/polls", method = RequestMethod.GET) + public ResponseEntity> getAllPolls(Pageable p) { + Page allPolls = pollRepository.findAll(p); + return new ResponseEntity<>(allPolls, HttpStatus.OK); + } + + @RequestMapping(value = "/polls", method = RequestMethod.POST) + public ResponseEntity createPoll(@Valid @RequestBody Poll poll) { + poll = pollRepository.save(poll); + URI newPollUri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(poll.getId()).toUri(); + HttpHeaders headers = new HttpHeaders(); + headers.setLocation(newPollUri); + return new ResponseEntity<>(headers, 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) { + 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); + } + + public void verifyPoll(Long pollId) { + if (!pollRepository.exists(pollId)) + throw new ResourceNotFoundException(); + + } +} diff --git a/src/main/java/io/zipcoder/tc_spring_poll_application/controller/RestExceptionHandler.java b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/RestExceptionHandler.java new file mode 100644 index 0000000..b236b17 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/RestExceptionHandler.java @@ -0,0 +1,69 @@ +package io.zipcoder.tc_spring_poll_application.controller; + +import io.zipcoder.tc_spring_poll_application.dto.error.ErrorDetail; +import io.zipcoder.tc_spring_poll_application.dto.error.ValidationError; +import io.zipcoder.tc_spring_poll_application.exception.ResourceNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +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 javax.servlet.http.HttpServletRequest; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@ControllerAdvice +public class RestExceptionHandler { + + @Autowired + private MessageSource messageSource; + + @ExceptionHandler(ResourceNotFoundException.class) + public ResponseEntity handleResourceNotFoundException(ResourceNotFoundException rnfe, HttpServletRequest request) { + ErrorDetail ed = new ErrorDetail(rnfe.getClass().getSimpleName(),404,rnfe.getStackTrace().toString(), (new Date()).getTime(), rnfe.getMessage()); + return new ResponseEntity(ed, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleValidationError(MethodArgumentNotValidException manve, HttpServletRequest request) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + manve.printStackTrace(pw); + + ErrorDetail errorDetail = new ErrorDetail( + "Resource Validation Failed", + HttpStatus.BAD_REQUEST.value(), + manve.getMessage(), + (new Date()).getTime(), + sw.toString()); + + List fieldErrors = manve.getBindingResult().getFieldErrors(); + for(FieldError fe : fieldErrors) { + List validationErrorList; + try{ + validationErrorList = errorDetail.getErrors().get(fe.getField()); + } catch (NullPointerException npe) { + 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 new ResponseEntity<>(fieldErrors, HttpStatus.BAD_REQUEST); + } + + +} 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..9f93872 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java @@ -0,0 +1,41 @@ +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.beans.factory.annotation.Autowired; +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; + +@RestController +public class VoteController { + private VoteRepository voteRepository; + + @Autowired + public VoteController(VoteRepository voteRepository) { + this.voteRepository = voteRepository; + } + + @RequestMapping(value = "/polls/{pollId}/votes", method = RequestMethod.POST) + public ResponseEntity createVote(@PathVariable Long pollId, @RequestBody Vote vote) { + vote = voteRepository.save(vote); + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setLocation(ServletUriComponentsBuilder.fromCurrentRequest().path("/{pollId}").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); + } + //valid value required to post vote, but it gets vote data from id not value. and id changes depending on springs mood between reloads + + +} 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..e7830b6 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java @@ -0,0 +1,35 @@ +package io.zipcoder.tc_spring_poll_application.domain; + +import javax.persistence.*; + +@Entity +public class Option { + @Column(name = "OPTION_ID") + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + Long id; + + @Column(name = "OPTION_VALUE") + String value; + +// public Option() {} +// public Option(String value) { +// this.value = value; +// } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} 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..21c417b --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java @@ -0,0 +1,55 @@ +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//(strategy = GenerationType.AUTO) + @Column(name = "POLL_ID") + private Long id; + + @NotEmpty + @Column(name = "QUESTION") + private String question; + + @OneToMany(cascade = CascadeType.ALL) + @Size(min=2, max=6) + @JoinColumn(name = "POLL_ID") + @OrderBy + private Set