diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/controllers/PartieKahootController.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/controllers/PartieKahootController.java index 8aed2b6..631e1bb 100644 --- a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/controllers/PartieKahootController.java +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/controllers/PartieKahootController.java @@ -1,14 +1,16 @@ package fr.iut.sciencequest.sae.controllers; import fr.iut.sciencequest.sae.controllers.request.PartieAddJoueurRequest; +import fr.iut.sciencequest.sae.controllers.request.PartieReponse; import fr.iut.sciencequest.sae.controllers.request.PartieRequest; import fr.iut.sciencequest.sae.dto.partieKahoot.PartieKahootDTO; import fr.iut.sciencequest.sae.dto.partieKahoot.PartieKahootQuestionDTO; import fr.iut.sciencequest.sae.dto.partieKahoot.PartieKahootStatusDTO; +import fr.iut.sciencequest.sae.dto.reponse.ReponseValideDTO; import fr.iut.sciencequest.sae.entities.*; -import fr.iut.sciencequest.sae.exceptions.partie.PartyAlreadyStartedException; -import fr.iut.sciencequest.sae.exceptions.partie.PartyNotStartedException; +import fr.iut.sciencequest.sae.exceptions.partie.*; import fr.iut.sciencequest.sae.repositories.QuestionPartieKahootRepository; +import fr.iut.sciencequest.sae.repositories.ReponsePartieKahootRepository; import fr.iut.sciencequest.sae.repositories.ScorePartieKahootJoueurRepository; import fr.iut.sciencequest.sae.services.*; import jakarta.validation.Valid; @@ -18,10 +20,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; +import java.util.*; @RestController @AllArgsConstructor @@ -34,9 +33,11 @@ public class PartieKahootController { private final PartieKahootService partieKahootService; private final JoueurService joueurService; private final QuestionService questionService; + private final ReponseService reponseService; private final ThematiqueService thematiqueService; private final DifficulteService difficulteService; private final ModelMapper modelMapper; + private final ReponsePartieKahootRepository reponsePartieKahootRepository; @RequestMapping(value = "/{codeInvitation}",method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public PartieKahootDTO getPartie(@PathVariable String codeInvitation) { @@ -125,4 +126,46 @@ public class PartieKahootController { return this.modelMapper.map(partieKahoot, PartieKahootQuestionDTO.class); } + @PostMapping(value = "/{codeInvitation}/reponse", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(HttpStatus.OK) + public ReponseValideDTO repondre(@PathVariable String codeInvitation, @RequestBody @Valid PartieReponse request){ + PartieKahoot partieKahoot = this.partieKahootService.getPartieKahootByIdOrCodeInvitation(codeInvitation); + Joueur joueur = this.joueurService.findById(request.getIdJoueur()); + + if(partieKahoot.getStatus() != Status.Started){ + throw new PartyNotStartedException(); + } + + if(partieKahoot.getJoueurs().stream().noneMatch(joueur1 -> Objects.equals(joueur1.getId(), joueur.getId()))){ + throw new JoueurPasDansPartieException(); + } + + if(partieKahoot.getReponses().stream() + .filter(partieReponse -> Objects.equals(partieReponse.getJoueur().getId(), joueur.getId())) + .anyMatch(partieReponse -> Objects.equals(partieReponse.getQuestion().getId(), partieKahoot.getQuestionActuel().getId()))){ + throw new QuestionDejaReponduException(); + } + + + Reponse reponse = reponseService.findById(request.getIdReponse()); + if(!Objects.equals(reponse.getQuestion().getId(), partieKahoot.getQuestionActuel().getId())){ + throw new ReponseIncoherenteException(); + } + + Calendar actualDate = Calendar.getInstance(); + actualDate.setTime(new Date()); + if(actualDate.after(partieKahoot.getTempsLimiteReponse())){ + throw new ReponseTempsLimiteDepasseException(); + } + + ReponsePartieKahoot reponsePartie = new ReponsePartieKahoot(); + reponsePartie.setId(new ReponsePartieKahootKey(reponse.getQuestion().getId(), partieKahoot.getId(), joueur.getId())); + reponsePartie.setQuestion(reponse.getQuestion()); + reponsePartie.setPartie(partieKahoot); + reponsePartie.setJoueur(joueur); + this.reponsePartieKahootRepository.save(reponsePartie); + + return this.modelMapper.map(reponse, ReponseValideDTO.class); + } + } diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/controllers/request/PartieReponse.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/controllers/request/PartieReponse.java new file mode 100644 index 0000000..b5943ae --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/controllers/request/PartieReponse.java @@ -0,0 +1,14 @@ +package fr.iut.sciencequest.sae.controllers.request; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Data +public class PartieReponse { + @NotNull + private int idReponse; + @NotNull + private int idJoueur; +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/dto/reponse/ReponseValideDTO.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/dto/reponse/ReponseValideDTO.java new file mode 100644 index 0000000..c1a1632 --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/dto/reponse/ReponseValideDTO.java @@ -0,0 +1,19 @@ +package fr.iut.sciencequest.sae.dto.reponse; + +import com.fasterxml.jackson.annotation.JsonInclude; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import org.springframework.hateoas.RepresentationModel; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ReponseValideDTO extends RepresentationModel { + @NotNull + @NotBlank + private boolean estValide; +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/PartieKahoot.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/PartieKahoot.java index 250967c..c5d8fd5 100644 --- a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/PartieKahoot.java +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/PartieKahoot.java @@ -31,6 +31,10 @@ public class PartieKahoot extends Partie { @OneToMany(mappedBy = "partie", fetch = FetchType.EAGER) private List questions; + @JsonManagedReference + @OneToMany(mappedBy = "partie", fetch = FetchType.EAGER) + private List reponses; + @JsonManagedReference @OneToMany(mappedBy = "partie", fetch = FetchType.EAGER) private List scores; diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/ReponsePartieKahoot.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/ReponsePartieKahoot.java new file mode 100644 index 0000000..10dd856 --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/ReponsePartieKahoot.java @@ -0,0 +1,40 @@ +package fr.iut.sciencequest.sae.entities; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Entity +@Table(name="reponsepartiekahootjoueur") +public class ReponsePartieKahoot { + @EmbeddedId + private ReponsePartieKahootKey id = new ReponsePartieKahootKey(); + + @JsonBackReference + @ManyToOne + @MapsId("idQuestion") + @JoinColumn(name = "idquestion") + private Question question; + + @JsonBackReference + @ManyToOne + @MapsId("idPartie") + @JoinColumn(name="idpartie") + private PartieKahoot partie; + + @JsonBackReference + @ManyToOne + @MapsId("idJoueur") + @JoinColumn(name="idjoueur") + private Joueur joueur; + + @JsonBackReference + @ManyToOne + @JoinColumn(name = "idreponse") + private Reponse reponse; +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/ReponsePartieKahootKey.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/ReponsePartieKahootKey.java new file mode 100644 index 0000000..05c73f7 --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/entities/ReponsePartieKahootKey.java @@ -0,0 +1,25 @@ +package fr.iut.sciencequest.sae.entities; + + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Embeddable +public class ReponsePartieKahootKey implements Serializable { + @Column(name="idquestion") + private Integer idQuestion; + + @Column(name="idpartie") + private Integer idPartie; + + @Column(name="idjoueur") + private Integer idJoueur; +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/notFound/ReponseNotFoundException.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/notFound/ReponseNotFoundException.java new file mode 100644 index 0000000..4a4f482 --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/notFound/ReponseNotFoundException.java @@ -0,0 +1,7 @@ +package fr.iut.sciencequest.sae.exceptions.notFound; + +public class ReponseNotFoundException extends EntityNotFoundException{ + public ReponseNotFoundException(int id) { + super("Reponse", id); + } +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/JoueurPasDansPartieException.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/JoueurPasDansPartieException.java new file mode 100644 index 0000000..82e2596 --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/JoueurPasDansPartieException.java @@ -0,0 +1,12 @@ +package fr.iut.sciencequest.sae.exceptions.partie; + + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.PRECONDITION_FAILED) +public class JoueurPasDansPartieException extends RuntimeException { + public JoueurPasDansPartieException() { + super("Le joueur n'est pas présent dans la partie"); + } +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/QuestionDejaReponduException.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/QuestionDejaReponduException.java new file mode 100644 index 0000000..0009248 --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/QuestionDejaReponduException.java @@ -0,0 +1,12 @@ +package fr.iut.sciencequest.sae.exceptions.partie; + + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.FORBIDDEN) +public class QuestionDejaReponduException extends RuntimeException { + public QuestionDejaReponduException() { + super("Le joueur a déjà répondu à la question"); + } +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/ReponseIncoherenteException.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/ReponseIncoherenteException.java new file mode 100644 index 0000000..861f458 --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/ReponseIncoherenteException.java @@ -0,0 +1,12 @@ +package fr.iut.sciencequest.sae.exceptions.partie; + + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.PRECONDITION_FAILED) +public class ReponseIncoherenteException extends RuntimeException { + public ReponseIncoherenteException() { + super("La réponse ne correspond pas à la question en cours"); + } +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/ReponseTempsLimiteDepasseException.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/ReponseTempsLimiteDepasseException.java new file mode 100644 index 0000000..da3df7c --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/exceptions/partie/ReponseTempsLimiteDepasseException.java @@ -0,0 +1,12 @@ +package fr.iut.sciencequest.sae.exceptions.partie; + + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.PRECONDITION_FAILED) +public class ReponseTempsLimiteDepasseException extends RuntimeException { + public ReponseTempsLimiteDepasseException() { + super("La réponse a été donné trop tard"); + } +} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/repositories/ReponsePartieKahootRepository.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/repositories/ReponsePartieKahootRepository.java new file mode 100644 index 0000000..74ea98d --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/repositories/ReponsePartieKahootRepository.java @@ -0,0 +1,11 @@ +package fr.iut.sciencequest.sae.repositories; + +import fr.iut.sciencequest.sae.entities.ReponsePartieKahoot; +import fr.iut.sciencequest.sae.entities.ReponsePartieKahootKey; +import fr.iut.sciencequest.sae.entities.ScorePartieKahootJoueur; +import fr.iut.sciencequest.sae.entities.ScorePartieKahootJoueurKey; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ReponsePartieKahootRepository extends CrudRepository {} diff --git a/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/services/ReponseService.java b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/services/ReponseService.java new file mode 100644 index 0000000..8cd67e7 --- /dev/null +++ b/SpringBootProject/src/main/java/fr/iut/sciencequest/sae/services/ReponseService.java @@ -0,0 +1,28 @@ +package fr.iut.sciencequest.sae.services; + +import fr.iut.sciencequest.sae.entities.Difficulte; +import fr.iut.sciencequest.sae.entities.Question; +import fr.iut.sciencequest.sae.entities.Reponse; +import fr.iut.sciencequest.sae.entities.Thematique; +import fr.iut.sciencequest.sae.exceptions.notFound.ReponseNotFoundException; +import fr.iut.sciencequest.sae.exceptions.notFound.ThematiqueNotFoundException; +import fr.iut.sciencequest.sae.repositories.QuestionRepository; +import fr.iut.sciencequest.sae.repositories.ReponseRepository; +import lombok.AllArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.List; + +@AllArgsConstructor +@Service +public class ReponseService { + private final ReponseRepository reponseRepository; + public Reponse findById(int id) { + return this.reponseRepository.findById(id).orElseThrow(() -> + new ReponseNotFoundException(id) + ); + } + +} diff --git a/SpringBootProject/src/main/resources/schema.sql b/SpringBootProject/src/main/resources/schema.sql index 92f8343..c79b41b 100644 --- a/SpringBootProject/src/main/resources/schema.sql +++ b/SpringBootProject/src/main/resources/schema.sql @@ -16,6 +16,7 @@ DROP TABLE IF EXISTS ThematiqueSelectionnee CASCADE; DROP TABLE IF EXISTS PartieKahoot CASCADE; DROP TABLE IF EXISTS QuestionPartieKahoot CASCADE; DROP TABLE IF EXISTS ScorePartieKahootjoueur CASCADE; +DROP TABLE IF EXISTS ReponsePartieKahootJoueur CASCADE; DROP TABLE IF EXISTS Difficulte; @@ -189,6 +190,14 @@ CREATE TABLE ScorePartieKahootjoueur( PRIMARY KEY (idJoueur, idPartie) ); +--ReponsePartieKahootJoueur +CREATE TABLE ReponsePartieKahootJoueur( + idJoueur integer REFERENCES Joueur(id), + idPartie integer REFERENCES PartieKahoot(idPartie), + idQuestion integer REFERENCES Question(id), + idReponse integer REFERENCES Reponse(id) +); + -- TRIGGERS