10 Commits

Author SHA1 Message Date
trochas
cb685ef004 readme, ajout info sur l'état actuel du projet 2025-10-25 00:07:16 +02:00
trochas
fbff98f1dd merge 2025-10-24 23:22:01 +02:00
trochas
1354457836 Merge remote-tracking branch 'refs/remotes/origin/tp_rest' into tp_rest 2025-10-24 23:17:04 +02:00
Vu Tuan Minh
6388783cff Merge remote-tracking branch 'origin/tp_rest' into tp_rest
# Conflicts:
#	src/main/java/fr/istic/taa/jaxrs/DAO/QuestionDAO.java
#	src/main/java/fr/istic/taa/jaxrs/DAO/UtilisateurDAO.java
2025-10-24 23:14:33 +02:00
trochas
74b13cc7f4 correction Question 2025-10-24 23:13:02 +02:00
Vu Tuan Minh
d55e48b7e4 change the transaction in DAO, in case it's in transaction and block all, add exception 2025-10-24 23:11:47 +02:00
trochas
50c9f5a61e gitignore 2025-10-24 19:44:52 +02:00
trochas
4b2604fe17 corrections 2025-10-24 19:39:02 +02:00
Vu Tuan Minh
0553fc13f7 Minor fix README.md 2025-10-13 00:22:03 +02:00
Vu Tuan Minh
9b6b8d6c80 Finished and tested 2025-10-13 00:17:51 +02:00
28 changed files with 809 additions and 284 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/target/
/data/

View File

@@ -1,11 +1,77 @@
# TP TAA # TP TAA
## TP2 Partie API REST
## TP1 - TP2
### Compte rendu ### Compte rendu
Dans ce TP REST, nous avons implémenté les éléments suivants:
- Mapper pour convertir les entités vers les DTO et inversement
- Lombok afin de simplifier le code et éviter le code boilerplate (getters, setters, constructeurs, etc.)
- API REST pour exposer les différentes ressources
- Swagger UI pour documenter et tester facilement toutes les méthodes de lAPI.
- DTO (Data Transfer Objects) afin déviter les problèmes de boucle infinie liés aux relations bidirectionnelles entre entités.
#### Utilisateur Resource
#### Execution du projet
Recharger les dépendances Maven :
`mvn clean install`
Lancer la base de données (Linux) : `./run-hsqldb-server.sh`
Lancer le serveur par fichier `src/main/java/fr.istic.taa.jaxrs/RestServer.java`
Après le lancement du serveur, on a testé des appels API avec Insomnia et l'interface Swagger est accessible via: http://localhost:8080/api
Seuls Utilisateur et Question sont fonctionnels, il reste quelques problèmes sur le reste.
#### Diagramme de classe
```mermaid
classDiagram
Utilisateur "*" -- "*" Session
Session "*" -- "*" Quizz
Quizz "1" -- "1..*" Question
Utilisateur "1" -- "*" Quizz
Question "1" -- "1" Reponse
Reponse <|-- ReponseCourte
Reponse <|-- Choix
class Utilisateur {
-id : int
-name : String
-session : List&lt;Session&gt;
-email : String
-password : String
-quizzs : String
}
class Session{
-id : int
-codePIN : int
-quizzs : List&lt;Quizz&gt;
-utilisateurs : List&lt;Utilisateur&gt;
-theme : String
}
class Quizz{
-session: Session
-id : int
-createur: Utilisateur
}
class Reponse{
-id : int
-question: Question
-reponses : ArrayList&lt;String&gt;
}
class Choix{
-choix : ArrayList&lt;String&gt;
}
class ReponseCourte{
}
class Question{
-id : int
-enonce : String
-reponse: Reponse
}
```
##### Utilisateur Resource
| Methode | URL | Description | | Methode | URL | Description |
|---------|---------------------------------------------------|-------------------------------------------------------| |---------|---------------------------------------------------|-------------------------------------------------------|
| GET | `/utilisateur` | Retourne toute la liste de l'utilisateur | | GET | `/utilisateur` | Retourne toute la liste de l'utilisateur |
@@ -16,7 +82,7 @@
| PUT | `/utilisateur/{user_id}/add_session/{session_id}` | Ajoute un nouveau session à la liste de l'utilisateur | | PUT | `/utilisateur/{user_id}/add_session/{session_id}` | Ajoute un nouveau session à la liste de l'utilisateur |
| DELETE | `/utilisteur/{user_id}/delete` | Supprime l'utilisateur | | DELETE | `/utilisteur/{user_id}/delete` | Supprime l'utilisateur |
#### Session Resource ##### Session Resource
| Methode | URL | Description | | Methode | URL | Description |
|---------|--------------------------------------|------------------------------------| |---------|--------------------------------------|------------------------------------|
| GET | `/session` | Retourne toute la liste du session | | GET | `/session` | Retourne toute la liste du session |
@@ -25,29 +91,28 @@
| GET | `/session/{session_id}/utilisateurs` | Retourne la liste de l'utilisateur | | GET | `/session/{session_id}/utilisateurs` | Retourne la liste de l'utilisateur |
| DELETE | `/session/{session_id}/delete` | Supprime la session | | DELETE | `/session/{session_id}/delete` | Supprime la session |
#### Quizz Resource ##### Quizz Resource
| Methode | URL | Description | | Methode | URL | Description |
|---------|------------------------------------------------|----------------------------------------| |---------|------------------------------------------------|-----------------------------------------|
| GET | `/quizz` | Retourne toute la liste du quizz | | GET | `/quizz` | Retourne toute la liste du quizz |
| GET | `/quizz/{quizz_id}/questions` | Retourne toutes questions du quizz |
| GET | `/quizz/{quizz_id}/add_question/{question_id}` | Ajoute une nouvuelle question au quizz | | GET | `/quizz/{quizz_id}/add_question/{question_id}` | Ajoute une nouvuelle question au quizz |
| DELETE | `/quizz/{quizz_id}/delete` | Suprrime le quizz | | DELETE | `/quizz/{quizz_id}/delete` | Suprrime le quizz |
| PUT | `/quizz/{quizz_id}/deleteQ` | Supprime toute les questions de quizz | | PUT | `/quizz/{quizz_id}/deleteQ` | Supprime toute les questions de quizz |
#### Question Resource ##### Question Resource
| Methode | URL | Description | | Methode | URL | Description |
|----------|----------------------------------------------------|-----------------------------------------------------------------------| |----------|----------------------------------------------------|-----------------------------------------------------------------------|
| GET | `/question` | Retourne toute la liste du question | | GET | `/question` | Retourne toute la liste du question |
| POST | `/question/addQuestion` | Créer une question | | POST | `/question/addQuestion` | Créer une question |
| PUT | `/question/{question_id}/changeQuestion` | Change l'énoncé de la question | | PUT | `/question/{question_id}/changeQuestion` | Change l'énoncé de la question |
| GET | `/question/{question_id}/getReponse` | retourne l'objet Reponse | | GET | `/question/{question_id}/getReponse` | retourne l'objet Reponse |
| PUT | `/question/{question_id}/addReponse` | Ajoute une réponse à Reponse |
| DELETE | `/question/{question_id}/deletReponses` | supprime toute les réponse correct | | DELETE | `/question/{question_id}/deletReponses` | supprime toute les réponse correct |
| PUT | `/question/{question_id}/addReponse` | Ajoute une réponse à Reponse | | PUT | `/question/{question_id}/addReponse` | Ajoute une réponse à Reponse |
| PUT | `/question/{question_id}/setReponse/choix` | créer un nouvel objet Reponse de type Choix pour la question | | PUT | `/question/{question_id}/setReponse/choix` | créer un nouvel objet Reponse de type Choix pour la question |
| PUT | `/question/{question_id}/setReponse/reponseCourte` | créer un nouvel objet Reponse de type reponse courte pour la question | | PUT | `/question/{question_id}/setReponse/reponseCourte` | créer un nouvel objet Reponse de type reponse courte pour la question |
| PUT | `/question/{question_id}/addChoix` | rajoute un choix si Reponse est de type Choix | | PUT | `/question/{question_id}/addChoix` | rajoute un choix si Reponse est de type Choix |
## Auteurs ## Auteurs
- Tuan Minh VU - Tuan Minh VU

View File

@@ -45,6 +45,11 @@
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
<version>8.1.0</version> <version>8.1.0</version>
</dependency> </dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency>
<!-- ==== REST API ==== --> <!-- ==== REST API ==== -->
<!--https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-undertow --> <!--https://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-undertow -->
<dependency> <dependency>

View File

@@ -6,12 +6,19 @@ import jakarta.persistence.Persistence;
public class EntityManagerHelper { public class EntityManagerHelper {
private static final EntityManagerFactory emf; private static EntityManagerFactory emf;
private static final ThreadLocal<EntityManager> threadLocal; private static final ThreadLocal<EntityManager> threadLocal;
static { static {
try {
emf = Persistence.createEntityManagerFactory("dev"); emf = Persistence.createEntityManagerFactory("dev");
} catch (Exception e) {
emf = null;
e.printStackTrace();
}
threadLocal = new ThreadLocal<EntityManager>(); threadLocal = new ThreadLocal<EntityManager>();
} }
public static EntityManager getEntityManager() { public static EntityManager getEntityManager() {

View File

@@ -17,38 +17,53 @@ public class QuestionDAO extends AbstractJpaDao<Integer, Question> {
this.setClass(Question.class); this.setClass(Question.class);
} }
public void addReponse(String reponse, int questionId) { public void addReponse(String reponse, int questionId) {
EntityTransaction t = em.getTransaction(); EntityTransaction t = em.getTransaction();
t.begin(); try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, questionId); Question q = em.find(Question.class, questionId);
if (q != null && q.getReponse() != null) {
q.getReponse().getReponses().add(reponse); q.getReponse().getReponses().add(reponse);
em.merge(q); em.merge(q);
t.commit();
} }
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
}
public void deleteReponse(int questionId) { public void deleteReponse(int questionId) {
EntityTransaction t = em.getTransaction(); EntityTransaction t = em.getTransaction();
t.begin(); try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, questionId); Question q = em.find(Question.class, questionId);
if (q != null && q.getReponse() != null) {
q.getReponse().setReponses(new ArrayList<>()); q.getReponse().setReponses(new ArrayList<>());
em.merge(q); em.merge(q);
t.commit();
} }
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
}
public void setReponse(Reponse rep, Integer id) { public void setReponse(Reponse rep, Integer id) {
EntityTransaction t = em.getTransaction(); EntityTransaction t = em.getTransaction();
t.begin(); try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, id); Question q = em.find(Question.class, id);
if (q != null) {
q.setReponse(rep); q.setReponse(rep);
em.merge(q); em.merge(q);
t.commit();
} }
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
}
public void setChoix(Integer id) { public void setChoix(Integer id) {
setReponse(new Choix(), id); setReponse(new Choix(), id);
@@ -58,25 +73,36 @@ public class QuestionDAO extends AbstractJpaDao<Integer, Question> {
setReponse(new ReponseCourte(), id); setReponse(new ReponseCourte(), id);
} }
public void addChoix(Integer id, String choix) { public void addChoix(Integer id, String choix) {
EntityTransaction t = em.getTransaction(); EntityTransaction t = em.getTransaction();
t.begin(); try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, id); Question q = em.find(Question.class, id);
if (q != null && q.getReponse() instanceof Choix) {
((Choix) q.getReponse()).getChoix().add(choix); ((Choix) q.getReponse()).getChoix().add(choix);
em.merge(q); em.merge(q);
}
t.commit(); t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
} }
public void changeEnonce(String newEnonce, Integer id) {
public void changeQuestion(String newQuestion, Integer id) {
EntityTransaction t = em.getTransaction(); EntityTransaction t = em.getTransaction();
t.begin(); try {
if (!t.isActive()) t.begin();
Question q = em.find(Question.class, id); Question q = em.find(Question.class, id);
q.setQuestion(newQuestion); if (q != null) {
q.setEnonce(newEnonce);
em.merge(q); em.merge(q);
}
t.commit(); t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
}
} }
} }

View File

@@ -10,23 +10,39 @@ public class QuizzDAO extends AbstractJpaDao<Integer, Quizz> {
this.setClass(Quizz.class); this.setClass(Quizz.class);
} }
public void deleteAllQustion(int quizz_id){ public void deleteAllQuestion(int quizzId) {
EntityTransaction et= em.getTransaction(); EntityTransaction t = em.getTransaction();
et.begin(); try {
Quizz quizz = em.find(Quizz.class, quizz_id); if (!t.isActive()) t.begin();
Quizz quizz = em.find(Quizz.class, quizzId);
if (quizz != null) {
quizz.getQuestions().clear(); quizz.getQuestions().clear();
em.merge(quizz); em.merge(quizz);
et.commit(); }
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
} }
public void addQuestion(int quizz_id, int question_id){ public void addQuestion(int quizzId, int questionId) {
EntityTransaction et= em.getTransaction(); EntityTransaction t = em.getTransaction();
et.begin(); try {
Quizz quizz = em.find(Quizz.class, quizz_id); if (!t.isActive()) t.begin();
Question question =em.find(Question.class, question_id); Quizz quizz = em.find(Quizz.class, quizzId);
Question question = em.find(Question.class, questionId);
if (quizz != null && question != null) {
quizz.getQuestions().add(question); quizz.getQuestions().add(question);
em.merge(quizz); em.merge(quizz);
et.commit(); }
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
} }
} }

View File

@@ -8,12 +8,4 @@ public class ReponseDAO extends AbstractJpaDao<Integer, Reponse> {
this.setClass(Reponse.class); this.setClass(Reponse.class);
} }
/*public List<String> getGoodResponses(){
EntityTransaction t=em.getTransaction();
t.begin();
Query query=em.createQuery("select r from Reponse r where r.reponses");
List<String> lString=query.getResultList();
t.commit();
return lString;
}*/
} }

View File

@@ -15,13 +15,19 @@ public class SessionDAO extends AbstractJpaDao<Integer, Session> {
public List<Session> findByTheme(String theme) { public List<Session> findByTheme(String theme) {
EntityTransaction t = em.getTransaction(); EntityTransaction t = em.getTransaction();
Query query=em.createQuery("select s from Session s where s.theme=:theme"); try {
if (!t.isActive()) {
t.begin();
}
Query query = em.createQuery("SELECT s FROM Session s WHERE s.theme = :theme", Session.class);
query.setParameter("theme", theme); query.setParameter("theme", theme);
List<Session> sessions = query.getResultList(); List<Session> sessions = query.getResultList();
if(sessions.size()>0){ t.commit();
return sessions; return sessions;
}else{ } catch (Exception e) {
return null; if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
} }
} }
} }

View File

@@ -13,28 +13,49 @@ public class UtilisateurDAO extends AbstractJpaDao<Integer, Utilisateur> {
} }
public Utilisateur findByEmail(String email) { public Utilisateur findByEmail(String email) {
List<Utilisateur> results = List<Utilisateur> results = em.createQuery(
em.createQuery("SELECT u FROM Utilisateur u WHERE u.email = :email", Utilisateur.class) "SELECT u FROM Utilisateur u WHERE u.email = :email", Utilisateur.class)
.setParameter("email", email).getResultList(); .setParameter("email", email)
.getResultList();
if (results.isEmpty()) { return results.isEmpty() ? null : results.get(0);
return null;
} else {
return results.get(0);
}
} }
public void addToSession(int sessionId, int userId) { public void addToSession(int userId, int sessionId) {
EntityTransaction t = em.getTransaction(); EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) {
t.begin(); t.begin();
}
Session s = em.find(Session.class, sessionId); Session s = em.find(Session.class, sessionId);
Utilisateur u = em.find(Utilisateur.class, userId); Utilisateur u = em.find(Utilisateur.class, userId);
if (s == null || u == null) {
//FAUT AJOUTER OWNING SIDE ( Ici u --> s) throw new IllegalArgumentException("User or session not found");
u.getSession().add(s); }
//Jsp il faut birectionnelle ou pas? if (!u.getSessions().contains(s)) {
//s.getUtilisateurs().add(u); u.getSessions().add(s);
em.merge(u); em.merge(u);
}
t.commit(); t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
}
@Override
public void create(Utilisateur entity) {
EntityTransaction t = em.getTransaction();
try {
if (!t.isActive()) {
t.begin();
}
em.merge(entity);
t.commit();
} catch (Exception e) {
if (t.isActive()) t.rollback();
e.printStackTrace();
throw e;
}
} }
} }

View File

@@ -9,7 +9,5 @@ import java.util.List;
@XmlRootElement @XmlRootElement
public class QuestionDTO { public class QuestionDTO {
private int id; private int id;
private String question; private String enonce;
private List<String> reponses_string;
} }

View File

@@ -8,7 +8,7 @@ import java.util.List;
@XmlRootElement @XmlRootElement
public class QuizzDTO { public class QuizzDTO {
private int id; private int id;
private Integer sessionId; private List<Integer> sessionsId;
private Integer utilisateurId; private Integer utilisateurId;
private List<Integer> questionsId; private List<Integer> questionsId;
} }

View File

@@ -0,0 +1,11 @@
package fr.istic.taa.jaxrs.DTO;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Data;
import java.util.List;
@Data
@XmlRootElement
public class ReponseDTO {
public List<String> reponses;
}

View File

@@ -7,7 +7,6 @@ import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Mapper @Mapper
@@ -15,7 +14,6 @@ public interface QuestionMapper {
QuestionMapper INSTANCE = Mappers.getMapper( QuestionMapper.class ); QuestionMapper INSTANCE = Mappers.getMapper( QuestionMapper.class );
@Mapping(target = "reponses_string", expression = "java(question_ReponseString(question.getReponse()))")
QuestionDTO toDTO(Question question); QuestionDTO toDTO(Question question);
Question toEntity(QuestionDTO questionDTO); Question toEntity(QuestionDTO questionDTO);

View File

@@ -2,6 +2,7 @@ package fr.istic.taa.jaxrs.Mapper;
import fr.istic.taa.jaxrs.DTO.QuizzDTO; import fr.istic.taa.jaxrs.DTO.QuizzDTO;
import fr.istic.taa.jaxrs.metier.Question; import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Session;
import fr.istic.taa.jaxrs.metier.Quizz; import fr.istic.taa.jaxrs.metier.Quizz;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
@@ -16,8 +17,8 @@ public interface QuizzMapper {
//https://www.baeldung.com/mapstruct-map-source-object-target-list //https://www.baeldung.com/mapstruct-map-source-object-target-list
//https://mapstruct.org/ //https://mapstruct.org/
@Mapping(target="sessionId", source="session.id") @Mapping(target="sessionsId", expression="java(function_mapS(quizz.getSessions()))")
@Mapping(target="utilisateurId", source = "utilisateur.id") @Mapping(target="utilisateurId", source = "createur.id")
@Mapping(target="questionsId",expression="java(function_mapQ(quizz.getQuestions()))") @Mapping(target="questionsId",expression="java(function_mapQ(quizz.getQuestions()))")
QuizzDTO toDTO(Quizz quizz); QuizzDTO toDTO(Quizz quizz);
Quizz toEntity(QuizzDTO quizzDTO); Quizz toEntity(QuizzDTO quizzDTO);
@@ -31,4 +32,12 @@ public interface QuizzMapper {
} }
return list; return list;
} }
default List<Integer> function_mapS(List<Session> sessionList){
List<Integer> list=new ArrayList<Integer>();
for(Session session : sessionList){
list.add(session.getId());
}
return list;
}
} }

View File

@@ -34,7 +34,6 @@ public class TestApplication extends Application {
final Set<Class<?>> clazzes = new HashSet<Class<?>>(); final Set<Class<?>> clazzes = new HashSet<Class<?>>();
clazzes.add(OpenApiResource.class); clazzes.add(OpenApiResource.class);
clazzes.add(PetResource.class);
clazzes.add(QuestionResource.class); clazzes.add(QuestionResource.class);
clazzes.add(QuizzResource.class); clazzes.add(QuizzResource.class);
clazzes.add(UtilisateurResource.class); clazzes.add(UtilisateurResource.class);

View File

@@ -1,44 +0,0 @@
package fr.istic.taa.jaxrs.domain;
import java.util.ArrayList;
import java.util.List;
import io.swagger.v3.oas.models.tags.Tag;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Pet")
public class Pet {
private long id;
private String name;
private List<Tag> tags = new ArrayList<Tag>();
@XmlElement(name = "id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlElementWrapper(name = "tags")
@XmlElement(name = "tag")
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
}

View File

@@ -1,6 +1,7 @@
package fr.istic.taa.jaxrs.metier; package fr.istic.taa.jaxrs.metier;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -11,11 +12,12 @@ import java.io.Serializable;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@XmlRootElement
public class Question implements Serializable { public class Question implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; private int id;
private String question; private String enonce;
@OneToOne(cascade = CascadeType.ALL) @OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name ="bonne_reponse", referencedColumnName = "id") @JoinColumn(name ="bonne_reponse", referencedColumnName = "id")

View File

@@ -1,6 +1,7 @@
package fr.istic.taa.jaxrs.metier; package fr.istic.taa.jaxrs.metier;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -13,17 +14,18 @@ import java.util.List;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@XmlRootElement
public class Quizz implements Serializable { public class Quizz implements Serializable {
@Id @Id
@GeneratedValue @GeneratedValue
private int id; private int id;
@ManyToOne @ManyToMany
private Session session; private List<Session> sessions;
@ManyToOne @ManyToOne
@JoinColumn(name="id_utilisateur") @JoinColumn(name="id_utilisateur")
private Utilisateur utilisateur; private Utilisateur createur;
@OneToMany(mappedBy = "quizz") @OneToMany(mappedBy = "quizz")
private List<Question> questions=new ArrayList<Question>(); private List<Question> questions=new ArrayList<Question>();

View File

@@ -1,6 +1,7 @@
package fr.istic.taa.jaxrs.metier; package fr.istic.taa.jaxrs.metier;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import jakarta.persistence.*; import jakarta.persistence.*;
@@ -22,7 +23,7 @@ public abstract class Reponse implements Serializable {
@OneToOne @OneToOne
private Question question; private Question question;
public List<String> reponses; public List<String> reponses = new ArrayList<String>();
public String valHTML(){ public String valHTML(){
return ""; return "";

View File

@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -13,6 +14,7 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@XmlRootElement
public class Session implements Serializable { public class Session implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -21,10 +23,10 @@ public class Session implements Serializable {
@Column(unique=true) @Column(unique=true)
private int codePIN; private int codePIN;
@OneToMany(mappedBy="session") @ManyToMany(mappedBy="sessions", fetch = FetchType.EAGER)
private List<Quizz> quizzs = new ArrayList<>(); private List<Quizz> quizzs = new ArrayList<>();
@ManyToMany(mappedBy = "session") @ManyToMany(mappedBy = "sessions", fetch = FetchType.EAGER)
private List<Utilisateur> utilisateurs = new ArrayList<>(); private List<Utilisateur> utilisateurs = new ArrayList<>();
private String theme; private String theme;
} }

View File

@@ -1,6 +1,7 @@
package fr.istic.taa.jaxrs.metier; package fr.istic.taa.jaxrs.metier;
import jakarta.persistence.*; import jakarta.persistence.*;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.*; import lombok.*;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -10,6 +11,7 @@ import java.util.List;
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@XmlRootElement
public class Utilisateur implements Serializable { public class Utilisateur implements Serializable {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -26,8 +28,8 @@ public class Utilisateur implements Serializable {
joinColumns = @JoinColumn(name="utilisateur_id"), joinColumns = @JoinColumn(name="utilisateur_id"),
inverseJoinColumns = @JoinColumn(name = "session_id") inverseJoinColumns = @JoinColumn(name = "session_id")
) )
private List<Session> session= new ArrayList<>();; private List<Session> sessions= new ArrayList<Session>();
@OneToMany(mappedBy = "utilisateur") @OneToMany(mappedBy = "createur")
private List<Quizz> quizzs; private List<Quizz> quizzs = new ArrayList<Quizz>();;
} }

View File

@@ -1,38 +0,0 @@
package fr.istic.taa.jaxrs.rest;
import fr.istic.taa.jaxrs.domain.Pet;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
@Path("pet")
@Produces({"application/json", "application/xml"})
public class PetResource {
@GET
@Path("/{petId}")
public Pet getPetById(@PathParam("petId") Long petId) {
// return pet
return new Pet();
}
@GET
@Path("/")
public Pet getPet(Long petId) {
return new Pet();
}
@POST
@Consumes("application/json")
public Response addPet(
@Parameter(description = "Pet object that needs to be added to the store", required = true) Pet pet) {
// add pet
return Response.ok().entity("SUCCESS").build();
}
}

View File

@@ -9,12 +9,13 @@ import fr.istic.taa.jaxrs.metier.Choix;
import fr.istic.taa.jaxrs.metier.Question; import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Reponse; import fr.istic.taa.jaxrs.metier.Reponse;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.ws.rs.Consumes; import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.PATCH;
import jakarta.ws.rs.PUT; import jakarta.ws.rs.PUT;
import jakarta.ws.rs.POST; import jakarta.ws.rs.POST;
import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DELETE;
@@ -32,34 +33,70 @@ public class QuestionResource {
private final QuestionMapper mapper = QuestionMapper.INSTANCE; private final QuestionMapper mapper = QuestionMapper.INSTANCE;
@GET @GET
public List<Question> listQuestion(){ @Operation(summary = "List all questions",
tags = {"Questions"},
description = "List all questions.",
responses = {
@ApiResponse(description = "List of all questions", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = Question.class))))
}
)
public List<QuestionDTO> listQuestion() {
List<Question> questions = questionDAO.findAll(); List<Question> questions = questionDAO.findAll();
return questions; return mapper.toDTOs(questions);
} }
@POST @POST
@Path("/addQuestion") @Path("/addQuestion")
public Response addQuestion(QuestionDTO dto){ @Operation(summary = "Create a new question",
tags = {"Questions"},
description = "Create a new question",
responses = {@ApiResponse(responseCode = "201", description = "Question added.")}
)
public Response addQuestion(
@Parameter(description = "The question details to be added", required = true) QuestionDTO dto) {
Question question = mapper.toEntity(dto); Question question = mapper.toEntity(dto);
questionDAO.create(question); questionDAO.create(question);
return Response.status(Response.Status.CREATED).entity("Question ajouté avec Succès : \"" + dto.getQuestion() + "\"").build(); return Response.status(Response.Status.CREATED).entity("Question ajouté avec Succès : \"" + dto.getEnonce() + "\"").build();
} }
@PUT @PUT
@Path("/{question_id}/changeQuestion/") @Path("/{question_id}/changeQuestion/")
public Response changeQuestion(@PathParam("question_id") Integer id, String newQuestion){ @Operation(summary = "Update the text of a question",
tags = {"Questions"},
description = "Update the text of a question.",
responses = {
@ApiResponse(responseCode = "201", description = "Question answer updated."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response changeQuestion(
@Parameter(description = "ID of the question to modify", required = true) @PathParam("question_id") Integer id,
@Parameter(description = "New answer for the question", required = true) String newQuestion) {
Question question = questionDAO.findById(id); Question question = questionDAO.findById(id);
if (question == null) { if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
} }
questionDAO.changeQuestion(newQuestion,id); questionDAO.changeEnonce(newQuestion, id);
return Response.status(Response.Status.CREATED).entity("Question mis à jour : " + newQuestion).build(); return Response.status(Response.Status.CREATED).entity("Enonce de la question mis à jour : " + newQuestion).build();
} }
@GET @GET
@Path("/{question_id}/getReponse/") @Path("/{question_id}/getReponse/")
public Response getReponse(@PathParam("question_id") Integer id){ @Operation(summary = "Get the correct answer for question",
tags = {"Questions"},
description = "Get the correct answer for question by ID of question.",
responses = {
@ApiResponse(description = "The correct answer", content = @Content(
schema = @Schema(implementation = Reponse.class))),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response getReponse(
@Parameter(description = "ID of the question", required = true)
@PathParam("question_id") Integer id) {
Question question = questionDAO.findById(id); Question question = questionDAO.findById(id);
if (question == null) { if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -71,7 +108,18 @@ public class QuestionResource {
@PUT @PUT
@Path("/{question_id}/addReponse/") @Path("/{question_id}/addReponse/")
public Response addReponse(@PathParam("question_id") Integer id, String reponse){ @Operation(summary = "Add/Update the correct answer for question",
tags = {"Questions"},
description = "Add/Update the correct answer for question",
responses = {
@ApiResponse(responseCode = "201", description = "Answer text updated."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response addReponse(
@Parameter(description = "ID of the question", required = true) @PathParam("question_id") Integer id,
@Parameter(description = "The correct answer", required = true) String reponse) {
Question question = questionDAO.findById(id); Question question = questionDAO.findById(id);
if (question == null) { if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -83,7 +131,17 @@ public class QuestionResource {
@DELETE @DELETE
@Path("/{question_id}/deletReponses/") @Path("/{question_id}/deletReponses/")
public Response addReponse(@PathParam("question_id") Integer id){ @Operation(summary = "Removes the correct response.",
tags = {"Questions"},
description = "Removes the correct response.",
responses = {
@ApiResponse(responseCode = "201", description = "Response deleted."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response deleteReponses(
@Parameter(description = "ID of the question", required = true)
@PathParam("question_id") Integer id) {
Question question = questionDAO.findById(id); Question question = questionDAO.findById(id);
if (question == null) { if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -95,7 +153,17 @@ public class QuestionResource {
@PUT @PUT
@Path("/{question_id}/setReponse/choix") @Path("/{question_id}/setReponse/choix")
public Response setChoix(@PathParam("question_id") Integer id){ @Operation(summary = "Set question type to multiple choice",
tags = {"Questions"},
description = "Set question type to multiple choice type. It could override old answers",
responses = {
@ApiResponse(responseCode = "201", description = "Question type set to multiple choice."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response setChoix(
@Parameter(description = "ID of the question", required = true)
@PathParam("question_id") Integer id) {
Question question = questionDAO.findById(id); Question question = questionDAO.findById(id);
if (question == null) { if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -106,7 +174,17 @@ public class QuestionResource {
@PUT @PUT
@Path("/{question_id}/setReponse/reponseCourte") @Path("/{question_id}/setReponse/reponseCourte")
public Response setReponseCourte(@PathParam("question_id") Integer id){ @Operation(summary = "Set question type to short answer",
tags = {"Questions"},
description = "Set question type to multiple short answer. It could override old answers",
responses = {
@ApiResponse(responseCode = "201", description = "Question type set to short answer."),
@ApiResponse(responseCode = "404", description = "Question not found")
}
)
public Response setReponseCourte(
@Parameter(description = "ID of the question", required = true)
@PathParam("question_id") Integer id) {
Question question = questionDAO.findById(id); Question question = questionDAO.findById(id);
if (question == null) { if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -118,7 +196,18 @@ public class QuestionResource {
@PUT @PUT
@Path("/{question_id}/AddChoix") @Path("/{question_id}/AddChoix")
public Response addChoix(@PathParam("question_id") Integer id, String choix){ @Operation(summary = "Add a choice option to a multiple-choice question",
tags = {"Questions"},
description = "Adds a new choice option to the question (Type Multiple Choice obligatoire)",
responses = {
@ApiResponse(responseCode = "201", description = "Choice added."),
@ApiResponse(responseCode = "404", description = "Question not found"),
@ApiResponse(responseCode = "400", description = "Wrong type")
}
)
public Response addChoix(
@Parameter(description = "ID of the question", required = true) @PathParam("question_id") Integer id,
@Parameter(description = "The choice", required = true) String choix){
Question question = questionDAO.findById(id); Question question = questionDAO.findById(id);
if (question == null) { if (question == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();

View File

@@ -1,5 +1,7 @@
package fr.istic.taa.jaxrs.rest; package fr.istic.taa.jaxrs.rest;
import java.util.List;
import fr.istic.taa.jaxrs.DAO.QuestionDAO; import fr.istic.taa.jaxrs.DAO.QuestionDAO;
import fr.istic.taa.jaxrs.DAO.QuizzDAO; import fr.istic.taa.jaxrs.DAO.QuizzDAO;
import fr.istic.taa.jaxrs.DTO.QuestionDTO; import fr.istic.taa.jaxrs.DTO.QuestionDTO;
@@ -8,11 +10,22 @@ import fr.istic.taa.jaxrs.Mapper.QuestionMapper;
import fr.istic.taa.jaxrs.Mapper.QuizzMapper; import fr.istic.taa.jaxrs.Mapper.QuizzMapper;
import fr.istic.taa.jaxrs.metier.Question; import fr.istic.taa.jaxrs.metier.Question;
import fr.istic.taa.jaxrs.metier.Quizz; import fr.istic.taa.jaxrs.metier.Quizz;
import jakarta.ws.rs.*; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import java.util.List;
@Path("quizz") @Path("quizz")
@Consumes({"application/json", "application/xml"}) @Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"}) @Produces({"application/json", "application/xml"})
@@ -21,9 +34,51 @@ public class QuizzResource {
public final QuizzDAO quizzDAO = new QuizzDAO(); public final QuizzDAO quizzDAO = new QuizzDAO();
public final QuestionDAO questionDAO = new QuestionDAO(); public final QuestionDAO questionDAO = new QuestionDAO();
@POST
@Path("/addQuizz")
@Operation(summary = "Create a new quizz",
tags = {"Quizz"},
description = "Create a new quizz",
responses = {@ApiResponse(responseCode = "201", description = "Quizz added.")}
)
public Response addQuizz(
@Parameter(description = "The quizz details to be added", required = true) QuizzDTO dto) {
Quizz quizz = mapper.toEntity(dto);
quizzDAO.create(quizz);
return Response.status(Response.Status.CREATED).entity("Quizz ajouté avec Succès : \"" + dto.getId() + "\"").build();
}
@GET
@Operation(summary = "List all quizz",
tags = {"Quizz"},
description = "List all quizz.",
responses = {
@ApiResponse(description = "List of all quizz", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = Question.class))))
}
)
public List<QuizzDTO> listQuizz() {
List<Quizz> quizz = quizzDAO.findAll();
return mapper.toDTOs(quizz);
}
@GET @GET
@Path("/{quizz_id}") @Path("/{quizz_id}")
public Response getQuizzById(@PathParam("quizz_id") Integer quizzId) { @Operation(summary = "Get a quizz by ID",
tags = {"Quizzes"},
description = "Get a quizz by ID",
responses = {
@ApiResponse(description = "The quizz by ID", content = @Content(
schema = @Schema(implementation = QuizzDTO.class))),
@ApiResponse(responseCode = "404", description = "Quizz not found")
}
)
public Response getQuizzById(
@Parameter(description = "ID of the quizz to fetch", required = true)
@PathParam("quizz_id") Integer quizzId) {
Quizz quizz = quizzDAO.findById(quizzId); Quizz quizz = quizzDAO.findById(quizzId);
if (quizz == null) { if (quizz == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -34,7 +89,18 @@ public class QuizzResource {
@GET @GET
@Path("/{quizz_id}/questions") @Path("/{quizz_id}/questions")
public Response getQuestions(@PathParam("quizz_id") Integer quizzId) { @Operation(summary = "List all questions for a quizz",
tags = {"Quizzes"},
description = "List all questions by quizz ID.",
responses = {
@ApiResponse(description = "List of questions", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = QuestionDTO.class)))),
@ApiResponse(responseCode = "404", description = "Quizz not found")
}
)
public Response getQuestions(
@Parameter(description = "ID of the quizz", required = true)
@PathParam("quizz_id") Integer quizzId) {
Quizz quizz = quizzDAO.findById(quizzId); Quizz quizz = quizzDAO.findById(quizzId);
if (quizz == null) { if (quizz == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -47,7 +113,18 @@ public class QuizzResource {
@PUT @PUT
@Path("/{quizz_id}/add_question/{question_id}") @Path("/{quizz_id}/add_question/{question_id}")
public Response addQuestion(@PathParam("quizz_id") Integer quizzId, @PathParam("question_id") Integer questionId) { @Operation(summary = "Add a question to a quizz",
tags = {"Quizzes"},
description = "Add question to quizz by quizz ID and question ID.",
responses = {
@ApiResponse(responseCode = "200", description = "Question added successfully",
content = @Content(schema = @Schema(implementation = QuizzDTO.class))),
@ApiResponse(responseCode = "404", description = "Quizz or Question not found")
}
)
public Response addQuestion(
@Parameter(description = "ID of the quizz to update", required = true) @PathParam("quizz_id") Integer quizzId,
@Parameter(description = "ID of the question to add", required = true) @PathParam("question_id") Integer questionId) {
Quizz quizz = quizzDAO.findById(quizzId); Quizz quizz = quizzDAO.findById(quizzId);
Question question = questionDAO.findById(questionId); Question question = questionDAO.findById(questionId);
if (quizz == null || question == null) { if (quizz == null || question == null) {
@@ -61,13 +138,43 @@ public class QuizzResource {
@PUT @PUT
@Path("/{quizz_id}/deleteQ") @Path("/{quizz_id}/deleteQ")
public Response deleteQuestion(@PathParam("quizz_id") Integer quizzId) { @Operation(summary = "Remove all questions from a quizz",
tags = {"Quizzes"},
description = "Removes all questions by ID of quizz.",
responses = {
@ApiResponse(responseCode = "200", description = "Removed all questions"),
@ApiResponse(responseCode = "404", description = "Quizz not found")}
)
public Response deleteQuestion(
@Parameter(description = "ID of the quizz", required = true)
@PathParam("quizz_id") Integer quizzId) {
Quizz quizz = quizzDAO.findById(quizzId); Quizz quizz = quizzDAO.findById(quizzId);
if (quizz == null) { if (quizz == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
} }
quizzDAO.deleteAllQustion(quizzId); quizzDAO.deleteAllQuestion(quizzId);
quizzDAO.update(quizz); quizzDAO.update(quizz);
return Response.status(Response.Status.OK).build(); return Response.status(Response.Status.OK).build();
} }
@DELETE
@Path("/{quizz_id}/delete")
@Operation(summary = "Delete a Quizz",
tags = {"Quizzes"},
description = "Deletes a Quizz by ID.",
responses = {
@ApiResponse(responseCode = "200", description = "Quizz deleted."),
@ApiResponse(responseCode = "404", description = "Quizz not found.")
}
)
public Response deleteQuizz(
@Parameter(description = "ID of the Quizz to delete", required = true)
@PathParam("quizz_id") Integer quizzId) {
Quizz quizz = quizzDAO.findById(quizzId);
if (quizz == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
quizzDAO.delete(quizz);
return Response.status(Response.Status.OK).build();
}
} }

View File

@@ -1,6 +1,8 @@
package fr.istic.taa.jaxrs.rest; package fr.istic.taa.jaxrs.rest;
import java.util.List;
import fr.istic.taa.jaxrs.DAO.SessionDAO; import fr.istic.taa.jaxrs.DAO.SessionDAO;
import fr.istic.taa.jaxrs.DTO.QuizzDTO; import fr.istic.taa.jaxrs.DTO.QuizzDTO;
import fr.istic.taa.jaxrs.DTO.SessionDTO; import fr.istic.taa.jaxrs.DTO.SessionDTO;
@@ -8,12 +10,24 @@ import fr.istic.taa.jaxrs.DTO.UtilisateurDTO;
import fr.istic.taa.jaxrs.Mapper.QuizzMapper; import fr.istic.taa.jaxrs.Mapper.QuizzMapper;
import fr.istic.taa.jaxrs.Mapper.SessionMapper; import fr.istic.taa.jaxrs.Mapper.SessionMapper;
import fr.istic.taa.jaxrs.Mapper.UtilisateurMapper; import fr.istic.taa.jaxrs.Mapper.UtilisateurMapper;
import fr.istic.taa.jaxrs.metier.Quizz;
import fr.istic.taa.jaxrs.metier.Session; import fr.istic.taa.jaxrs.metier.Session;
import fr.istic.taa.jaxrs.metier.Utilisateur; import fr.istic.taa.jaxrs.metier.Utilisateur;
import jakarta.ws.rs.*; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import java.util.List;
@Path("session") @Path("session")
@Consumes({"application/json", "application/xml"}) @Consumes({"application/json", "application/xml"})
@@ -22,15 +36,49 @@ public class SessionResource {
private final SessionDAO sessionDAO = new SessionDAO(); private final SessionDAO sessionDAO = new SessionDAO();
private final SessionMapper mapper = SessionMapper.INSTANCE; private final SessionMapper mapper = SessionMapper.INSTANCE;
@POST
@Path("/addSession")
@Operation(summary = "Create a new session",
tags = {"Session"},
description = "Create a new session",
responses = {@ApiResponse(responseCode = "201", description = "Session added.")}
)
public Response addQuizz(
@Parameter(description = "The session details to be added", required = true) SessionDTO dto) {
Session session = mapper.toEntity(dto);
sessionDAO.create(session);
return Response.status(Response.Status.CREATED).entity("Session ajouté avec Succès : \"" + dto.getTheme() + "\"").build();
}
@GET @GET
public List<Session> listSession() { @Operation(summary = "List all session", tags = {"Sessions"},
description = "Get a list of all sessions in BDD",
responses = {@ApiResponse(description = "List of sessions", content = @Content(
schema = @Schema(implementation = Session.class)
))
}
)
public List<SessionDTO> listSession() {
List<Session> sessions = sessionDAO.findAll(); List<Session> sessions = sessionDAO.findAll();
return sessions; return mapper.toDTOs(sessions);
} }
@GET @GET
@Path("/{id}") @Path("/{id}")
public Response getSession(@PathParam("id") Integer id) { @Operation(summary = "Get session by ID",
tags = {"Sessions"},
description = "Get session by ID.",
responses = {
@ApiResponse(description = "Session", content = @Content(
schema = @Schema(implementation = SessionDTO.class)
)),
@ApiResponse(responseCode = "404", description = "Session not found")
}
)
public Response getSession(
@Parameter(description = "ID of the session to fetch", required = true)
@PathParam("id") Integer id) {
Session session = sessionDAO.findById(id); Session session = sessionDAO.findById(id);
if (session == null) { if (session == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -41,7 +89,19 @@ public class SessionResource {
@GET @GET
@Path("/{session_id}/quizzs") @Path("/{session_id}/quizzs")
public Response getQuizzs(@PathParam("session_id") Integer sessionId) { @Operation(summary = "Get all quizzes for a session",
tags = {"Sessions"},
description = "Get all quizzes for a session by ID of session.",
responses = {
@ApiResponse(description = "List of quizzes", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = QuizzDTO.class))
)),
@ApiResponse(responseCode = "404", description = "Session not found")
}
)
public Response getQuizzs(
@Parameter(description = "ID of the session to get quizzes", required = true)
@PathParam("session_id") Integer sessionId) {
Session session = sessionDAO.findById(sessionId); Session session = sessionDAO.findById(sessionId);
if (session == null) { if (session == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -52,7 +112,20 @@ public class SessionResource {
@GET @GET
@Path("/{session_id}/utilisateurs") @Path("/{session_id}/utilisateurs")
public Response getUtilisateurs(@PathParam("session_id") Integer sessionId) { @Operation(summary = "Get all users for a session",
tags = {"Sessions"},
description = "Get all users for a session by ID of session.",
responses = {
@ApiResponse(description = "List of users", content = @Content(
array = @ArraySchema(schema = @Schema(implementation = UtilisateurDTO.class))
)),
@ApiResponse(responseCode = "404", description = "Session not found")
}
)
public Response getUtilisateurs(
@Parameter(description = "ID of the session to get users", required = true)
@PathParam("session_id") Integer sessionId) {
Session session = sessionDAO.findById(sessionId); Session session = sessionDAO.findById(sessionId);
if (session == null) { if (session == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
@@ -64,12 +137,22 @@ public class SessionResource {
@DELETE @DELETE
@Path("/{session_id}/delete") @Path("/{session_id}/delete")
public Response deleteSession(@PathParam("session_id") Integer sessionId) { @Operation(summary = "Delete a session",
tags = {"Sessions"},
description = "Deletes a session by ID of session.",
responses = {
@ApiResponse(responseCode = "200", description = "Session deleted"),
@ApiResponse(responseCode = "404", description = "Session not found")
}
)
public Response deleteSession(
@Parameter(description = "ID of the session to delete", required = true)
@PathParam("session_id") Integer sessionId) {
Session session = sessionDAO.findById(sessionId); Session session = sessionDAO.findById(sessionId);
if (session == null) { if (session == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
} }
sessionDAO.delete(session); sessionDAO.delete(session);
return Response.status(Response.Status.OK).entity("Réussi de supprimer").build(); return Response.status(Response.Status.OK).entity("Session deleted").build();
} }
} }

View File

@@ -1,6 +1,7 @@
package fr.istic.taa.jaxrs.rest; package fr.istic.taa.jaxrs.rest;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -8,28 +9,37 @@ import java.util.logging.Logger;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam; import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.Response;
@Path("/api") @Path("/api")
public class SwaggerResource { public class SwaggerResource {
private static final Logger logger = Logger.getLogger(SwaggerResource.class.getName()); private static final Logger logger = Logger.getLogger(SwaggerResource.class.getName());
private static final String SWAGGER_BASE_PATH = "swagger/";
@GET @GET
public byte[] Get1() { public Response Get1() {
try { return getFileContent("index.html");
return Files.readAllBytes(FileSystems.getDefault().getPath("src/main/webapp/swagger/index.html"));
} catch (IOException e) {
return null;
}
} }
@GET @GET
@Path("{path:.*}") @Path("{path:.*}")
public byte[] Get(@PathParam("path") String path) { public Response Get(@PathParam("path") String path) {
try { return getFileContent(path);
return Files.readAllBytes(FileSystems.getDefault().getPath("src/main/webapp/swagger/"+path));
} catch (IOException e) {
return null;
}
} }
private Response getFileContent(String fileName) {
String fullPath = SWAGGER_BASE_PATH + fileName;
try (InputStream is = getClass().getClassLoader().getResourceAsStream(fullPath)) {
if (is == null) {
logger.warning("File not found: " + fullPath);
return Response.status(Response.Status.NOT_FOUND).build(); // HTTP 404
}
return Response.ok(is.readAllBytes()).build();
} catch (IOException e) {
logger.severe("Error reading file " + fullPath + ": " + e.getMessage());
return Response.serverError().build(); // HTTP 500
}
}
} }

View File

@@ -27,14 +27,31 @@ public class UtilisateurResource {
private final UtilisateurMapper mapper = UtilisateurMapper.INSTANCE; private final UtilisateurMapper mapper = UtilisateurMapper.INSTANCE;
@GET @GET
public List<Utilisateur> listUtilisateur() { @Operation(summary = "List all users", tags = {"Utilisateurs"},
description = "Get a list of all users in BDD",
responses = {@ApiResponse(description = "List of users", content = @Content(
schema = @Schema(implementation = Utilisateur.class)
))
}
)
public List<UtilisateurDTO> listUtilisateur() {
List<Utilisateur> utilisateurs = utilisateurDAO.findAll(); List<Utilisateur> utilisateurs = utilisateurDAO.findAll();
return utilisateurs; return mapper.toDTOs(utilisateurs);
} }
//https://stackoverflow.com/questions/9269040/which-http-response-code-for-this-email-is-already-registered
@POST @POST
@Path("/register") @Path("/register")
public Response registerUtilisateur(UtilisateurDTO dto) { @Operation(summary = "Register a new user",
tags = {"Utilisateurs"},
description = "Registers a new user.",
responses = {
@ApiResponse(responseCode = "201", description = "Registration succès"),
@ApiResponse(responseCode = "409", description = "Email est déjà registré")
}
)
public Response registerUtilisateur(
@Parameter(description = "User details for registration", required = true) UtilisateurDTO dto) {
String email_verification = dto.getEmail(); String email_verification = dto.getEmail();
Utilisateur existing = utilisateurDAO.findByEmail(email_verification); Utilisateur existing = utilisateurDAO.findByEmail(email_verification);
@@ -51,7 +68,19 @@ public class UtilisateurResource {
@POST @POST
@Path("/login") @Path("/login")
public Response loginUtilisateur(UtilisateurDTO dto) { @Operation(summary = "Log in a user",
tags = {"Utilisateurs"},
description = "Authenticates a user and returns the user's details upon success.",
responses = {
@ApiResponse(responseCode = "200", description = "Successful login", content = @Content(
schema = @Schema(implementation = UtilisateurDTO.class)
)),
@ApiResponse(responseCode = "404", description = "Email n'existe pas"),
@ApiResponse(responseCode = "401", description = "Mauvais mdp")
}
)
public Response loginUtilisateur(
@Parameter(description = "User credentials (email and password)", required = true) UtilisateurDTO dto) {
Utilisateur utilisateur = utilisateurDAO.findByEmail(dto.getEmail()); Utilisateur utilisateur = utilisateurDAO.findByEmail(dto.getEmail());
if (utilisateur == null) { if (utilisateur == null) {
@@ -67,7 +96,7 @@ public class UtilisateurResource {
@GET @GET
@Path("/{id}") @Path("/{id}")
@Operation(summary = "Get user by ID", @Operation(summary = "Get user by ID",
tags = {"utilisateur"}, tags = {"Utilisateurs"},
description = "Get User by ID", description = "Get User by ID",
responses = { responses = {
@ApiResponse(description = "Utilisateur", content = @Content( @ApiResponse(description = "Utilisateur", content = @Content(
@@ -95,7 +124,20 @@ public class UtilisateurResource {
@PUT @PUT
@Path("/{user_id}/add_session/{session_id}") @Path("/{user_id}/add_session/{session_id}")
public Response addSession(@PathParam("user_id") Integer user_id, @PathParam("session_id") Integer session_id) { @Operation(summary = "Add a session to a user",
tags = {"Utilisateurs"},
description = "Add a session to a user existed in BDD",
responses = {
@ApiResponse(responseCode = "200", description = "Session added successfully", content = @Content(
schema = @Schema(implementation = UtilisateurDTO.class) // Returns updated user DTO
)),
@ApiResponse(responseCode = "404", description = "User or Session not found"),
@ApiResponse(responseCode = "409", description = "User is already in the session")
}
)
public Response addSession(
@Parameter(description = "ID of the user") @PathParam("user_id") Integer user_id,
@Parameter(description = "ID of the session to add") @PathParam("session_id") Integer session_id) {
SessionDAO sessionDAO = new SessionDAO(); SessionDAO sessionDAO = new SessionDAO();
Session existingSession = sessionDAO.findById(session_id); Session existingSession = sessionDAO.findById(session_id);
@@ -105,7 +147,7 @@ public class UtilisateurResource {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
} }
//If user already joined //If user already joined
if (utilisateur.getSession().contains(existingSession)) { if (utilisateur.getSessions().contains(existingSession)) {
return Response.status(Response.Status.CONFLICT).build(); return Response.status(Response.Status.CONFLICT).build();
} }
utilisateurDAO.addToSession(user_id, session_id); utilisateurDAO.addToSession(user_id, session_id);
@@ -119,19 +161,39 @@ public class UtilisateurResource {
@GET @GET
@Path("{user_id}/session") @Path("{user_id}/session")
public Response listSession(@PathParam("user_id") Integer user_id) { @Operation(summary = "List of all sessions of a user",
tags = {"Utilisateurs"},
description = "Return a response of all sessions of a user",
responses = {
@ApiResponse(responseCode = "200", description = "List of user's sessions", content = @Content(
schema = @Schema(implementation = SessionDTO.class)
)),
@ApiResponse(responseCode = "404", description = "User not found")
}
)
public Response listSession(
@Parameter(description = "ID of the user") @PathParam("user_id") Integer user_id) {
Utilisateur utilisateur = utilisateurDAO.findById(user_id); Utilisateur utilisateur = utilisateurDAO.findById(user_id);
if (utilisateur == null) { if (utilisateur == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();
} }
List<Session> sess = utilisateur.getSession(); List<Session> sess = utilisateur.getSessions();
List<SessionDTO> dtos = SessionMapper.INSTANCE.toDTOs(sess); List<SessionDTO> dtos = SessionMapper.INSTANCE.toDTOs(sess);
return Response.status(Response.Status.OK).entity(dtos).build(); return Response.status(Response.Status.OK).entity(dtos).build();
} }
@DELETE @DELETE
@Path("{user_id}/delete") @Path("{user_id}/delete")
public Response deleteUtilisateur(@PathParam("user_id") Integer user_id) { @Operation(summary = "Delete a user",
tags = {"Utilisateurs"},
description = "Delete a user with ID",
responses = {
@ApiResponse(responseCode = "200", description = "User deleted"),
@ApiResponse(responseCode = "404", description = "User not found")
}
)
public Response deleteUtilisateur(
@Parameter(description = "ID of the user to delete") @PathParam("user_id") Integer user_id) {
Utilisateur existing = utilisateurDAO.findById(user_id); Utilisateur existing = utilisateurDAO.findById(user_id);
if (existing == null) { if (existing == null) {
return Response.status(Response.Status.NOT_FOUND).build(); return Response.status(Response.Status.NOT_FOUND).build();

View File

@@ -0,0 +1,92 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css"
href="https://unpkg.com/swagger-ui-dist/swagger-ui.css">
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
style="position:absolute;width:0;height:0">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="locked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="close">
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function () {
// Build a system
const ui = SwaggerUIBundle({
url: "http://localhost:8080/openapi.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
window.ui = ui
}
</script>
</body>
</html>