diff --git a/README.md b/README.md index 2c6950e..f8269af 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.dtos` ## Part 4.1 - Create class `OptionCount` diff --git a/pom.xml b/pom.xml index ed84c9b..bd9c78b 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,29 @@ javax.inject 1 + + + + + + + + javax.xml.bind + jaxb-api + 2.3.0 + + + + org.springframework + spring-jdbc + 5.1.3.RELEASE + + + + com.h2database + h2 + runtime + 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..dd09f5c --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/ComputeResultController.java @@ -0,0 +1,50 @@ +package io.zipcoder.tc_spring_poll_application.controller; + + +import io.zipcoder.tc_spring_poll_application.dtos.OptionCount; +import io.zipcoder.tc_spring_poll_application.dtos.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; + +import java.util.HashMap; +import java.util.Map; + +@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); + OptionCount optionCount; + Integer allVotesCount = 0; + Map voteCounts = new HashMap<>(); + for (Vote element : allVotes) { + allVotesCount++; + optionCount = voteCounts.get(element.getOption().getId()); + if (optionCount == null) { + optionCount = new OptionCount(); + optionCount.setOptionId(element.getOption().getId()); + voteCounts.put(element.getOption().getId(), optionCount); + } + optionCount.setCount(optionCount.getCount() + 1); + } + voteResult.setTotalVotes(allVotesCount); + voteResult.setResults(voteCounts.values()); + 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..f4a9c66 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/PollController.java @@ -0,0 +1,93 @@ +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.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.annotation.Resource; +import javax.validation.OverridesAttribute; +import javax.validation.Valid; +import java.net.URI; + +@RestController +public class PollController { + +// public void setLocation () { +// URI newPollUri = ServletUriComponentsBuilder +// .fromCurrentRequest() +// .path("/{id}") +// .buildAndExpand(poll.getId()) +// .toUri(); +// } + + + private PollRepository pollRepository; + + public PollController() { + } + + @Autowired + public PollController(PollRepository pollRepository) { + this.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( + @RequestBody @Valid Poll poll) { + poll = pollRepository.save(poll); + URI newPollUri = ServletUriComponentsBuilder + .fromCurrentRequest() + .path("/{id}") + .buildAndExpand(poll.getId()) + .toUri(); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setLocation(newPollUri); + return new ResponseEntity<>(newPollUri, HttpStatus.CREATED); + } + + @RequestMapping(value="/polls/{pollId}", method=RequestMethod.GET) + public ResponseEntity getPoll( + @PathVariable Long pollId) { + verifyPoll(pollId); + + Poll p = pollRepository.findOne(pollId); + return new ResponseEntity<> (p, HttpStatus.OK); + } + + @RequestMapping(value="/polls/{pollId}", method=RequestMethod.PUT) + public ResponseEntity updatePoll( + @RequestBody @Valid Poll poll, + @PathVariable Long pollId) { + verifyPoll(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) { + verifyPoll(pollId); + pollRepository.delete(pollId); + return new ResponseEntity<>(HttpStatus.OK); + } + + public void verifyPoll(Long pollId) { + if(pollRepository.findOne(pollId) == null) + throw new ResourceNotFoundException("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..775ef0b --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/controller/VoteController.java @@ -0,0 +1,48 @@ +package io.zipcoder.tc_spring_poll_application.controller; + +import io.zipcoder.tc_spring_poll_application.domain.Poll; +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); + // 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..0fa978f --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Option.java @@ -0,0 +1,42 @@ +package io.zipcoder.tc_spring_poll_application.domain; + + +import org.springframework.boot.autoconfigure.AutoConfigureOrder; + +import javax.persistence.*; + +@Entity +public class Option { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "OPTION_ID") + private Long id; + + @Column(name = "OPTION_VALUE") + private String value; + + public Option() { + } + + public Option(Long id, String value) { + this.id = id; + 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..55f2a93 --- /dev/null +++ b/src/main/java/io/zipcoder/tc_spring_poll_application/domain/Poll.java @@ -0,0 +1,60 @@ +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; + + @Column(name = "QUESTION") + @NotEmpty + private String question; + + @OneToMany(cascade = CascadeType.ALL) + @JoinColumn(name = "POLL_ID") + @OrderBy + @Size(min = 2, max = 6) + private Set