jour 4 -- après-midi

Springboot
Victor SOULIER 1 year ago
parent 0b22f02742
commit a2fe781a96

@ -50,6 +50,11 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId> <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.2.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

@ -4,13 +4,14 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.accept.FixedContentNegotiationStrategy; import org.springframework.web.accept.FixedContentNegotiationStrategy;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List; import java.util.List;
@Configuration @Configuration
public class ApplicationConfig implements WebMvcConfigurer { public class ApplicationConfig implements WebMvcConfigurer {
public static final int DEFAULT_PAGEABLE_SIZE = 1;
// Permet de forcer l'affichage des erreurs en JSON sans prendre en compte les headers du client // Permet de forcer l'affichage des erreurs en JSON sans prendre en compte les headers du client
@Override @Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

@ -7,18 +7,16 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingResponseWrapper; import org.springframework.web.util.ContentCachingResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -32,7 +30,8 @@ public class ApplicationFilter extends OncePerRequestFilter {
} }
@Override @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { @NonNull
protected void doFilterInternal(@Nullable HttpServletRequest request, @Nullable HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// Intercept and modify the JSON response // Intercept and modify the JSON response
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);

@ -3,6 +3,8 @@ package fr.iut.sciencequest.sae;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -12,8 +14,10 @@ public class SaeApplication {
public WebMvcConfigurer corsConfigurer() { public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() { return new WebMvcConfigurer() {
@Override @Override
public void addCorsMappings(CorsRegistry registry) { @NonNull
registry.addMapping("/**").allowedOrigins("*"); public void addCorsMappings(@Nullable CorsRegistry registry) {
assert registry != null;
registry.addMapping("/**").allowedOrigins("*");
} }
}; };
} }

@ -0,0 +1,24 @@
package fr.iut.sciencequest.sae.assemblers;
import fr.iut.sciencequest.sae.controllers.PartieController;
import fr.iut.sciencequest.sae.entities.Partie;
import fr.iut.sciencequest.sae.dto.PartieDTO;
import jakarta.annotation.Nullable;
import org.modelmapper.ModelMapper;
import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
@Component
public class PartieModelAssembler extends RepresentationModelAssemblerSupport<Partie, PartieDTO> {
public PartieModelAssembler() {
super(PartieController.class, PartieDTO.class);
}
@Override
@NonNull
public PartieDTO toModel(@Nullable Partie entity) {
ModelMapper mapper = new ModelMapper();
return mapper.map(entity, PartieDTO.class);
}
}

@ -2,25 +2,24 @@ package fr.iut.sciencequest.sae.assemblers;
import fr.iut.sciencequest.sae.controllers.QuestionController; import fr.iut.sciencequest.sae.controllers.QuestionController;
import fr.iut.sciencequest.sae.entities.Question; import fr.iut.sciencequest.sae.entities.Question;
import fr.iut.sciencequest.sae.models.QuestionModel; import fr.iut.sciencequest.sae.dto.QuestionDTO;
import jakarta.annotation.Nullable;
import org.modelmapper.ModelMapper;
import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport; import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
public class QuestionModelAssembler extends RepresentationModelAssemblerSupport<Question, QuestionModel> { public class QuestionModelAssembler extends RepresentationModelAssemblerSupport<Question, QuestionDTO> {
public QuestionModelAssembler() { public QuestionModelAssembler() {
super(QuestionController.class, QuestionModel.class); super(QuestionController.class, QuestionDTO.class);
} }
@Override @Override
public QuestionModel toModel(Question entity) { @NonNull
QuestionModel questionModel = instantiateModel(entity); public QuestionDTO toModel(@Nullable Question entity) {
ModelMapper mapper = new ModelMapper();
questionModel.setQuestion(entity.getQuestion()); return mapper.map(entity, QuestionDTO.class);
questionModel.setId(entity.getId());
questionModel.setReponses(entity.getReponses());
return questionModel;
} }
} }

@ -0,0 +1,24 @@
package fr.iut.sciencequest.sae.assemblers;
import fr.iut.sciencequest.sae.controllers.ScientifiqueController;
import fr.iut.sciencequest.sae.dto.ScientifiqueDTO;
import fr.iut.sciencequest.sae.entities.scientifique.Scientifique;
import jakarta.annotation.Nullable;
import org.modelmapper.ModelMapper;
import org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
@Component
public class ScientifiqueModelAssembler extends RepresentationModelAssemblerSupport<Scientifique, ScientifiqueDTO> {
public ScientifiqueModelAssembler() {
super(ScientifiqueController.class, ScientifiqueDTO.class);
}
@Override
@NonNull
public ScientifiqueDTO toModel(@Nullable Scientifique entity) {
ModelMapper mapper = new ModelMapper();
return mapper.map(entity, ScientifiqueDTO.class);
}
}

@ -8,9 +8,7 @@ import org.springframework.hateoas.Link;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;

@ -4,8 +4,6 @@ package fr.iut.sciencequest.sae.controllers;
import fr.iut.sciencequest.sae.entities.Difficulte; import fr.iut.sciencequest.sae.entities.Difficulte;
import fr.iut.sciencequest.sae.services.DifficulteService; import fr.iut.sciencequest.sae.services.DifficulteService;
import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -13,9 +11,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
@RestController @RestController
@RequestMapping("/api/v1/difficultes") @RequestMapping("/api/v1/difficultes")

@ -1,11 +1,19 @@
package fr.iut.sciencequest.sae.controllers; package fr.iut.sciencequest.sae.controllers;
import fr.iut.sciencequest.sae.assemblers.PartieModelAssembler;
import fr.iut.sciencequest.sae.assemblers.QuestionModelAssembler;
import fr.iut.sciencequest.sae.dto.PartieDTO;
import fr.iut.sciencequest.sae.entities.Partie; import fr.iut.sciencequest.sae.entities.Partie;
import fr.iut.sciencequest.sae.entities.Question;
import fr.iut.sciencequest.sae.exceptions.DuplicatedFieldException; import fr.iut.sciencequest.sae.exceptions.DuplicatedFieldException;
import fr.iut.sciencequest.sae.exceptions.notFound.PartieNotFoundException; import fr.iut.sciencequest.sae.exceptions.notFound.PartieNotFoundException;
import fr.iut.sciencequest.sae.repositories.PartieRepository; import fr.iut.sciencequest.sae.repositories.PartieRepository;
import fr.iut.sciencequest.sae.services.PartieService;
import fr.iut.sciencequest.sae.services.QuestionService;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link; import org.springframework.hateoas.Link;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -16,25 +24,21 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
import java.util.Optional; import java.util.Optional;
@RestController @RestController
@AllArgsConstructor
@RequestMapping("/api/v1/partie") @RequestMapping("/api/v1/partie")
public class PartieController extends Controller { public class PartieController extends Controller {
private final PartieRepository partieRepository; private final PartieModelAssembler partieModelAssembler;
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
public PartieController(PartieRepository partieRepository) { private final PagedResourcesAssembler<Partie> pagedResourcesAssembler;
this.partieRepository = partieRepository; private final PartieService partieService;
}
@RequestMapping(value = "/{id}",method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/{id}",method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public EntityModel<Optional<Partie>> getPartie(@PathVariable int id, HttpServletRequest request) { public PartieDTO getPartie(@PathVariable int id) {
Optional<Partie> partieOptional = this.partieRepository.findById(id); Partie partie = this.partieService.findById(id);
Partie partie = partieOptional.orElseThrow(() -> return partieModelAssembler.toModel(partie);
new PartieNotFoundException("Partie", id)
);
Link selfLink = linkTo(methodOn(PartieController.class).getPartie(id,request)).withSelfRel();
return EntityModel.of(Optional.ofNullable(partie), selfLink);
} }
/*
@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.CREATED) @ResponseStatus(HttpStatus.CREATED)
public Partie createPartie(@RequestBody Partie partie) { public Partie createPartie(@RequestBody Partie partie) {
@ -43,7 +47,7 @@ public class PartieController extends Controller {
} catch (DataIntegrityViolationException e) { } catch (DataIntegrityViolationException e) {
throw new DuplicatedFieldException("ERREUR : il existe déjà une partie : " + partie.getId() + " en base"); throw new DuplicatedFieldException("ERREUR : il existe déjà une partie : " + partie.getId() + " en base");
} }
} }*/
} }

@ -1,36 +1,32 @@
package fr.iut.sciencequest.sae.controllers; package fr.iut.sciencequest.sae.controllers;
import fr.iut.sciencequest.sae.ApplicationConfig;
import fr.iut.sciencequest.sae.assemblers.QuestionModelAssembler; import fr.iut.sciencequest.sae.assemblers.QuestionModelAssembler;
import fr.iut.sciencequest.sae.entities.Question; import fr.iut.sciencequest.sae.entities.Question;
import fr.iut.sciencequest.sae.exceptions.IncorrectPageException; import fr.iut.sciencequest.sae.exceptions.IncorrectPageException;
import fr.iut.sciencequest.sae.models.QuestionModel; import fr.iut.sciencequest.sae.dto.QuestionDTO;
import fr.iut.sciencequest.sae.services.QuestionService; import fr.iut.sciencequest.sae.services.QuestionService;
import org.springframework.beans.factory.annotation.Autowired; import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.PagedResourcesAssembler; import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.PagedModel; import org.springframework.hateoas.PagedModel;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@RestController @RestController
@AllArgsConstructor
@RequestMapping("/api/v1/questions") @RequestMapping("/api/v1/questions")
public class QuestionController extends Controller { public class QuestionController extends Controller {
private final QuestionService questionService; private final QuestionService questionService;
private final QuestionModelAssembler questionModelAssembler;
@Autowired @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
private QuestionModelAssembler questionModelAssembler; private final PagedResourcesAssembler<Question> pagedResourcesAssembler;
@Autowired
private PagedResourcesAssembler<Question> pagedResourcesAssembler;
public QuestionController(QuestionService questionService) {
this.questionService = questionService;
}
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody @ResponseBody
public PagedModel<QuestionModel> getAllQuestions(Pageable p) { public PagedModel<QuestionDTO> getAllQuestions(@PageableDefault(size = ApplicationConfig.DEFAULT_PAGEABLE_SIZE) Pageable p) {
try { try {
Page<Question> questionPage = questionService.findAll(p); Page<Question> questionPage = questionService.findAll(p);
return pagedResourcesAssembler.toModel(questionPage, questionModelAssembler); return pagedResourcesAssembler.toModel(questionPage, questionModelAssembler);

@ -1,5 +1,11 @@
package fr.iut.sciencequest.sae.controllers; package fr.iut.sciencequest.sae.controllers;
import fr.iut.sciencequest.sae.ApplicationConfig;
import fr.iut.sciencequest.sae.assemblers.QuestionModelAssembler;
import fr.iut.sciencequest.sae.assemblers.ScientifiqueModelAssembler;
import fr.iut.sciencequest.sae.dto.QuestionDTO;
import fr.iut.sciencequest.sae.dto.ScientifiqueDTO;
import fr.iut.sciencequest.sae.entities.Question;
import fr.iut.sciencequest.sae.entities.scientifique.Scientifique; import fr.iut.sciencequest.sae.entities.scientifique.Scientifique;
import fr.iut.sciencequest.sae.entities.indice.IIndiceidAndLibelleAndScientifiqueIdOnlyProjection; import fr.iut.sciencequest.sae.entities.indice.IIndiceidAndLibelleAndScientifiqueIdOnlyProjection;
import fr.iut.sciencequest.sae.entities.indice.Indice; import fr.iut.sciencequest.sae.entities.indice.Indice;
@ -7,10 +13,14 @@ import fr.iut.sciencequest.sae.entities.indice.IValidateOnlyLibelle;
import fr.iut.sciencequest.sae.exceptions.IncorrectPageException; import fr.iut.sciencequest.sae.exceptions.IncorrectPageException;
import fr.iut.sciencequest.sae.services.IndiceService; import fr.iut.sciencequest.sae.services.IndiceService;
import fr.iut.sciencequest.sae.services.interfaces.IScientifiqueService; import fr.iut.sciencequest.sae.services.interfaces.IScientifiqueService;
import org.springframework.data.projection.ProjectionFactory; import lombok.AllArgsConstructor;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.PagedModel;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -18,24 +28,21 @@ import org.springframework.web.bind.annotation.*;
import java.util.Optional; import java.util.Optional;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
@RestController @RestController
@AllArgsConstructor
@RequestMapping("/api/v1/scientifiques") @RequestMapping("/api/v1/scientifiques")
public class ScientifiqueController extends Controller { public class ScientifiqueController extends Controller {
private final IScientifiqueService scientifiqueService; private final IScientifiqueService scientifiqueService;
private final ScientifiqueModelAssembler scientifiqueModelAssembler;
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
private final PagedResourcesAssembler<Scientifique> pagedResourcesAssembler;
private final IndiceService indiceService; private final IndiceService indiceService;
public ScientifiqueController(IScientifiqueService scientifiqueService, IndiceService indiceService) {
this.scientifiqueService = scientifiqueService;
this.indiceService = indiceService;
}
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public CollectionModel<EntityModel<Scientifique>> getAllScientists(@RequestParam(name = "page") Optional<Integer> page) { public PagedModel<ScientifiqueDTO> getAllScientists(@PageableDefault(size = ApplicationConfig.DEFAULT_PAGEABLE_SIZE) Pageable p) {
try { try {
return getPageableCollectionModel(this.scientifiqueService.findAll(page.orElse(0)), page.orElse(0),"getAllScientists"); return pagedResourcesAssembler.toModel(this.scientifiqueService.findAll(p), scientifiqueModelAssembler);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new IncorrectPageException("numéro de page incorrect"); throw new IncorrectPageException("numéro de page incorrect");
} }

@ -1,10 +1,11 @@
package fr.iut.sciencequest.sae.models; package fr.iut.sciencequest.sae.dto;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import fr.iut.sciencequest.sae.entities.Reponse; import fr.iut.sciencequest.sae.entities.Reponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.*; import lombok.*;
import org.springframework.hateoas.RepresentationModel; import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.core.Relation;
import java.util.List; import java.util.List;
@ -15,8 +16,10 @@ import java.util.List;
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class QuestionModel extends RepresentationModel<QuestionModel> { public class IndiceDTO extends RepresentationModel<QuestionDTO> {
@NotNull
private int id; private int id;
private String question; private String question;
@NotEmpty
private List<Reponse> reponses; private List<Reponse> reponses;
} }

@ -0,0 +1,29 @@
package fr.iut.sciencequest.sae.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import fr.iut.sciencequest.sae.entities.Partie;
import fr.iut.sciencequest.sae.entities.Reponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import org.springframework.hateoas.RepresentationModel;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class JoueurDTO extends RepresentationModel<JoueurDTO> {
@NotNull
private int id;
@NotBlank
private String pseudo;
private Partie partie;
}

@ -0,0 +1,27 @@
package fr.iut.sciencequest.sae.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import fr.iut.sciencequest.sae.entities.Jeu;
import fr.iut.sciencequest.sae.entities.joueur.Joueur;
import jakarta.validation.constraints.NotEmpty;
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 PartieDTO extends RepresentationModel<PartieDTO> {
@NotNull
private int id;
@NotEmpty
private String codeInvitation;
@NotEmpty
private Iterable<Joueur> joueurs;
@NotEmpty
private Jeu jeu;
}

@ -0,0 +1,27 @@
package fr.iut.sciencequest.sae.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import fr.iut.sciencequest.sae.entities.Reponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import org.springframework.hateoas.RepresentationModel;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class QuestionDTO extends RepresentationModel<QuestionDTO> {
@NotNull
private int id;
@NotBlank
private String question;
@NotEmpty
private Iterable<Reponse> reponses;
}

@ -0,0 +1,54 @@
package fr.iut.sciencequest.sae.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import fr.iut.sciencequest.sae.entities.Difficulte;
import fr.iut.sciencequest.sae.entities.Sexe;
import fr.iut.sciencequest.sae.entities.Thematique;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.*;
import org.hibernate.validator.constraints.URL;
import org.springframework.hateoas.RepresentationModel;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ScientifiqueDTO extends RepresentationModel<ScientifiqueDTO> {
@NotNull
private int id;
@NotNull
private Difficulte difficulte;
@NotNull
private Thematique thematique;
@URL
private String pathToPhoto;
@NotBlank
private String nom;
@NotBlank
private String prenom;
@NotBlank
private String descriptif;
@NotEmpty
private Date dateNaissance;
@NotBlank
private Sexe sexe;
@Size(min=0, max=1)
private double ratioTrouvee;
}

@ -6,11 +6,13 @@ import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Entity @Entity
@Table(name="admin") @Table(name="admin")
public class Admin extends BaseEntity { public class Admin extends BaseEntity {

@ -5,12 +5,15 @@ import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.modelmapper.internal.bytebuddy.implementation.bind.annotation.Super;
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Entity @Entity
@Table(name="difficulte") @Table(name="difficulte")
public class Difficulte extends BaseEntity { public class Difficulte extends BaseEntity {

@ -1,5 +1,5 @@
package fr.iut.sciencequest.sae.entities; package fr.iut.sciencequest.sae.entities;
public interface IToProjection { public interface IToProjection {
public <T> T toProjection(Class<T> projectionType); <T> T toProjection(Class<T> projectionType);
} }

@ -1,6 +1,7 @@
package fr.iut.sciencequest.sae.entities; package fr.iut.sciencequest.sae.entities;
import fr.iut.sciencequest.sae.entities.joueur.Joueur;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -11,5 +12,6 @@ import lombok.EqualsAndHashCode;
@Data @Data
@Entity @Entity
@Table(name = "invite") @Table(name = "invite")
@PrimaryKeyJoinColumn(name = "idjoueur")
public class Invite extends Joueur { public class Invite extends Joueur {
} }

@ -6,24 +6,26 @@ import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Entity @Entity
@Table(name="jeu") @Table(name="jeu")
public class Jeu extends BaseEntity { public class Jeu extends BaseEntity {
@Id @Id
@NotNull //@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; private int id;
@NotBlank //@NotBlank
@Column(unique = true) @Column(unique = true)
private String nom; private String nom;
@Column(name = "nbrparties") @Column(name = "nbrparties")
@Min(0) //@Min(0)
private int nbrParties = 0; private int nbrParties = 0;
} }

@ -1,11 +1,18 @@
package fr.iut.sciencequest.sae.entities; package fr.iut.sciencequest.sae.entities;
import fr.iut.sciencequest.sae.entities.joueur.Joueur;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import java.util.List;
@EqualsAndHashCode(callSuper = true)
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@Data @Data
@ -13,21 +20,18 @@ import lombok.NoArgsConstructor;
@Table(name="partie") @Table(name="partie")
public class Partie extends BaseEntity { public class Partie extends BaseEntity {
@Id @Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; private int id;
@Column(name = "codeinvitation", unique = true) @Column(name = "codeinvitation", unique = true)
private String codeInvitation; private String codeInvitation;
/*private Jeu jeu;
@Getter() private Set<Joueur> joueurs;
public boolean add(Joueur joueur){ @OneToMany(mappedBy = "id")
return this.joueurs.add(joueur); @Fetch(FetchMode.JOIN) // Sinon crash (Could not write JSON: failed to lazily initialize a collection of role)
} private List<Joueur> joueurs;
public boolean remove(Joueur joueur){ @NotNull
return this.joueurs.remove(joueur); @ManyToOne
} @JoinColumn(name="idjeu")
*/ private Jeu jeu;
} }

@ -4,6 +4,7 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.hibernate.annotations.Fetch; import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.FetchMode;
@ -14,16 +15,15 @@ import java.util.List;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Entity @Entity
@Table(name="question") @Table(name="question")
public class Question extends BaseEntity { public class Question extends BaseEntity {
@Id @Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; private int id;
private String question; private String question;
@NotEmpty
@OneToMany(mappedBy = "id") @OneToMany(mappedBy = "id")
@Fetch(FetchMode.JOIN) // Sinon crash (Could not write JSON: failed to lazily initialize a collection of role) @Fetch(FetchMode.JOIN) // Sinon crash (Could not write JSON: failed to lazily initialize a collection of role)
private List<Reponse> reponses; private List<Reponse> reponses;

@ -4,11 +4,13 @@ import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Entity @Entity
@Table(name="reponse") @Table(name="reponse")
public class Reponse extends BaseEntity { public class Reponse extends BaseEntity {

@ -5,12 +5,14 @@ import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Entity @Entity
@Table(name="thematique") @Table(name="thematique")
public class Thematique extends BaseEntity { public class Thematique extends BaseEntity {

@ -1,6 +1,7 @@
package fr.iut.sciencequest.sae.entities; package fr.iut.sciencequest.sae.entities;
import fr.iut.sciencequest.sae.entities.joueur.Joueur;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
@ -16,7 +17,8 @@ import lombok.NoArgsConstructor;
@Data @Data
@Entity @Entity
@Table(name="utilisateur") @Table(name="utilisateur")
public class Utilisateur extends Joueur{ @PrimaryKeyJoinColumn(name = "idjoueur")
public class Utilisateur extends Joueur {
@Email(message="Veuillez fournir une adresse mail valide") @Email(message="Veuillez fournir une adresse mail valide")
@NotNull @NotNull
@Column(unique = true) @Column(unique = true)

@ -7,11 +7,13 @@ import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Entity @Entity
@Table(name="indice") @Table(name="indice")
public class Indice extends BaseEntity { public class Indice extends BaseEntity {

@ -0,0 +1,6 @@
package fr.iut.sciencequest.sae.entities.joueur;
public interface IIdAndPseudoOnlyProjection {
int getId();
String getPseudo();
}

@ -1,26 +1,31 @@
package fr.iut.sciencequest.sae.entities; package fr.iut.sciencequest.sae.entities.joueur;
import fr.iut.sciencequest.sae.entities.BaseEntity;
import fr.iut.sciencequest.sae.entities.Partie;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Inheritance ( strategy = InheritanceType.JOINED) @Inheritance ( strategy = InheritanceType.JOINED)
@Entity @Entity
@Table(name="joueur") @Table(name="joueur")
public abstract class Joueur extends BaseEntity { public abstract class Joueur extends BaseEntity {
@Id @Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; private int id;
@NotBlank
@Column(unique = true) @Column(unique = true)
private String pseudo; private String pseudo;
//private Partie partie;
@ManyToOne
@JoinColumn(name="idpartie")
private Partie partie;
} }

@ -10,8 +10,8 @@ import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.URL; import org.hibernate.validator.constraints.URL;
import org.springframework.hateoas.server.core.Relation; import org.springframework.hateoas.server.core.Relation;
@ -21,46 +21,37 @@ import java.util.Date;
@RequiredArgsConstructor @RequiredArgsConstructor
@Relation(collectionRelation = "scientifiques", itemRelation = "scientifique") @Relation(collectionRelation = "scientifiques", itemRelation = "scientifique")
@Data @Data
@EqualsAndHashCode(callSuper = false)
@Entity @Entity
@Table(name = "scientifique") @Table(name = "scientifique")
public class Scientifique extends BaseEntity { public class Scientifique extends BaseEntity {
@Id @Id
@NotNull
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; private int id;
@NotNull
@ManyToOne @ManyToOne
@JoinColumn(name="iddifficulte") @JoinColumn(name="iddifficulte")
private Difficulte difficulte; private Difficulte difficulte;
@NotNull
@ManyToOne @ManyToOne
@JoinColumn(name="idthematique") @JoinColumn(name="idthematique")
private Thematique thematique; private Thematique thematique;
@URL
@Column(name = "photo") @Column(name = "photo")
private String pathToPhoto; private String pathToPhoto;
@NotBlank
private String nom; private String nom;
@NotBlank
private String prenom; private String prenom;
@NotBlank
private String descriptif; private String descriptif;
@NotBlank
@Column(name = "datenaissance") @Column(name = "datenaissance")
private Date dateNaissance; private Date dateNaissance;
@NotBlank
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
private Sexe sexe; private Sexe sexe;
@Column(name = "ratiotrouvee") @Column(name = "ratiotrouvee")
@Size(min=0, max=1)
private double ratioTrouve = 0.0; private double ratioTrouve = 0.0;
} }

@ -5,8 +5,6 @@ import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository @Repository
public interface IndiceRepository extends PagingAndSortingRepository<Indice, Integer>, CrudRepository<Indice, Integer> { public interface IndiceRepository extends PagingAndSortingRepository<Indice, Integer>, CrudRepository<Indice, Integer> {
<T> Iterable<T> findByScientifiqueId(int id, Class<T> type); <T> Iterable<T> findByScientifiqueId(int id, Class<T> type);

@ -1,6 +1,6 @@
package fr.iut.sciencequest.sae.repositories; package fr.iut.sciencequest.sae.repositories;
import fr.iut.sciencequest.sae.entities.Joueur; import fr.iut.sciencequest.sae.entities.joueur.Joueur;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;

@ -1,11 +1,7 @@
package fr.iut.sciencequest.sae.repositories; package fr.iut.sciencequest.sae.repositories;
import fr.iut.sciencequest.sae.entities.Question; import fr.iut.sciencequest.sae.entities.Question;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
@Repository @Repository

@ -7,5 +7,5 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public interface ThematiqueRepository extends CrudRepository<Thematique, Integer> { public interface ThematiqueRepository extends CrudRepository<Thematique, Integer> {
public boolean existsByLibelle(String libelle); boolean existsByLibelle(String libelle);
} }

@ -1,4 +1,25 @@
package fr.iut.sciencequest.sae.services; package fr.iut.sciencequest.sae.services;
public class PartieService { import fr.iut.sciencequest.sae.entities.Partie;
import fr.iut.sciencequest.sae.exceptions.notFound.PartieNotFoundException;
import fr.iut.sciencequest.sae.repositories.PartieRepository;
import fr.iut.sciencequest.sae.services.interfaces.IPartieService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Optional;
@AllArgsConstructor
@Service
public class PartieService implements IPartieService {
private final PartieRepository partieRepository;
public Partie findById(int id) {
return this.partieRepository.findById(id).orElseThrow(() ->
new PartieNotFoundException("Partie", id)
);
}
public Partie save(Partie p) {
return new Partie();
}
} }

@ -4,13 +4,11 @@ import fr.iut.sciencequest.sae.entities.Question;
import fr.iut.sciencequest.sae.repositories.QuestionRepository; import fr.iut.sciencequest.sae.repositories.QuestionRepository;
import fr.iut.sciencequest.sae.services.interfaces.IQuestionService; import fr.iut.sciencequest.sae.services.interfaces.IQuestionService;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@Service @Service
public class QuestionService implements IQuestionService { public class QuestionService implements IQuestionService {
private static final int PAGE_SIZE = 1;
private final QuestionRepository questionRepository; private final QuestionRepository questionRepository;
public QuestionService(QuestionRepository questionRepository) { public QuestionService(QuestionRepository questionRepository) {

@ -10,8 +10,6 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
@Service @Service
public class ScientifiqueService implements IScientifiqueService { public class ScientifiqueService implements IScientifiqueService {
@ -36,9 +34,8 @@ public class ScientifiqueService implements IScientifiqueService {
} }
@Override @Override
public Page<Scientifique> findAll(Integer page) { public Page<Scientifique> findAll(Pageable page) {
Pageable paging = PageRequest.of(page, PAGE_SIZE); return scientifiqueRepository.findAll(page);
return scientifiqueRepository.findAll(paging);
} }
@Override @Override

@ -1,5 +1,8 @@
package fr.iut.sciencequest.sae.services.interfaces; package fr.iut.sciencequest.sae.services.interfaces;
public class IPartieService { import fr.iut.sciencequest.sae.entities.Partie;
public interface IPartieService {
Partie findById(int id);
Partie save(Partie p);
} }

@ -3,13 +3,14 @@ package fr.iut.sciencequest.sae.services.interfaces;
import fr.iut.sciencequest.sae.entities.scientifique.Scientifique; import fr.iut.sciencequest.sae.entities.scientifique.Scientifique;
import fr.iut.sciencequest.sae.entities.indice.IIndiceidAndLibelleAndScientifiqueIdOnlyProjection; import fr.iut.sciencequest.sae.entities.indice.IIndiceidAndLibelleAndScientifiqueIdOnlyProjection;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface IScientifiqueService { public interface IScientifiqueService {
Scientifique update(Scientifique scientifique); Scientifique update(Scientifique scientifique);
Scientifique create(Scientifique scientifique); Scientifique create(Scientifique scientifique);
Page<Scientifique> findAll(Integer page); Page<Scientifique> findAll(Pageable page);
Scientifique findById(int id); Scientifique findById(int id);

@ -94,7 +94,7 @@ CREATE TABLE Jeu(
CREATE TABLE Partie( CREATE TABLE Partie(
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
codeInvitation varchar(10) NOT NULL UNIQUE, codeInvitation varchar(5) NOT NULL UNIQUE,
idJeu integer REFERENCES Jeu(id) idJeu integer REFERENCES Jeu(id)
); );
@ -166,11 +166,16 @@ VALUES
('Sophie Germain', 3, 3); ('Sophie Germain', 3, 3);
-- Utilisateurs -- Utilisateurs
INSERT INTO Joueur(id,pseudo) VALUES (1337, 'moi, le meilleur joueur du monde'); INSERT INTO Joueur(pseudo) VALUES ('moi, le meilleur joueur du monde'); --id = 1
INSERT INTO Utilisateur(idJoueur,email,password) VALUES (1337, 'joueur','$2y$10$juGnlWC9cS19popEKLZsYeir0Jl39k6hDl0dpaCix00FDcdiEbtmS'); INSERT INTO Utilisateur(idJoueur,email,password) VALUES (1, 'joueur','$2y$10$juGnlWC9cS19popEKLZsYeir0Jl39k6hDl0dpaCix00FDcdiEbtmS');
-- mdp = test -- mdp = test
INSERT INTO decouvrir(idUtilisateur,idScientifique) VALUES (1337,1); -- Découvrir
INSERT INTO decouvrir(idUtilisateur,idScientifique) VALUES (1,1);
-- Admin
INSERT INTO Admin(id,email,password) VALUES (1, 'admin','$2y$10$juGnlWC9cS19popEKLZsYeir0Jl39k6hDl0dpaCix00FDcdiEbtmS'); INSERT INTO Admin(id,email,password) VALUES (1, 'admin','$2y$10$juGnlWC9cS19popEKLZsYeir0Jl39k6hDl0dpaCix00FDcdiEbtmS');
-- mdp = test -- mdp = test
-- Partie
INSERT INTO Partie(codeInvitation, idJeu) VALUES ('abcde', 1);
Loading…
Cancel
Save