refacto - restructure code

This commit is contained in:
Kevin Mitressé
2024-06-14 17:05:30 +02:00
parent 4fa4cf2d1f
commit 2a4a594b14
162 changed files with 2 additions and 2 deletions
+13
View File
@@ -0,0 +1,13 @@
package uppa.project;
public final class Global {
public static final String APP_NAME = "Cards Rush";
public static final String PERSISTENCE_UNIT_NAME = "prod";
public static final String MAIL_USERNAME = "cardsrushuppa@gmail.com";
public static final String MAIL_PASSWORD = "aktr zity mayw kvek";
public static final String MAIL_PORT = "587";
public static final String MAIL_HOST = "smtp.gmail.com";
}
@@ -0,0 +1,145 @@
/*
* ForgottenPasswordBeen.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.bean;
import java.io.Serial;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Properties;
import java.util.UUID;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import uppa.project.Global;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.RecoveryPasswordToken;
import uppa.project.database.pojo.User;
import uppa.project.web.translation.Translator;
import static uppa.project.web.servlet.ForgottenPasswordServlet.CreateToken;
public class ForgottenPasswordBean implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String email;
private Translator translator;
public ForgottenPasswordBean() {
}
/**
* Validation des paramètres de la requête & gestion de la création du token de réinitialisation de mot de passe
*
* @param requestPath le chemin de la requête
* @return true si l'adresse e-mail est valide, false sinon
*/
public boolean validate(String requestPath) {
Game_JPA_DAO_Factory factory = new Game_JPA_DAO_Factory();
try {
DAO<User> userDao = factory.getDAOUser();
User[] user = userDao.findByField("email", email);
for (User u : user) {
if (u.getEmail().equals(email)) {
sendTokenEmail(u, requestPath);
return true;
}
}
} catch (DAOException e) {
throw new RuntimeException(e);
}
return false;
}
/**
*
* @param email l'adresse e-mail supposée de l'utilisateur ayant oublié son mot de passe.
* @return this
*/
public ForgottenPasswordBean setEmail(String email) {
this.email = email;
return this;
}
/**
*
* @param translator le traducteur
* @return this
*/
public ForgottenPasswordBean setTranslator(Translator translator) {
this.translator = translator;
return this;
}
/**
* Création et envoi d'un token de réinitialisation de mot de passe
*
* @param user l'utilisateur ayant oublié son mot de passe
* @param requestPath le chemin de la requête
*/
private void sendTokenEmail(User user, String requestPath) {
String token = UUID.randomUUID().toString();
RecoveryPasswordToken recoveryPasswordToken = new RecoveryPasswordToken(token, user);
CreateToken(recoveryPasswordToken);
sendRecoveryEmail(user.getEmail(), token, requestPath);
}
/**
* Envoi d'un e-mail de réinitialisation de mot de passe
*
* @param email l'adresse e-mail du destinataire
* @param token le token de réinitialisation
*/
public void sendRecoveryEmail(String email, String token, String requestPath){
String host = Global.MAIL_HOST;
String port = Global.MAIL_PORT;
String username = Global.MAIL_USERNAME;
String password = Global.MAIL_PASSWORD;
Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", host);
props.put("mail.smtp.port", port);
Session session = Session.getInstance(props, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
try {
// Création du message
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(username));
message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(email));
message.setSubject(this.translator.translate("forgotten_email_object"));
String contentTemplate = this.translator.translate("forgotten_email_content");
String content = MessageFormat.format(contentTemplate, requestPath, token);
message.setText(content);
// Envoi du message
Transport.send(message);
} catch (MessagingException e) {
throw new RuntimeException("Erreur lors de l'envoi de l'e-mail", e);
}
}
}
@@ -0,0 +1,104 @@
/*
* LoginBean.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.bean;
import java.io.Serial;
import java.io.Serializable;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.User;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
public class LoginBean implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String username;
private String password;
private User user;
private HttpResponse error;
private Translator translator;
public LoginBean() {
}
/**
* Validation des paramètres de la requête
*
* @return true si le nom d'utilisateur et le mot de passe sont valides, false sinon
*/
public boolean validate() {
Game_JPA_DAO_Factory factory = new Game_JPA_DAO_Factory();
try {
DAO<User> userDao = factory.getDAOUser();
User[] user = userDao.findByField("username", username);
for (User u : user) {
if (u.getUsername().equals(username) && u.verifyPassword(password)) {
this.user = u;
return true;
}
}
} catch (DAOException e) {
error = new HttpResponse(HttpResponseCode.INTERNAL_SERVER_ERROR,translator.translate("internal_error_1"));
return false;
}
error = new HttpResponse(HttpResponseCode.NOT_FOUND, translator.translate("login_error"));
return false;
}
/**
*
* @param username le nom d'utilisateur supposé de l'utilisateur qui souhaite se connecter
* @return l'entité
*/
public LoginBean setUsername(String username) {
this.username = username;
return this;
}
/**
*
* @param password le mot de passe supposé de l'utilisateur qui souhaite se connecter
* @return l'entité
*/
public LoginBean setPassword(String password) {
this.password = password;
return this;
}
/**
*
* @param translator le traducteur
* @return l'entité
*/
public LoginBean setTranslator(Translator translator) {
this.translator = translator;
return this;
}
/**
*
* @return l'utilisateur connecté
*/
public User getUser() {
return user;
}
/**
*
* @return l'erreur
*/
public HttpResponse getError() {
return error;
}
}
@@ -0,0 +1,146 @@
/*
* NewGameBean.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.bean;
import jakarta.persistence.EntityManager;
import java.io.Serial;
import java.io.Serializable;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.Game;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
public class NewGameBean implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String difficulty;
private String nbRounds;
private String timer;
private String nbValues;
private String nbColors;
private Translator translator;
private Game game;
private HttpResponse error;
public NewGameBean() {
}
/**
* Validation des paramètres de la requête
*
* @return true si les paramètres sont valides, false sinon
*/
public boolean validate() {
EntityManager entityManager = EntityManagerProvider.getInstance();
try {
Game game = new Game(
Game.Difficulty.valueOf(difficulty),
Integer.parseInt(timer),
Integer.parseInt(nbRounds),
Integer.parseInt(nbColors),
Integer.parseInt(nbValues)
);
// Sauvegarder la game en base de données
DAO<Game> gameDAO = new Game_JPA_DAO_Factory().getDAOGame();
entityManager.getTransaction().begin();
this.game = gameDAO.create(game);
entityManager.getTransaction().commit();
return true;
} catch (NumberFormatException e) {
error = new HttpResponse(HttpResponseCode.BAD_REQUEST, translator.translate("newGame_invalid_param_values"));
} catch (DAOException e) {
entityManager.getTransaction().rollback();
error = new HttpResponse(HttpResponseCode.INTERNAL_SERVER_ERROR, translator.translate("newGame_error_creation"));
}
return false;
}
/**
*
* @param difficulty la difficulté de la partie
* @return l'entité
*/
public NewGameBean setDifficulty(String difficulty) {
this.difficulty = difficulty;
return this;
}
/**
*
* @param nbRounds le nombre de tours de la partie
* @return l'entité
*/
public NewGameBean setNbRounds(String nbRounds) {
this.nbRounds = nbRounds;
return this;
}
/**
*
* @param timer le temps de jeu de la partie
* @return l'entité
*/
public NewGameBean setTimer(String timer) {
this.timer = timer;
return this;
}
/**
*
* @param nbValues le nombre de valeurs de la partie
* @return l'entité
*/
public NewGameBean setNbValues(String nbValues) {
this.nbValues = nbValues;
return this;
}
/**
*
* @param nbColors le nombre de couleurs de la partie
* @return l'entité
*/
public NewGameBean setNbColors(String nbColors) {
this.nbColors = nbColors;
return this;
}
/**
*
* @param translator le traducteur
* @return l'entité
*/
public NewGameBean setTranslator(Translator translator) {
this.translator = translator;
return this;
}
/**
*
* @return la partie créée
*/
public Game getGame() {
return game;
}
/**
*
* @return l'erreur
*/
public HttpResponse getError() {
return error;
}
}
@@ -0,0 +1,48 @@
/*
* PlayerBean.java, 1/05/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.bean;
import jakarta.persistence.EntityManager;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.Player;
import uppa.project.web.translation.Translator;
public class PlayerBean {
private Player player;
public PlayerBean(Player player) {
this.player = player;
}
/**
* Gestion des joueurs de la parties
*
* @return true si tous les joueurs sont gérés, false sinon
*/
public boolean validate() {
EntityManager em = EntityManagerProvider.getInstance();
em.getTransaction().begin();
try {
Player dbPlayer = new Player(player.getGame(), player.getUser());
dbPlayer.setScore(player.getScore());
if (player.isWinner()) dbPlayer.setWinner();
dbPlayer.setClickCount(player.getClickCount());
dbPlayer.setRapidClickCount(player.getRapidClickCount());
dbPlayer.setRightClickCount(player.getRightClickCount());
player.getGame().addPlayer(dbPlayer);
player.getUser().addPlayedGame(dbPlayer);
em.getTransaction().commit();
return true;
} catch (Exception e) {
em.getTransaction().rollback();
return false;
}
}
}
@@ -0,0 +1,186 @@
/*
* ProfileBean.java, 01/05/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.bean;
import jakarta.persistence.EntityManager;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.User;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
public class ProfileBean {
private String username;
private String oldEmail;
private String email;
private String oldPassword;
private String newPassword;
private String confirmPassword;
private String gender;
private User user;
private HttpResponse error;
private Translator translator;
public ProfileBean() {}
/**
* Validation des paramètres de la requête & mise à jour des informations de l'utilisateur
*
* @return true si les paramètres sont valides, false sinon
*/
public boolean validate() {
EntityManager entityManager = EntityManagerProvider.getInstance();
entityManager.getTransaction().begin();
DAO<User> userDAO;
String errorMessage = "";
try {
userDAO= new Game_JPA_DAO_Factory().getDAOUser();
// Vérification de l'existence de l'utilisateur
user = (userDAO.findByField("username",username).length == 0 ? null : userDAO.findByField("username",username)[0]);
if (user == null) {
error = new HttpResponse(HttpResponseCode.UNAUTHORIZED, translator.translate("profile_error_username_unknown"));
entityManager.getTransaction().rollback();
return false;
}
// Vérification de l'unicité de l'adresse e-mail
User[] users = userDAO.findByField("email", email);
if (!oldEmail.equals(email) && users.length > 0) {
errorMessage += translator.translate("profile_error_email");
}
// Verification de l'ancien mot de passe
if(!oldPassword.isEmpty() && !user.verifyPassword(oldPassword)) {
errorMessage += "<br>" + translator.translate("profile_error_old_password");
}
if(!newPassword.equals(confirmPassword)) {
errorMessage += "<br>" + translator.translate("profile_error_password");
}
if (!errorMessage.isEmpty()) {
error = new HttpResponse(HttpResponseCode.UNAUTHORIZED, errorMessage);
entityManager.getTransaction().rollback();
return false;
}
} catch (DAOException e) {
error = new HttpResponse(HttpResponseCode.INTERNAL_SERVER_ERROR, translator.translate("internal_error_2"));
entityManager.getTransaction().rollback();
return false;
}
// Mise à jour des informations de l'utilisateur
user.setEmail(email);
if (!newPassword.isEmpty()) {
user.setPassword(newPassword);
}
user.setGender(User.Gender.valueOf(gender));
try {
userDAO.update(user);
entityManager.getTransaction().commit();
return true;
} catch (DAOException e) {
error = new HttpResponse(HttpResponseCode.INTERNAL_SERVER_ERROR, translator.translate("internal_error_2"));
entityManager.getTransaction().rollback();
return false;
}
}
/**
*
* @param username le pseudo de l'utilisateur
* @return l'entité
*/
public ProfileBean setUsername(String username) {
this.username = username;
return this;
}
/**
*
* @param email l'adresse e-mail actuelle de l'utilisateur
* @return l'entité
*/
public ProfileBean setOldEmail(String email) {
this.oldEmail = email;
return this;
}
/**
*
* @param email la nouvelle adresse e-mail de l'utilisateur
* @return l'entité
*/
public ProfileBean setEmail(String email) {
this.email = email;
return this;
}
/**
*
* @param oldPassword l'ancien mot de passe de l'utilisateur
* @return l'entité
*/
public ProfileBean setOldPassword(String oldPassword) {
this.oldPassword = oldPassword;
return this;
}
/**
*
* @param password le nouveau mot de passe de l'utilisateur
* @return l'entité
*/
public ProfileBean setNewPassword(String password) {
this.newPassword = password;
return this;
}
/**
*
* @param confirmPassword la confirmation du nouveau mot de passe de l'utilisateur
* @return l'entité
*/
public ProfileBean setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
return this;
}
/**
*
* @param gender le genre de l'utilisateur
* @return l'entité
*/
public ProfileBean setGender(String gender) {
this.gender = gender;
return this;
}
/**
*
* @param translator le traducteur
* @return l'entité
*/
public ProfileBean setTranslator(Translator translator) {
this.translator = translator;
return this;
}
/**
*
* @return l'erreur
*/
public HttpResponse getError() {
return error;
}
/**
*
* @return l'utilisateur
*/
public User getUser() {
return user;
}
}
@@ -0,0 +1,190 @@
package uppa.project.bean;
import jakarta.persistence.EntityManager;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.User;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
public class RegisterBean implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String username;
private String email;
private String password;
private String confirmPassword;
private String birth;
private String gender;
private HttpResponse error;
private Translator translator;
public RegisterBean() {
}
/**
* Validation des paramètres de la requête & création d'un nouvel utilisateur
*
* @return true si les paramètres sont valides, false sinon
*/
public boolean validate() {
Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory();
DAO<User> userDAO;
// Vérification de l'unicité du nom d'utilisateur et de l'adresse e-mail
try {
userDAO = jpaDaoFactory.getDAOUser();
String errorMessage = "";
// Vérification de l'unicité du nom d'utilisateur
User[] users = userDAO.findByField("username", username);
if (users.length > 0) {
errorMessage += translator.translate("register_error_username");
}
// Vérification de l'unicité de l'adresse e-mail
users = userDAO.findByField("email", email);
if (users.length > 0) {
errorMessage += "<br>" + translator.translate("register_error_email");
}
// Vérification de la correspondance des mots de passe
if (!password.equals(confirmPassword)) {
errorMessage += "<br>" + translator.translate("register_error_password");
}
if (!errorMessage.isEmpty()) {
error = new HttpResponse(HttpResponseCode.UNAUTHORIZED, errorMessage);
return false;
}
} catch (DAOException e) {
error = new HttpResponse(HttpResponseCode.INTERNAL_SERVER_ERROR, translator.translate("internal_error_1"));
return false;
}
// Creation de l'utilisateur
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setEmail(email);
try {
user.setGender(User.Gender.valueOf(gender));
} catch (IllegalArgumentException e) {
error = new HttpResponse(HttpResponseCode.UNAUTHORIZED, translator.translate("register_error_gender"));
return false;
}
// Convertion de la date de naissance de String au format YYYY-MM-DD en objet Date
try {
LocalDate localDate = LocalDate.parse(birth);
ZoneId defaultZoneId = ZoneId.systemDefault();
Date date = Date.from(localDate.atStartOfDay(defaultZoneId).toInstant());
user.setBirth(date);
} catch (Exception e) {
error = new HttpResponse(HttpResponseCode.UNAUTHORIZED, translator.translate("register_error_birthdate"));
return false;
}
// Sauvegarde de l'utilisateur en base de données
EntityManager entityManager = EntityManagerProvider.getInstance();
entityManager.getTransaction().begin();
try {
userDAO = jpaDaoFactory.getDAOUser();
userDAO.create(user);
entityManager.getTransaction().commit();
return true;
} catch (DAOException e) {
error = new HttpResponse(HttpResponseCode.INTERNAL_SERVER_ERROR, translator.translate("internal_error_2"));
entityManager.getTransaction().rollback();
}
return false;
}
/**
*
* @param username le nom d'utilisateur
* @return l'entité
*/
public RegisterBean setUsername(String username) {
this.username = username;
return this;
}
/**
*
* @param password le mot de passe
* @return l'entité
*/
public RegisterBean setPassword(String password) {
this.password = password;
return this;
}
/**
*
* @param confirmPassword la confirmation du mot de passe
* @return l'entité
*/
public RegisterBean setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
return this;
}
/**
*
* @param email l'adresse e-mail
* @return l'entité
*/
public RegisterBean setEmail(String email) {
this.email = email;
return this;
}
/**
*
* @param birth la date de naissance
* @return l'entité
*/
public RegisterBean setBirth(String birth) {
this.birth = birth;
return this;
}
/**
*
* @param gender le genre de l'utilisateur
* @return l'entité
*/
public RegisterBean setGender(String gender) {
this.gender = gender;
return this;
}
/**
*
* @param translator le traducteur
* @return l'entité
*/
public RegisterBean setTranslator(Translator translator) {
this.translator = translator;
return this;
}
/**
*
* @return l'erreur
*/
public HttpResponse getError() {
return error;
}
}
@@ -0,0 +1,126 @@
package uppa.project.bean;
import jakarta.persistence.EntityManager;
import java.io.Serial;
import java.io.Serializable;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.RecoveryPasswordToken;
import uppa.project.database.pojo.User;
import uppa.project.web.translation.Translator;
public class ResetPasswordBean implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private String token;
private String password;
private String confirmPassword;
private String errorMessage;
private Translator translator;
public ResetPasswordBean() {
}
/**
* Validation des paramètres de la requête & gestion de la réinitialisation du mot de passe
*
* @return true si le token est valide, false sinon
*/
public boolean validate() {
Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory();
DAO<User> userDAO;
DAO<RecoveryPasswordToken> recoveryPasswordTokenDAO;
// Vérification du lien entre le token et un utilisateur
EntityManager entityManager = EntityManagerProvider.getInstance();
entityManager.getTransaction().begin();
try {
userDAO = jpaDaoFactory.getDAOUser();
recoveryPasswordTokenDAO = jpaDaoFactory.getDAORecoveryPasswordToken();
// Vériier l'existence du token
RecoveryPasswordToken[] tokens = recoveryPasswordTokenDAO.findByField("token", token);
if (tokens.length == 0) {
errorMessage = "Ce token n'est pas valide";
entityManager.getTransaction().rollback();
return false;
}
RecoveryPasswordToken token = tokens[0];
// Verifier la correspondance des mots de passe
if (!password.equals(confirmPassword)) {
errorMessage = "Les mots de passe ne correspondent pas";
entityManager.getTransaction().rollback();
return false;
}
// Récupéreration de l'utilisateur associé au token
User user = token.getUser();
if (user == null) {
errorMessage = "Erreur: Aucun utilisateur associé à ce token";
return false;
}
user.setPassword(password);
userDAO.update(user);
entityManager.getTransaction().commit();
} catch (DAOException e) {
errorMessage = "Une erreur est survenue (DB_CONNECTION_ERROR)";
entityManager.getTransaction().rollback();
return false;
}
return true;
}
/**
*
* @param token le token de réinitialisation de mot de passe
* @return this
*/
public ResetPasswordBean setToken(String token) {
this.token = token;
return this;
}
/**
*
* @param password le nouveau mot de passe
* @return this
*/
public ResetPasswordBean setPassword(String password) {
this.password = password;
return this;
}
/**
*
* @param confirmPassword la confirmation du nouveau mot de passe
* @return this
*/
public ResetPasswordBean setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
return this;
}
/**
*
* @param translator le traducteur
* @return this
*/
public ResetPasswordBean setTranslator(Translator translator) {
this.translator = translator;
return this;
}
/**
*
* @return le message d'erreur
*/
public String getErrorMessage() {
return errorMessage;
}
}
@@ -0,0 +1,30 @@
/*
* AbstractDAOFactory.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
/**
* Factory renvoyant une factory de DAO en fonction du support de persistance choisi
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
public class AbstractDAOFactory {
/**
* Renvoie une factory de DAO en fonction du support de persistance choisi
*
* @param type le support de persistance
* @return la factory de DAO
* @see PersistenceKind
*/
public static GameDAOFactory getDAOFactory(PersistenceKind type) {
if (type.equals(PersistenceKind.JPA)) return new Game_JPA_DAO_Factory();
return null;
}
}
@@ -0,0 +1,97 @@
/*
* DAO.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.util.List;
import uppa.project.database.pojo.Player;
/**
* DAO abstrait et générique pour tout type de données
*
* @param <D> la classe paramétrant le DAO
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
public abstract class DAO<D> {
/**
* Constructeur par défaut
*
* @throws DAOException si une erreur survient lors de la création du DAO
*/
public DAO() throws DAOException {}
/**
* Retourne l'objet {@link D} en fonction de son identifiant
*
* @param id identifiant de l'objet
* @return l'instance de l'objet {@link D}
* @throws DAOException en cas de problème
* @see D
*/
public abstract D findById(int id) throws DAOException;
/**
* Retourne tous les objets {@link D} paramétrant le DAO
*
* @return un tableau d'objets {@link D}
* @throws DAOException en cas de problème
* @see D
*/
public abstract D[] findAll() throws DAOException;
/**
* Rend persistant un objet {@link D} qui n'avait pas encore de réprésentation sur le support de persistance
*
* @param data l'objet {@link D} à rendre persistant
* @throws DAOException en cas de problème
* @see D
*/
public abstract D create(D data) throws DAOException;
/**
* Met à jour le contenu correspondant à l'objet {@link D} sur le support persistant (l'objet
* avait déjà une représentation sur le support persistant)
*
* @param data l'objet {@link D} modifié dont le contenu est à mettre à jour
* @throws DAOException en cas de problème
* @see D
*/
public abstract D update(D data) throws DAOException;
/**
* Efface du support persistant le contenu équivalent à l'objet {@link D}
*
* @param data l'objet {@link D} à supprimer
* @throws DAOException en cas de problème
* @see D
*/
public abstract void delete(D data) throws DAOException;
/**
* Retourne les objets {@link D} paramétrant le DAO en fonction d'un champ et d'une valeur
*
* @param field le champ à rechercher
* @param value la valeur à rechercher
* @return un tableau d'objets {@link D}
* @throws DAOException en cas de problème
* @see D
*/
public abstract D[] findByField(String field, Object value) throws DAOException;
public Player[] findPlayerForPagination(int userId, int firstData) throws DAOException {
EntityManager entityManager = EntityManagerProvider.getInstance();
TypedQuery<Player> query = entityManager.createQuery("SELECT p FROM Player p WHERE p.user.id = (:user) ORDER BY p.id DESC", Player.class);
query.setParameter("user", userId);
query.setFirstResult(firstData);
query.setMaxResults(5);
List<Player> results = query.getResultList();
return results.toArray(new Player[0]);
}
}
@@ -0,0 +1,33 @@
/*
* DAOException.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao;
/**
* Exception spécifique aux problèmes d'accès aux données via un DAO
*
* @author Kevin Mitressé
* @author Lucàs Vabre
* @see DAO
*/
public class DAOException extends Exception {
/**
* Constructeur par défaut
*/
public DAOException() {
super();
}
/**
* Constructeur avec message
*
* @param message le message de l'exception
*/
public DAOException(String message) {
super(message);
}
}
@@ -0,0 +1,50 @@
/*
* EntityManagerProvider.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.Persistence;
import uppa.project.Global;
/**
* Fournisseur d'EntityManager
* Permet de récupérer une instance d'EntityManager
* pour les DAO
*
* @see jakarta.persistence.EntityManager
*/
public final class EntityManagerProvider {
private static String PERSISTENCE_UNIT_NAME = Global.PERSISTENCE_UNIT_NAME;
private static EntityManager instance;
private static EntityManagerFactory factory;
public static EntityManager getInstance() {
if (instance == null) {
instance = getFactory().createEntityManager();
instance.setFlushMode(FlushModeType.COMMIT);
}
return instance;
}
public static EntityManagerFactory getFactory() {
if (factory == null) {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
}
return factory;
}
public static void setPersitenceUnitName(String name) {
PERSISTENCE_UNIT_NAME = name;
}
public static void close() {
if (instance.isOpen()) instance.close();
if (factory.isOpen()) factory.close();
}
}
@@ -0,0 +1,55 @@
/*
* GameDAOFactory.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao;
import uppa.project.database.pojo.Game;
import uppa.project.database.pojo.Player;
import uppa.project.database.pojo.RecoveryPasswordToken;
import uppa.project.database.pojo.User;
/**
* Fabrique abstraite de DAO pour le schéma du jeu
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
public abstract class GameDAOFactory {
protected DAO<User> daoUser = null;
protected DAO<Game> daoGame = null;
protected DAO<Player> daoPlayer = null;
protected DAO<RecoveryPasswordToken> daoRecoveryPasswordToken = null;
/**
* @return le DAO pour la classe/table User
* @throws DAOException en cas de problème
* @see User
*/
public abstract DAO<User> getDAOUser() throws DAOException;
/**
* @return le DAO pour la classe/table Game
* @throws DAOException en cas de problème
* @see Game
*/
public abstract DAO<Game> getDAOGame() throws DAOException;
/**
* @return le DAO pour la classe/table Player
* @throws DAOException en cas de problème
* @see Player
*/
public abstract DAO<Player> getDAOPlayer() throws DAOException;
/**
* @return le DAO pour la classe/table RecoveryPasswordToken
* @throws DAOException en cas de problème
* @see RecoveryPasswordToken
*/
public abstract DAO<RecoveryPasswordToken> getDAORecoveryPasswordToken() throws DAOException;
}
@@ -0,0 +1,19 @@
/*
* PersistenceKind.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao;
/**
* Type de support de persistance pour les données
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*
* @see AbstractDAOFactory
*/
public enum PersistenceKind {
JPA
}
@@ -0,0 +1,78 @@
/**
* DAO_JPA_Game.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.math.BigDecimal;
import java.util.List;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.pojo.Game;
import uppa.project.database.dao.EntityManagerProvider;
/**
* DAO pour les parties de jeu
*
* @author Kevin Mitressé
* @author Lucàs Vabre
* @see Game
* @see DAO
*/
public class DAO_JPA_Game extends DAO<Game> {
/**
* Gestionnaire d'entités
*/
private final EntityManager entityManager;
/**
* Constructeur par défaut
*
* @throws DAOException si une erreur survient lors de la création du DAO
*/
public DAO_JPA_Game() throws DAOException {
this.entityManager = EntityManagerProvider.getInstance();
}
@Override
public Game findById(int id) throws DAOException {
return entityManager.find(Game.class, new BigDecimal(id));
}
@Override
public Game[] findByField(String field, Object value) throws DAOException {
String sqlQuery = String.format("SELECT u FROM Game u WHERE u.%s = (:val)", field);
TypedQuery<Game> query = entityManager.createQuery(sqlQuery, Game.class);
query.setParameter("val", value);
List<Game> results = query.getResultList();
return results.toArray(new Game[0]);
}
@Override
public Game[] findAll() throws DAOException {
TypedQuery<Game> query = entityManager.createQuery("SELECT g FROM Game g", Game.class);
List<Game> results = query.getResultList();
return results.toArray(new Game[0]);
}
@Override
public Game create(Game data) throws DAOException {
return update(data);
}
@Override
public Game update(Game data) throws DAOException {
return entityManager.merge(data);
}
@Override
public void delete(Game data) throws DAOException {
entityManager.remove(data);
}
}
@@ -0,0 +1,73 @@
/*
* DAO_JPA_Player.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.math.BigDecimal;
import java.util.List;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.pojo.Player;
/**
* DAO pour les joueurs
*
* @author Kévin Mitresse
* @author Lucàs Vabre
* @see Player
* @see DAO
*/
public class DAO_JPA_Player extends DAO<Player> {
/**
* Gestionnaire d'entités
*/
private final EntityManager entityManager;
public DAO_JPA_Player() throws DAOException {
this.entityManager = EntityManagerProvider.getInstance();
}
@Override
public Player findById(int id) throws DAOException {
return entityManager.find(Player.class, new BigDecimal(id));
}
@Override
public Player[] findByField(String field, Object value) throws DAOException {
String sqlQuery = String.format("SELECT p FROM Player p WHERE p.%s = (:val)", field);
TypedQuery<Player> query = entityManager.createQuery(sqlQuery, Player.class);
query.setParameter("val", value);
List<Player> results = query.getResultList();
return results.toArray(new Player[0]);
}
@Override
public Player[] findAll() throws DAOException {
TypedQuery<Player> query = entityManager.createQuery("SELECT p FROM Player p", Player.class);
List<Player> results = query.getResultList();
return results.toArray(new Player[0]);
}
@Override
public Player create(Player data) throws DAOException {
return update(data);
}
@Override
public Player update(Player data) throws DAOException {
return entityManager.merge(data);
}
@Override
public void delete(Player data) throws DAOException {
entityManager.remove(data);
}
}
@@ -0,0 +1,72 @@
/*
* DAO_JPA_RecoveryPasswordToken.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.math.BigDecimal;
import java.util.List;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.pojo.RecoveryPasswordToken;
/**
* DAO pour les tokens de récupération de mot de passe
*
* @author Kévin Mitresse
* @author Lucàs Vabre
* @see RecoveryPasswordToken
* @see DAO
*/
public class DAO_JPA_RecoveryPasswordToken extends DAO<RecoveryPasswordToken> {
/**
* Gestionnaire d'entités
*/
private final EntityManager entityManager;
public DAO_JPA_RecoveryPasswordToken() throws DAOException {
this.entityManager = EntityManagerProvider.getInstance();
}
@Override
public RecoveryPasswordToken findById(int id) throws DAOException {
return entityManager.find(RecoveryPasswordToken.class, new BigDecimal(id));
}
public RecoveryPasswordToken[] findByField(String field, Object value) throws DAOException {
String sqlQuery = String.format("SELECT r FROM RecoveryPasswordToken r WHERE r.%s = (:val)", field);
TypedQuery<RecoveryPasswordToken> query = entityManager.createQuery(sqlQuery, RecoveryPasswordToken.class);
query.setParameter("val", value);
List<RecoveryPasswordToken> results = query.getResultList();
return results.toArray(new RecoveryPasswordToken[0]);
}
@Override
public RecoveryPasswordToken[] findAll() throws DAOException {
TypedQuery<RecoveryPasswordToken> query = entityManager.createQuery("SELECT r FROM RecoveryPasswordToken r", RecoveryPasswordToken.class);
List<RecoveryPasswordToken> results = query.getResultList();
return results.toArray(new RecoveryPasswordToken[0]);
}
@Override
public RecoveryPasswordToken create(RecoveryPasswordToken data) throws DAOException {
return update(data);
}
@Override
public RecoveryPasswordToken update(RecoveryPasswordToken data) throws DAOException {
return entityManager.merge(data);
}
@Override
public void delete(RecoveryPasswordToken data) throws DAOException {
entityManager.remove(data);
}
}
@@ -0,0 +1,72 @@
/*
* DAO_JPA_User.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao.jpa;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.math.BigDecimal;
import java.util.List;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.pojo.User;
import uppa.project.database.dao.EntityManagerProvider;
/**
* DAO pour les utilisateurs
*
* @author Kévin Mitresse
* @author Lucàs Vabre
* @see User
* @see DAO
*/
public class DAO_JPA_User extends DAO<User> {
/**
* Gestionnaire d'entités
*/
private final EntityManager entityManager;
public DAO_JPA_User() throws DAOException {
this.entityManager = EntityManagerProvider.getInstance();
}
@Override
public User findById(int id) throws DAOException {
return entityManager.find(User.class, new BigDecimal(id));
}
public User[] findByField(String field, Object value) throws DAOException {
String sqlQuery = String.format("SELECT u FROM User u WHERE u.%s = (:val)", field);
TypedQuery<User> query = entityManager.createQuery(sqlQuery, User.class);
query.setParameter("val", value);
List<User> results = query.getResultList();
return results.toArray(new User[0]);
}
@Override
public User[] findAll() throws DAOException {
TypedQuery<User> query = entityManager.createQuery("SELECT u FROM User u", User.class);
List<User> results = query.getResultList();
return results.toArray(new User[0]);
}
@Override
public User create(User data) throws DAOException {
return update(data);
}
@Override
public User update(User data) throws DAOException {
return entityManager.merge(data);
}
@Override
public void delete(User data) throws DAOException {
entityManager.remove(data);
}
}
@@ -0,0 +1,48 @@
/*
* Sports_JDBC_DAOFactory.java, 09/02/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.dao.jpa;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.GameDAOFactory;
import uppa.project.database.pojo.Game;
import uppa.project.database.pojo.Player;
import uppa.project.database.pojo.RecoveryPasswordToken;
import uppa.project.database.pojo.User;
import uppa.project.database.dao.DAOException;
/**
* Fabrique concrète de DAO pour le schéma relationnel sports avec une implémentation en JDBC.
*
* @author Kevin Mitressé
* @author Lucàs Vabre
* @see GameDAOFactory
*/
public class Game_JPA_DAO_Factory extends GameDAOFactory {
@Override
public DAO<User> getDAOUser() throws DAOException {
if (daoUser == null) daoUser = new DAO_JPA_User();
return daoUser;
}
@Override
public DAO<Game> getDAOGame() throws DAOException {
if (daoGame == null) daoGame = new DAO_JPA_Game();
return daoGame;
}
@Override
public DAO<Player> getDAOPlayer() throws DAOException {
if (daoPlayer == null) daoPlayer = new DAO_JPA_Player();
return daoPlayer;
}
@Override
public DAO<RecoveryPasswordToken> getDAORecoveryPasswordToken() throws DAOException {
if (daoRecoveryPasswordToken == null) daoRecoveryPasswordToken= new DAO_JPA_RecoveryPasswordToken();
return daoRecoveryPasswordToken;
}
}
@@ -0,0 +1,84 @@
/*
* Card.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.pojo;
import jakarta.persistence.Transient;
/**
* Représentation d'une carte
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
public class Card {
/**
* Couleurs disponibles pour les cartes
*/
public enum Color{HEART, CLUBS, SPADES, DIAMONDS}
/**
* Valeurs disponibles pour les cartes
*/
public enum Value{ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING}
/**
* Couleur de la carte
*/
private final Color color;
/**
* Valeur de la carte
*/
private final Value value;
/**
* Constructeur par défaut
*
* @param color couleur de la carte
* @param value valeur de la carte
*
* @see Color
* @see Value
*/
public Card(Color color, Value value) {
if (color == null || value == null) {
throw new IllegalArgumentException("Color cannot be null");
}
this.color = color;
this.value = value;
}
/**
* @return la couleur de la carte
*/
public Color getColor() {
return color;
}
/**
* @return la valeur de la carte
*/
public Value getValue() {
return value;
}
@Override
public String toString() {
return "Card{" +
"color=" + color +
", value=" + value +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Card card)) return false;
return getColor() == card.getColor() && getValue() == card.getValue();
}
}
@@ -0,0 +1,103 @@
/*
* Deck.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.pojo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Représentation d'un paquet de cartes
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
public class Deck {
public static final int NB_COLORS_MIN = 2;
public static final int NB_COLORS_MAX = Card.Color.values().length;
public static final int NB_VALUES_PER_COLOR_MIN = 2;
public static final int NB_VALUES_PER_COLOR_MAX = Card.Value.values().length;
/**
* Ensemble de cartes du paquet
* @see Card
*/
private final List<Card> cards;
/**
* Constructeur par défaut
*
* @param nbColors nombre de couleurs (doit être compris entre 1 et le nombre de couleurs de {@link Card.Color})
* @param nbValues nombre de valeurs (doit être compris entre 1 et le nombre de valeurs de {@link Card.Value})
* @see Card.Color
* @see Card.Value
*/
public Deck(int nbColors, int nbValues) {
if (!Deck.isDeckValid(nbColors, nbValues)) {
throw new IllegalArgumentException("Nombre de couleurs et/ou nombre de valeurs invalide(s)");
}
this.cards = new ArrayList<>(nbColors * nbValues);
for (int nbCard = 0; nbCard < nbColors * nbValues; nbCard++) {
int color = nbCard % nbColors;
int value = nbCard / nbColors;
cards.add(new Card(Card.Color.values()[color], Card.Value.values()[value]));
}
}
/**
* Prédicat qui vérifie si un Deck est correctement initialisé
*
* @param nbColors Nombre de couleurs {@link Card.Color}
* @param nbValues Nombre de valeurs {@link Card.Value}
* @return true si le prédicat est vérifié, false sinon
*/
public static boolean isDeckValid(int nbColors, int nbValues) {
return NB_COLORS_MIN <= nbColors && nbColors <= NB_COLORS_MAX
&& NB_VALUES_PER_COLOR_MIN <= nbValues && nbValues <= NB_VALUES_PER_COLOR_MAX;
}
/**
* @return l'ensemble de cartes du paquet
*/
public List<Card> getCards() {
return cards;
}
/**
* Mélange les cartes d'un paquet
*/
public void shuffle() {
Collections.shuffle(this.cards);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Deck deck = (Deck) o;
boolean sameSize = cards.size() == deck.cards.size();
int counter = 0;
for (int i = 0; i < cards.size(); i++) {
for (int j = 0; j < deck.cards.size(); j++) {
if (cards.get(i).getColor() == deck.cards.get(j).getColor()
&& cards.get(i).getValue() == deck.cards.get(j).getValue()) {
counter++;
break;
}
}
}
return sameSize && counter == cards.size();
}
}
@@ -0,0 +1,372 @@
/*
* Game.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.pojo;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.persistence.Transient;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* Représentation d'une partie de jeu
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
@Entity
@Table(name = "game")
public class Game implements Serializable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private BigDecimal id;
@Transient
private int currentRound = 0;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_at")
private Date createdAt;
@Column(name = "difficulty")
@Enumerated(EnumType.STRING)
private Difficulty difficulty;
@Column(name = "nb_rounds")
private int nbRounds;
@Column(name = "nb_colors")
private int nbColors;
@Column(name = "nb_values_per_color")
private int nbValuesPerColor;
@OneToMany(mappedBy = "game", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Player> players;
@Transient
private Deck deck;
@Column(name = "timer")
private int timer;
@Transient
public static final int TIMER_MIN = 5;
@Transient
public static final int TIMER_MAX = 60;
@Transient
public static final int NB_ROUNDS_MIN = 3;
@Transient
private GameState gameState = GameState.WAITING;
/**
* Constructeur par défaut
*/
public Game() {
this.createdAt = new Date();
this.players = new ArrayList<>();
this.timer = 0;
}
/**
* Constructeur avec la difficulté
*
* @param difficulty la difficulté de la partie
* @see Difficulty
* @param timer le timer de chaque round en seconde
* @param nbRounds le nombre de tours de la partie
* @param nbColors le nombre de couleurs présente dans le deck
* @param nbValuesPerColor le nombre de valeurs par couleur
*/
public Game(Difficulty difficulty, int timer, int nbRounds, int nbColors, int nbValuesPerColor) {
if (isValidNumberRound(nbRounds, nbColors, nbValuesPerColor)){
throw new IllegalArgumentException("Le nombre de tours doit être compris entre 2 et " + nbColors * nbValuesPerColor);
}
if (timer < TIMER_MIN || timer > TIMER_MAX){
throw new IllegalArgumentException("Le timer doit être compris entre" + TIMER_MIN + " et " + TIMER_MAX + " secondes");
}
this.difficulty = difficulty;
this.nbRounds = nbRounds;
this.nbColors = nbColors;
this.nbValuesPerColor = nbValuesPerColor;
this.deck = new Deck(nbColors, nbValuesPerColor);
this.deck.shuffle();
this.players = new ArrayList<>();
this.createdAt = new Date();
this.timer = timer;
}
/**
* Constructeur d'une partie de jeu
*
* @param id l'identifiant de la partie
* @param createdAt la date de création de la partie
* @param difficulty la difficulté de la partie
* @param nbRounds le nombre de tours de la partie
* @param nbColors le nombre de couleurs présente dans le deck
* @param nbValuesPerColor le nombre de valeurs par couleur
* @param players les joueurs de la partie
*/
public Game(BigDecimal id, Date createdAt, Difficulty difficulty, int timer ,int nbRounds, int nbColors, int nbValuesPerColor, ArrayList<Player> players) {
if (isValidNumberRound(nbRounds, nbColors, nbValuesPerColor)){
throw new IllegalArgumentException("Le nombre de tours doit être compris entre 1 et " + nbColors * nbValuesPerColor);
}
if (timer < TIMER_MIN || timer > TIMER_MAX){
throw new IllegalArgumentException("Le timer doit être compris entre" + TIMER_MIN + " et " + TIMER_MAX + " secondes");
}
this.id = id;
this.createdAt = createdAt;
this.difficulty = difficulty;
this.nbRounds = nbRounds;
this.nbColors = nbColors;
this.nbValuesPerColor = nbValuesPerColor;
this.players = players;
this.deck = new Deck(nbColors, nbValuesPerColor);
this.timer = timer;
}
@Override
public int hashCode() {
return Objects.hash(id, createdAt);
}
/**
* @return l'identifiant de la partie
*/
public BigDecimal getId() {
return id;
}
/**
* @return la date de création de la partie
*/
public Date getCreatedAt() {
return createdAt;
}
/**
* @return la difficulté de la partie
*/
public Difficulty getDifficulty() {
return difficulty;
}
/**
* @param difficulty la nouvelle difficulté de la partie
* @see Difficulty
*/
public void setDifficulty(Difficulty difficulty) {
this.difficulty = difficulty;
}
/**
* @return le nombre de tours de la partie
*/
public int getNbRounds() {
return nbRounds;
}
/**
* @param nbRounds le nouveau nombre de tours de la partie
*/
public void setNbRounds(int nbRounds) {
if (nbRounds < NB_ROUNDS_MIN || nbRounds > nbColors * nbValuesPerColor){
throw new IllegalArgumentException("Le nombre de tours doit être compris entre " + NB_ROUNDS_MIN + " et " + nbColors * nbValuesPerColor);
}
if (nbColors < Deck.NB_COLORS_MIN || nbColors > Deck.NB_COLORS_MAX) {
throw new IllegalArgumentException("Le nombre de couleurs doit être compris entre" + NB_ROUNDS_MIN + " et " + Deck.NB_COLORS_MAX);
}
if (nbValuesPerColor < Deck.NB_VALUES_PER_COLOR_MIN || nbValuesPerColor > Deck.NB_VALUES_PER_COLOR_MAX) {
throw new IllegalArgumentException("Le nombre de valeurs par couleur doit être compris entre " + Deck.NB_VALUES_PER_COLOR_MIN + " et " + Deck.NB_VALUES_PER_COLOR_MAX);
}
this.nbRounds = nbRounds;
}
/**
* @return le nombre de couleurs présente dans le deck
*/
public int getNbColors() {
return nbColors;
}
/**
* @param nbColors le nouveau nombre de couleurs présente dans le deck
*/
public void setNbColors(int nbColors) {
if (nbColors < Deck.NB_COLORS_MIN || nbColors > Deck.NB_COLORS_MAX) {
throw new IllegalArgumentException("Le nombre de couleurs doit être compris entre " + Deck.NB_COLORS_MIN + " et " + Deck.NB_COLORS_MAX);
}
this.nbColors = nbColors;
}
/**
* @return le nombre de valeurs par couleur
*/
public int getNbValuesPerColor() {
return nbValuesPerColor;
}
/**
* @param nbValuesPerColor le nouveau nombre de valeurs par couleur
*/
public void setNbValuesPerColor(int nbValuesPerColor) {
if (nbValuesPerColor < Deck.NB_VALUES_PER_COLOR_MIN || nbValuesPerColor > Deck.NB_VALUES_PER_COLOR_MAX) {
throw new IllegalArgumentException("Le nombre de valeurs par couleur doit être compris entre " + Deck.NB_VALUES_PER_COLOR_MIN + " et " + Deck.NB_VALUES_PER_COLOR_MAX);
}
this.nbValuesPerColor = nbValuesPerColor;
}
/**
* @return les joueurs de la partie
*/
public List<Player> getPlayers() {
return players;
}
/**
* Modifie les joueurs de la partie
*
* @param players les nouveaux joueurs
*/
public void setPlayers(List<Player> players) {
this.players = players;
}
/**
* @return le nombre de joueurs de la partie
*/
public int getNbPlayers() {
return this.players.size();
}
/**
* Ajoute un joueur à la partie
*
* @param player le joueur à ajouter
*/
public void addPlayer(Player player) {
this.players.add(player);
}
public int getTimer() {
return timer;
}
public void setTimer(int timer) {
this.timer = timer;
}
public Deck getDeck() {
if (deck == null) {
deck = new Deck(nbColors, nbValuesPerColor);
deck.shuffle();
}
return deck;
}
/**
* Tri des joueurs de la partie par score puis par rapidité
*/
public void sortPlayersByScoreAndRapidity() {
players.sort((p1, p2) -> {
if (p1.getScore() == p2.getScore()) {
return p2.getRapidClickCount() - p1.getRapidClickCount();
}
return p2.getScore() - p1.getScore();
});
}
/**
* Récupère le gagnant de la partie
*
* @return le nom du gagnant
*/
public Player getWinner(){
this.sortPlayersByScoreAndRapidity();
return players.get(0);
}
/**
* Vérifie si le nombre de tours est valide
*
* @param nbRounds le nombre de tours
* @param nbColors le nombre de couleurs
* @param nbValuesPerColor le nombre de valeurs par couleur
* @return true si le nombre de tours est valide, false sinon
*/
public boolean isValidNumberRound(int nbRounds, int nbColors, int nbValuesPerColor){
return nbRounds < NB_ROUNDS_MIN || nbRounds > nbColors * nbValuesPerColor;
}
@Override
public String toString() {
return String.format("Game{id=%s, createdAt=%s, difficulty=%s, nbRounds=%d, nbColors=%d, nbValuesPerColor=%d}",
id != null ? id.toString() : "null",
createdAt != null ? createdAt.toString() : "null",
difficulty != null ? difficulty.toString() : "null",
nbRounds != 0 ? nbRounds : 0,
nbColors != 0 ? nbColors : 0,
nbValuesPerColor != 0 ? nbValuesPerColor : 0
);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Game)) return false;
Game game = (Game) o;
return getNbRounds() == game.getNbRounds() && getNbColors() == game.getNbColors() && getNbValuesPerColor() == game.getNbValuesPerColor() && Objects.equals(getId(), game.getId()) && Objects.equals(getCreatedAt(), game.getCreatedAt()) && getDifficulty() == game.getDifficulty() && Objects.equals(getPlayers(), game.getPlayers()) && Objects.equals(getDeck(), game.getDeck());
}
/**
* Difficulté possible d'une partie
*/
public enum Difficulty {EASY, HARD}
public enum GameState {WAITING, STARTED, FINISHED}
public GameState getGameState() {
return gameState;
}
public void setGameState(GameState gameState) {
this.gameState = gameState;
}
public int getCurrentRound() {
return currentRound;
}
public boolean nextRound() {
currentRound++;
if (currentRound >= nbRounds) gameState = GameState.FINISHED;
return gameState != GameState.FINISHED;
}
}
@@ -0,0 +1,406 @@
/*
* Player.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.pojo;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import jakarta.websocket.Session;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Objects;
import uppa.project.json.websocket.ClickChoice;
/**
* Représentation d'un joueur
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
@Entity
@Table(name = "player")
public class Player implements Serializable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private BigDecimal id;
@ManyToOne
@JoinColumn(name = "game_id", nullable = false)
private Game game;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Column(name = "score")
private int score;
@Column(name = "winner")
private boolean winner;
@Column(name = "click_count")
private int clickCount;
@Column(name = "right_click_count")
private int rightClickCount;
@Transient
private int tmpRightClickCount;
@Transient
private int partialRightClickCount;
@Transient
private int tmpPartialRightClickCount;
@Column(name = "rapid_click_count")
private int rapidClickCount;
@Transient
private Deck deck;
@Transient
private Session session = null;
@Transient
private ClickChoice currentClick = null;
/**
* Constructeur par défaut
*/
public Player() {
}
public Player(Game game, User user, Session session) {
this.game = game;
this.user = user;
this.session = session;
this.score = 0;
this.winner = false;
this.clickCount = 0;
this.rightClickCount = 0;
this.rapidClickCount = 0;
this.deck = new Deck(game.getNbColors(), game.getNbValuesPerColor());
this.deck.shuffle();
this.partialRightClickCount = 0;
this.tmpRightClickCount = 0;
this.tmpPartialRightClickCount = 0;
}
/**
* Constructeur d'un joueur
*
* @param game la partie de jeu
* @param user l'utilisateur
*/
public Player(Game game, User user) {
this.game = game;
this.user = user;
this.score = 0;
this.winner = false;
this.clickCount = 0;
this.rightClickCount = 0;
this.rapidClickCount = 0;
this.deck = new Deck(game.getNbColors(), game.getNbValuesPerColor());
this.deck.shuffle();
this.partialRightClickCount = 0;
this.tmpRightClickCount = 0;
this.tmpPartialRightClickCount = 0;
}
/**
* Constructeur d'un joueur
*
* @param game la partie de jeu
* @param user l'utilisateur
* @param score le score
* @param winner si le joueur est gagnant
* @param clickCount le nombre de clics
* @param rightClickCount le nombre de clics corrects
* @param rapidClickCount le nombre de clics rapides
*/
public Player(BigDecimal id, Game game, User user, int score, boolean winner, int clickCount, int rightClickCount, int rapidClickCount) {
this.id = id;
this.game = game;
this.user = user;
this.score = score;
this.winner = winner;
this.clickCount = clickCount;
this.rightClickCount = rightClickCount;
this.rapidClickCount = rapidClickCount;
this.partialRightClickCount = 0;
this.tmpRightClickCount = 0;
this.tmpPartialRightClickCount = 0;
this.deck = new Deck(game.getNbColors(), game.getNbValuesPerColor());
this.deck.shuffle();
}
@Override
public int hashCode() {
return Objects.hash(game, user, score, winner, clickCount, rightClickCount, rapidClickCount);
}
/**
* @return La partie de jeu du joueur
*/
public Game getGame() {
return game;
}
/**
* Modifie la partie de jeu du joueur
*
* @param game le nouveau jeu
*/
public void setGame(Game game) {
this.game = game;
}
/**
* @return l'utilisateur
*/
public User getUser() {
return user;
}
/**
* Modifie l'utilisateur
*
* @param user le nouvel utilisateur
*/
public void setUser(User user) {
this.user = user;
}
/**
* @return l'identifiant
*/
public int getScore() {
return score;
}
/**
* Modifie le score
*
* @param score le nouveau score
*/
public void setScore(int score) {
this.score = score;
}
/**
* Ajoute des points au score
*
* @param points les points à ajouter
*/
public void addToScore(int points) {
this.score += points;
}
/**
* @return le score maximum possible
*/
public int getScoreMax(){
return game.getNbRounds() * 3; // 2 points par bonne réponse + 1 point pour le clic rapide
}
/**
* @return si le joueur est gagnant
*/
public boolean isWinner() {
return winner;
}
/**
* Déclare le joueur comme gagnant
*/
public void setWinner() {
this.winner = true;
}
/**
* @return le nombre de clics
*/
public int getClickCount() {
return clickCount;
}
/**
* Modifie le nombre de clics
*
* @param clickCount le nouveau nombre de clics
*/
public void setClickCount(int clickCount) {
this.clickCount = clickCount;
}
/**
* Incrémente de 1 le nombre de clics
*/
public void incrementClickCount() {
clickCount++;
}
/**
* @return le nombre de clics corrects
*/
public int getRightClickCount() {
return rightClickCount;
}
/**
* Modifie le nombre de clics corrects
*
* @param rightClickCount le nouveau nombre de clics corrects
*/
public void setRightClickCount(int rightClickCount) {
this.rightClickCount = rightClickCount;
}
/**
* Incrémente de 1 le nombre de clics corrects
*/
public void incrementRightClickCount() {
rightClickCount++;
}
/**
* @return le nombre de clics corrects du joueur
*/
public int getTmpRightClickCount() {
return tmpRightClickCount;
}
/**
* Incrémente de 1 le nombre de clics corrects
*/
public void incrementTmpRightClickCount() {
tmpRightClickCount++;
}
/**
* @return le pourcentage de clics corrects du joueur sur la partie courante
*/
public double getRatioRightClick() {
if (clickCount == 0 || rightClickCount == 0) return 0;
return (double) Math.abs(rightClickCount * 10000 / game.getNbRounds()) / 100;
}
/**
* @return le nombre de clics rapides
*/
public int getRapidClickCount() {
return rapidClickCount;
}
/**
* @return le nombre de clics partiels corrects
*/
public int getPartialRightClickCount() {
return partialRightClickCount;
}
/**
* Incrémente de 1 le nombre de clics partielement corrects
*/
public void incrementPartialRightClickCount() {
partialRightClickCount++;
}
/**
* @return le nombre de clics corrects du joueur
*/
public int getTmpPartialRightClickCount() {
return tmpPartialRightClickCount;
}
/**
* Incrémente de 1 le nombre de clics corrects
*/
public void incrementTmpPartialRightClickCount() {
tmpPartialRightClickCount++;
}
/**
* Modifie le nombre de clics rapides
*
* @param rapidClickCount le nouveau nombre de clics rapides
*/
public void setRapidClickCount(int rapidClickCount) {
this.rapidClickCount = rapidClickCount;
}
/**
* Incrémente de 1 le nombre de clics rapides
*/
public void incrementRapidClickCount() {
rapidClickCount++;
}
/**
* @return le pourcentage de clics rapides du joueur sur la partie courante
*/
public double getRatioRapidClick() {
if (clickCount == 0 || rapidClickCount == 0) return 0;
return (double) Math.abs(rapidClickCount * 10000 / game.getNbRounds()) / 100;
}
public Deck getDeck() {
return deck;
}
@Override
public String toString() {
return String.format("Player{id=%s, game=%s, user=%s, score=%d, winner=%b, clickCount=%d, rightClickCount=%d, rapidClickCount=%d}",
id != null ? id.toString() : "null", game != null ? game.toString() : "null", user != null ? user.toString() : "null", score,
winner, clickCount, rightClickCount, rapidClickCount);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Player)) return false;
Player player = (Player) o;
return getScore() == player.getScore() && isWinner() == player.isWinner() && getClickCount() == player.getClickCount() && getRightClickCount() == player.getRightClickCount() && getRapidClickCount() == player.getRapidClickCount() && Objects.equals(id, player.id) && Objects.equals(getGame(), player.getGame()) && Objects.equals(getUser(), player.getUser());
}
/**
* @return l'identifiant
*/
public BigDecimal getId() {
return id;
}
public Session getSession() {
return session;
}
public ClickChoice getCurrentClick() {
return currentClick;
}
public void setCurrentClick(ClickChoice currentClick) {
this.currentClick = currentClick;
}
public void setPartialRightClickCount(int tmpPartialRightClickCount) {
this.partialRightClickCount = tmpPartialRightClickCount;
}
}
@@ -0,0 +1,165 @@
package uppa.project.database.pojo;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;
/**
* Représentation d'un token de réinitialisation de mot de passe
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
@Entity
@Table(name = "recovery_password_token")
public class RecoveryPasswordToken {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private BigDecimal id;
@Column(name = "token")
private String token;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "expires_at")
private Date expiresAt;
public RecoveryPasswordToken() {
}
/**
* Constructeur
*
* @param token
* @param user
*/
public RecoveryPasswordToken(String token, User user) {
this.token = token;
this.user = user;
this.expiresAt = new Date(new Date().getTime() + 600000);
}
/**
* Constructeur depuis la base de données
*
* @param id
* @param token
* @param user
*/
public RecoveryPasswordToken(BigDecimal id, String token, User user, Date expiresAt) {
this.id = id;
this.token = token;
this.user = user;
this.expiresAt = expiresAt;
}
/**
* Récupère l'id de l'instance
*
* @return l'id
*/
public BigDecimal getId() {
return id;
}
/**
* Récupère le token
*
* @return le token
*/
public String getToken() {
return token;
}
/**
* Définit le token
*
* @param token
*/
public void setToken(String token) {
this.token = token;
}
/**
* Récupère l'utilisateur associé au token
*
* @return l'utilisateur associé au token
*/
public User getUser() {
return user;
}
/**
* Définit l'utilisateur associé au token
*
* @param user
*/
public void setUser(User user) {
this.user = user;
}
/**
* Récupère la date d'expiration du token
*
* @return la date d'expiration du token
*/
public Date getExpiresAt() {
return expiresAt;
}
/**
* Définit la date d'expiration du token
*
* @param expiresAt
*/
public void setExpiresAt(Date expiresAt) {
this.expiresAt = expiresAt;
}
@Override
public int hashCode() {
return Objects.hash(getId(), getToken(), getUser(), getExpiresAt());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RecoveryPasswordToken)) return false;
RecoveryPasswordToken that = (RecoveryPasswordToken) o;
return Objects.equals(getId(), that.getId()) && Objects.equals(getToken(), that.getToken()) && Objects.equals(getUser(), that.getUser()) && Objects.equals(getExpiresAt(), that.getExpiresAt());
}
@Override
public String toString() {
return String.format("RecoveryPasswordToken{id=%s, token=%s, user=%s, expiresAt=%s}",
id != null ? id.toString() : "null",
token != null ? token : "null",
user != null ? user.toString() : "null",
expiresAt != null ? expiresAt.toString() : "null");
}
/**
* Récupère la date d'expiration du token
*
* @return la date d'expiration du token
*/
public Date getExpirationDate() {
return expiresAt;
}
}
@@ -0,0 +1,472 @@
/*
* User.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.database.pojo;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.persistence.Transient;
import java.io.Serializable;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* Représentation d'un utilisateur
*
* @author Kevin Mitressé
* @author Lucàs Vabre
*/
@Entity
@Table(name = "user")
public class User implements Serializable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private BigDecimal id;
@Column(name = "username")
private String username;
@Column(name = "email")
private String email;
@Column(name = "password")
private String password;
@Temporal(TemporalType.DATE)
@Column(name = "birth")
private Date birth;
@Column(name = "gender")
@Enumerated(EnumType.STRING)
private Gender gender;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Player> playedGames;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<RecoveryPasswordToken> recoveryPasswordTokens;
@Transient
private int nbPlayedGame;
@Transient
private int nbWin;
@Transient
private double winRate;
@Transient
private int nbClicks;
@Transient
private int nbRightClicks;
@Transient
private double rightClickPercentRate;
@Transient
private int nbRapidClicks;
@Transient
private double rapidClickPercentRate;
/**
* Constructeur par défaut
*/
public User() {
}
/**
* Constructeur d'un utilisateur
*
* @param username le pseudonyme
* @param email l'adresse email
* @param password le mot de passe
* @param birth la date de naissance
* @param gender le genre
*/
public User(String username, String email, String password, Date birth, Gender gender) {
if (!isValidBirthDate(birth)){
throw new IllegalArgumentException("La date de naissance n'est pas valide");
}
this.username = username;
this.email = email;
this.password = hashPassword(password);
this.birth = birth;
this.gender = gender;
this.playedGames = new ArrayList<>();
this.recoveryPasswordTokens = new ArrayList<>();
this.nbPlayedGame = 0;
this.nbWin = 0;
this.winRate = 0;
this.nbClicks = 0;
this.nbRightClicks = 0;
this.rightClickPercentRate = 0;
this.nbRapidClicks = 0;
this.rapidClickPercentRate = 0;
}
public User(BigDecimal id, String username, String email, String password, Date birth, Gender gender, List<Player> playedGames) {
if (!isValidBirthDate(birth)){
throw new IllegalArgumentException("La date de naissance n'est pas valide");
}
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.birth = birth;
this.gender = gender;
this.playedGames = playedGames;
this.nbPlayedGame = playedGames.size();
this.nbWin = getNbWin();
this.winRate = getWinRate();
this.nbClicks = getNbClicks();
this.nbRightClicks = getNbRightClicks();
this.rightClickPercentRate = getRightClickPercentRate();
this.nbRapidClicks = getNbRapidClicks();
this.rapidClickPercentRate = getRapidClickPercentRate();
}
/**
* Constructeur d'un utilisateur
*
* @param id l'identifiant
* @param username le pseudonyme
* @param email l'adresse email
* @param password le mot de passe
* @param birth la date de naissance
* @param gender le genre
*/
public User(BigDecimal id, String username, String email, String password, Date birth, Gender gender, List<Player> playedGames, List<RecoveryPasswordToken> recoveryPasswordToken) {
if (!isValidBirthDate(birth)){
throw new IllegalArgumentException("La date de naissance n'est pas valide");
}
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.birth = birth;
this.gender = gender;
this.playedGames = playedGames;
this.recoveryPasswordTokens = recoveryPasswordToken;
this.nbPlayedGame = playedGames.size();
this.nbWin = getNbWin();
this.winRate = getWinRate();
this.nbClicks = getNbClicks();
this.nbRightClicks = getNbRightClicks();
this.rightClickPercentRate = getRightClickPercentRate();
this.nbRapidClicks = getNbRapidClicks();
this.rapidClickPercentRate = getRapidClickPercentRate();
}
/**
* Hash le mot de passe en SHA-256
*
* @param password le mot de passe à hasher
* @return le mot de passe hashé
*/
public static String hashPassword(String password) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] encodedhash = digest.digest(password.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : encodedhash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
@Override
public int hashCode() {
return Objects.hash(id, username, email, password, birth, gender);
}
/**
* @return l'identifiant de l'utilisateur
*/
public BigDecimal getId() {
return id;
}
/**
* @return le pseudonyme de l'utilisateur
*/
public String getUsername() {
return username;
}
/**
* Modifie le pseudonyme de l'utilisateur
*
* @param username le nouveau pseudonyme
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return l'adresse email de l'utilisateur
*/
public String getEmail() {
return email;
}
/**
* Modifie l'adresse email de l'utilisateur
*
* @param email la nouvelle adresse email
*/
public void setEmail(String email) {
this.email = email;
}
/**
* @return le mot de passe hashé de l'utilisateur
*/
public String getPassword() {
return password;
}
/**
* Modifie le mot de passe de l'utilisateur
* Le mot de passe est hashé avant d'être stocké
*
* @param password le nouveau mot de passe
*/
public void setPassword(String password) {
this.password = hashPassword(password);
}
/**
* @return la date de naissance de l'utilisateur
*/
public Date getBirth() {
return birth;
}
/**
* Modifie la date de naissance de l'utilisateur
*
* @param birth la nouvelle date de naissance
*/
public void setBirth(Date birth) {
this.birth = birth;
}
/**
* @return le genre de l'utilisateur
*/
public Gender getGender() {
return gender;
}
/**
* Modifie le genre de l'utilisateur
*/
public void setGender(Gender gender) {
this.gender = gender;
}
/**
* Prédicat qui vérifie si le mot de passe fourni est correct
*
* @param password le mot de passe à vérifier
* @return true si le prédicat est vérifié, false sinon
*/
public boolean verifyPassword(String password) {
String hashedPassword = hashPassword(password);
return hashedPassword != null && hashedPassword.equals(this.password);
}
/**
* Récupère la liste des parties jouées par l'utilisateur
*
* @return la liste des parties jouées
*/
public List<Player> getPlayedGames() {
return playedGames;
}
/**
* Ajoute une partie dans la liste des parties jouées
*
* @param player la nouvelle partie jouée
*/
public void addPlayedGame(Player player){
playedGames.add(player);
}
/**
* Récupère le nombre de parties jouées
*
* @return le nombre de parties jouées
*/
public int getNbPlayedGame() {
return playedGames.size();
}
/**
* Récupère le nombre de parties gagnées
*
* @return le nombre de parties gagnées
*/
public int getNbWin(){
int nbWin = 0;
for (Player p : playedGames) {
if (p.isWinner()) nbWin++;
}
return nbWin;
}
public double getScoreRate(){
if (getNbPlayedGame() == 0) return 0;
int maxScore = 0;
int totalScore = 0;
for (Player p : playedGames) {
maxScore += p.getScoreMax();
totalScore += p.getScore();
}
return (double) Math.abs(totalScore * 100 / maxScore);
}
/**
* Récupère le pourcentage de victoire
*
* @return le pourcentage de victoire
*/
public double getWinRate(){
if (getNbPlayedGame() == 0 || getNbWin() == 0) return 0;
return (double) Math.abs(getNbWin() * 10000 / getNbPlayedGame()) /100;
}
/**
* Récupère le nombre total de clics toute partie confondue
*
* @return le nombre total de clics
*/
public int getNbClicks(){
int nbClicks = 0;
for (Player p : playedGames) {
nbClicks += p.getClickCount();
}
return nbClicks;
}
/**
* Récupère le nombre total de clics réussi toute partie confondue
*
* @return le nombre total de clics réussi
*/
public int getNbRightClicks(){
int nbRightClicks = 0;
for (Player p : playedGames) {
nbRightClicks += p.getRightClickCount();
}
return nbRightClicks;
}
/**
* Récupère le pourcentage de clics réussi
*
* @return le pourcentage de clics réussi
*/
public double getRightClickPercentRate(){
if (getNbClicks() == 0 || getNbRightClicks() == 0) return 0;
return (double) Math.abs(getNbRightClicks() * 10000 / getNbClicks())/100;
}
/**
* Récupère le nombre total de clics les plus rapides toute partie confondue
*
* @return le nombre total de clics les plus rapides
*/
public int getNbRapidClicks(){
int nbRapidClicks = 0;
for (Player p : playedGames) {
nbRapidClicks += p.getRapidClickCount();
}
return nbRapidClicks;
}
/**
* Récupère le pourcentage de clics les plus rapides
*
* @return le pourcentage de clics les plus rapides
*/
public double getRapidClickPercentRate(){
if (getNbClicks() == 0 || getNbRapidClicks() == 0) return 0;
return (double) Math.abs(getNbRapidClicks() * 10000 / getNbClicks())/100;
}
public boolean isValidBirthDate(Date birthdate){
Date currentDate = new Date();
return birthdate.before(currentDate) || birthdate.equals(currentDate);
}
@Override
public String toString() {
return String.format(
"User{id='%s', username=%s, email=%s, birth='%s', gender='%s'}",
id != null ? id.toString() : "null",
username != null ? username : "null",
email != null ? email : "null",
birth != null ? birth.toString() : "null",
gender != null ? gender.toString() : "null"
);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(id, user.id)
&& Objects.equals(username, user.username)
&& Objects.equals(email, user.email)
&& Objects.equals(password, user.password)
&& Objects.equals(birth, user.birth)
&& gender == user.gender
&& Objects.equals(playedGames, user.playedGames)
&& Objects.equals(recoveryPasswordTokens, user.recoveryPasswordTokens);
}
/**
* Enumération des genres possibles
*/
public enum Gender {MALE, FEMALE, OTHER}
public static Gender getGender(String value) throws IllegalArgumentException{
if (value.equals("MALE")) return Gender.MALE;
if (value.equals("FEMALE")) return Gender.FEMALE;
if (value.equals("OTHER")) return Gender.OTHER;
throw new IllegalArgumentException("Le genre selectionné n'existe pas");
}
}
@@ -0,0 +1,37 @@
/*
* HttpResponse.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.json;
/**
* Classe représentant une réponse HTTP
*
* @author Kevin Mitresse
* @author Lucàs Vabre
*/
public class HttpResponse {
/**
* Défini si la réponse est un succès
*/
protected final int code;
/**
* Message de la réponse
*/
protected final String message;
/**
* Constructeur
*
* @param code code HTTP de l'erreur
* @param message message d'erreur
*/
public HttpResponse(HttpResponseCode code, String message) {
this.code = code.getCode();
this.message = message;
}
}
@@ -0,0 +1,23 @@
package uppa.project.json;
public enum HttpResponseCode {
OK(200),
CREATED(201),
NO_CONTENT(204),
BAD_REQUEST(400),
UNAUTHORIZED(401),
FORBIDDEN(403),
NOT_FOUND(404),
CONFLICT(409),
INTERNAL_SERVER_ERROR(500);
private final int code;
HttpResponseCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
@@ -0,0 +1,9 @@
package uppa.project.json.websocket;
public enum ClickChoice {
COLOR_VALUE,
COLOR,
VALUE,
NONE,
TIMER_END
}
@@ -0,0 +1,32 @@
package uppa.project.json.websocket;
import com.google.gson.Gson;
public class Message {
private final static Gson gson = new Gson();
private final String type;
private final String data;
public Message(String type, String data) {
this.type = type;
this.data = data;
}
public String getType() {
return type;
}
public String getData() {
return data;
}
public String toJson() {
return gson.toJson(this);
}
@Override
public String toString() {
return "Message{" + "type=" + type + ", data=" + data + '}';
}
}
@@ -0,0 +1,38 @@
package uppa.project.json.websocket;
import java.util.ArrayList;
import uppa.project.database.pojo.Card;
import uppa.project.database.pojo.Game;
import uppa.project.database.pojo.Player;
public class SimpleGame {
private final int id;
private final ArrayList<SimplePlayer> players;
private final Card currentCard;
private final int currentRound;
public SimpleGame(Game game, ArrayList<Player> playerArrayList) {
this.id = game.getId().intValue();
this.players = new ArrayList<>();
for (Player p : playerArrayList) players.add(new SimplePlayer(p, game.getCurrentRound()));
this.currentCard = game.getDeck().getCards().get(game.getCurrentRound() % game.getDeck().getCards().size());
this.currentRound = game.getCurrentRound();
}
public int getId() {
return id;
}
public ArrayList<SimplePlayer> getPlayers() {
return players;
}
public Card getCurrentCard() {
return currentCard;
}
public int getCurrentRound() {
return currentRound;
}
}
@@ -0,0 +1,28 @@
package uppa.project.json.websocket;
public class SimpleInvitation {
private final SimpleUser from;
private final SimpleUser to;
private final int game_id;
public SimpleInvitation(SimpleUser from, SimpleUser to, int game_id) {
this.from = from;
this.to = to;
this.game_id = game_id;
}
public SimpleUser getFrom() {
return from;
}
public SimpleUser getTo() {
return to;
}
public int getGameId() {
return game_id;
}
}
@@ -0,0 +1,117 @@
package uppa.project.json.websocket;
import java.text.SimpleDateFormat;
import java.util.Date;
import uppa.project.database.pojo.Card;
import uppa.project.database.pojo.Player;
import uppa.project.web.translation.Translator;
public class SimplePlayer {
private final SimpleUser user;
private final int gameId;
private final int score;
private final boolean winner;
private final String winnerUsername;
private final String createdDate;
private final int clickCount;
private final int rightClickCount;
private final int partialRightClickCount;
private final int rapidClickCount;
private final Card currentCard;
public SimplePlayer(Player player, int currentRound) {
this.user = new SimpleUser(player.getUser());
this.score = player.getScore();
this.winner = player.isWinner();
this.winnerUsername = "";
this.clickCount = player.getClickCount();
this.rightClickCount = player.getRightClickCount();
this.rapidClickCount = player.getRapidClickCount();
this.partialRightClickCount = player.getPartialRightClickCount();
this.currentCard = player.getDeck().getCards().get((partialRightClickCount+rightClickCount) % player.getDeck().getCards().size());
this.createdDate = "";
this.gameId = -1;
}
/**
* Constructeur pour la pagination
*
* @param player le joueur
* @param translator le traducteur
*/
public SimplePlayer(Player player, Translator translator) {
this.user = new SimpleUser(player.getUser());
this.gameId = player.getGame().getId().intValue();
this.score = player.getScore();
this.winner = player.isWinner();
this.winnerUsername = player.getGame().getWinner().getUser().getUsername();
this.clickCount = player.getClickCount();
this.rightClickCount = player.getRightClickCount();
this.rapidClickCount = player.getRapidClickCount();
this.partialRightClickCount = player.getPartialRightClickCount();
this.currentCard = null;
Date date = player.getGame().getCreatedAt();
String language = translator.getLanguage();
SimpleDateFormat sdfDay;
SimpleDateFormat sdfHour;
if (translator.getLanguage().equals("EN")) {
sdfDay = new SimpleDateFormat("MM/dd/yyyy");
sdfHour = new SimpleDateFormat("HH:mm");
} else {
sdfDay = new SimpleDateFormat("dd/MM/yyyy");
sdfHour = new SimpleDateFormat("HH:mm");
}
String day = sdfDay.format(date);
String hour = sdfHour.format(date);
this.createdDate = day + ',' + hour ;
}
public SimplePlayer(Player player) {
this.user = new SimpleUser(player.getUser());
this.score = player.getScore();
this.winner = player.isWinner();
this.clickCount = player.getClickCount();
this.rightClickCount = player.getRightClickCount();
this.partialRightClickCount = player.getPartialRightClickCount();
this.rapidClickCount = player.getRapidClickCount();
this.currentCard = null;
this.winnerUsername = "";
this.createdDate = "" ;
this.gameId = -1;
}
public Card getCurrentCard() {
return currentCard;
}
public SimpleUser getUser() {
return user;
}
public int getScore() {
return score;
}
public boolean isWinner() {
return winner;
}
public int getClickCount() {
return clickCount;
}
public int getPartialRightClickCount() {
return partialRightClickCount;
}
public int getRightClickCount() {
return rightClickCount;
}
public int getRapidClickCount() {
return rapidClickCount;
}
}
@@ -0,0 +1,59 @@
package uppa.project.json.websocket;
import uppa.project.database.pojo.User;
public class SimpleUser {
private final int id;
private final String username;
private final int nbPlayedGames;
private final int nbWin;
private final double winRate;
private final double scoreRate;
private final double rigthClickPercentRate;
private final double rapidClickPercentRate;
public SimpleUser(User user) {
this.id = user.getId().intValue();
this.username = user.getUsername();
this.nbPlayedGames = user.getNbPlayedGame();
this.nbWin = user.getNbWin();
this.winRate = user.getWinRate();
this.scoreRate = user.getScoreRate();
this.rigthClickPercentRate = user.getRightClickPercentRate();
this.rapidClickPercentRate = user.getRapidClickPercentRate();
}
public int getId() {
return id;
}
public String getUsername() {
return username;
}
public int getNbPlayedGames() {
return nbPlayedGames;
}
public int getNbWin() {
return nbWin;
}
public double getWinRate() {
return winRate;
}
public double getScoreRate() {
return scoreRate;
}
public double getRigthClickPercentRate() {
return rigthClickPercentRate;
}
public double getRapidClickPercentRate() {
return rapidClickPercentRate;
}
}
@@ -0,0 +1,31 @@
package uppa.project.web.filter;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
public class AlreadyLoggedFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpSession session = httpRequest.getSession(false);
// Vérifier si l'utilisateur est connecté en vérifiant la présence d'une session
boolean isLoggedIn = (session != null && session.getAttribute("user") != null);
// Si l'utilisateur n'est pas connecté, laisser passer la requête
if (!isLoggedIn) {
chain.doFilter(request, response);
} else {
// Sinon, rediriger vers la page du menu principal
httpResponse.sendRedirect(httpRequest.getContextPath() + "/lobby");
}
}
}
@@ -0,0 +1,53 @@
package uppa.project.web.filter;
import jakarta.persistence.EntityManager;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.User;
public class AuthenticationFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpSession session = httpRequest.getSession(true);
// Vérifier si l'utilisateur est connecté en vérifiant la présence d'une session
boolean isLoggedIn = (session != null && session.getAttribute("user") != null);
// Si l'utilisateur est connecté, laisser passer la requête
if (isLoggedIn) {
User currentUser = (User) session.getAttribute("user");
try {
// Met à jour l'utilisateur en session
DAO<User> userDAO = new Game_JPA_DAO_Factory().getDAOUser();
session.removeAttribute("user");
EntityManager em = EntityManagerProvider.getInstance();
em.getTransaction().begin();
session.setAttribute("user", userDAO.findById(currentUser.getId().intValue()));
em.getTransaction().commit();
// Passe la requête au filtre suivant
chain.doFilter(request, response);
} catch (DAOException e) {
throw new RuntimeException(e);
}
} else {
// Sinon, rediriger vers la page de connexion
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login");
}
}
}
@@ -0,0 +1,102 @@
/*
* ForgottenPasswordServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import com.google.gson.Gson;
import jakarta.persistence.EntityManager;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import uppa.project.bean.ForgottenPasswordBean;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.RecoveryPasswordToken;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
@WebServlet(name = "forgottenPasswordServlet", value = "/forgotten-password")
public class ForgottenPasswordServlet extends HttpServlet {
final static EntityManager em = EntityManagerProvider.getInstance();
public void init() {
}
/**
* Affichage de la page de réinitialisation de mot de passe
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
request.setAttribute("current", "forgotten-password");
request.getRequestDispatcher("/WEB-INF/pages/forgotten-password.jsp").forward(request, response);
}
/**
* Gestion de la réinitialisation de mot de passe
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
Translator translator = (Translator) request.getSession().getAttribute("translator");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
ForgottenPasswordBean forgottenPasswordBean = new ForgottenPasswordBean()
.setEmail(request.getParameter("email"))
.setTranslator((Translator) request.getSession().getAttribute("translator"));
Gson gson = new Gson();
HttpResponse httpResponse;
String url = request.getRequestURL().toString();
String uri = url.substring(0, url.lastIndexOf("/"));
if (forgottenPasswordBean.validate(uri)) {
httpResponse = new HttpResponse(HttpResponseCode.OK, "Mail sent");
} else {
httpResponse = new HttpResponse(HttpResponseCode.NOT_FOUND, translator.translate("forgotten_error_email"));
}
out.println(gson.toJson(httpResponse));
out.flush();
}
/**
* Création d'un token de réinitialisation de mot de passe
*
* @param token le token
*/
public static void CreateToken(RecoveryPasswordToken token){
Game_JPA_DAO_Factory jpaDaoFactory = new Game_JPA_DAO_Factory();
em.getTransaction().begin();
try {
DAO<RecoveryPasswordToken> daoJpaRecoveryPasswordToken = jpaDaoFactory.getDAORecoveryPasswordToken();
daoJpaRecoveryPasswordToken.create(token);
em.getTransaction().commit();
} catch (DAOException e) {
em.getTransaction().rollback();
throw new RuntimeException(e);
}
}
public void destroy() {
}
}
@@ -0,0 +1,53 @@
/*
* MainMenuServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.Game;
import uppa.project.web.translation.Translator;
@WebServlet(name = "gameServlet", value = "/game")
public class GameServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page de jeu
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
try {
DAO<Game> gameDAO = new Game_JPA_DAO_Factory().getDAOGame();
Game game = gameDAO.findById(Integer.parseInt(request.getParameter("id")));
request.setAttribute("game", game);
request.getRequestDispatcher("/WEB-INF/pages/game.jsp").forward(request, response);
} catch (DAOException e) {
throw new RuntimeException(e);
}
}
public void destroy() {
}
}
@@ -0,0 +1,47 @@
package uppa.project.web.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.Game;
import uppa.project.database.pojo.Player;
import uppa.project.web.translation.Translator;
@WebServlet(name = "game-statistics", value = "/game-statistics")
public class GameStatisticsServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page de statistiques de jeu
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
Game game;
try {
DAO<Game> gameDAO = new Game_JPA_DAO_Factory().getDAOGame();
game = gameDAO.findById(Integer.parseInt(request.getParameter("id")));
ArrayList<Player> players = new ArrayList<>(game.getPlayers());
request.setAttribute("players", players);
request.setAttribute("game", game);
request.getRequestDispatcher("/WEB-INF/pages/game-statistics.jsp").forward(request, response);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,41 @@
/*
* LoginServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import uppa.project.web.translation.Translator;
@WebServlet(name = "indexServlet", value = {"/index"})
public class IndexServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page d'accueil
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
request.getRequestDispatcher("/WEB-INF/pages/index.jsp").forward(request, response);
}
public void destroy() {
}
}
@@ -0,0 +1,48 @@
/*
* MainMenuServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import uppa.project.database.pojo.Game;
import uppa.project.database.pojo.Player;
import uppa.project.database.pojo.User;
import uppa.project.web.translation.Translator;
@WebServlet(name = "lobbyServlet", value = "/lobby")
public class LobbyServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page de lobby
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
request.getRequestDispatcher("/WEB-INF/pages/lobby.jsp").forward(request, response);
}
public void destroy() {
}
}
@@ -0,0 +1,79 @@
/*
* LoginServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import com.google.gson.Gson;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import uppa.project.bean.LoginBean;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
@WebServlet(name = "loginServlet", value = "/login")
public class LoginServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page de connexion
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
request.setAttribute("current", "login");
request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response);
}
/**
* Gestion de la connexion
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
Translator translator = (Translator) request.getSession().getAttribute("translator");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
LoginBean loginBean = new LoginBean()
.setUsername(request.getParameter("username"))
.setPassword(request.getParameter("password"))
.setTranslator(translator)
;
Gson gson = new Gson();
HttpResponse httpResponse;
if (loginBean.validate()) {
request.getSession().setAttribute("user", loginBean.getUser());
httpResponse = new HttpResponse(HttpResponseCode.OK, "Login success");
} else {
httpResponse = loginBean.getError();
}
out.println(gson.toJson(httpResponse));
out.flush();
}
public void destroy() {
}
}
@@ -0,0 +1,35 @@
/*
* LogoutServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "logoutServlet", value = "/logout")
public class LogoutServlet extends HttpServlet {
public void init() {
}
/**
* Déconnexion de l'utilisateur
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
request.getSession().removeAttribute("user");
response.sendRedirect(request.getContextPath() + "/login");
}
public void destroy() {
}
}
@@ -0,0 +1,81 @@
/*
* MainMenuServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import com.google.gson.Gson;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import uppa.project.bean.NewGameBean;
import uppa.project.database.pojo.Game;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
@WebServlet(name = "newGameServlet", value = "/new")
public class NewGameServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page de création de partie
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
request.getRequestDispatcher("/WEB-INF/pages/new-game.jsp").forward(request, response);
}
/**
* Création d'une nouvelle partie
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
Gson gson = new Gson();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
NewGameBean newGameBean = new NewGameBean()
.setDifficulty(request.getParameter("difficulty"))
.setNbRounds(request.getParameter("nbRounds"))
.setTimer(request.getParameter("timer"))
.setNbValues(request.getParameter("nbValues"))
.setNbColors(request.getParameter("nbColors"))
;
HttpResponse httpResponse;
if (newGameBean.validate()) {
Game game = newGameBean.getGame();
httpResponse = new HttpResponse(HttpResponseCode.OK, game.getId().toString());
} else {
httpResponse = newGameBean.getError();
}
out.println(gson.toJson(httpResponse));
out.flush();
}
public void destroy() {
}
}
@@ -0,0 +1,130 @@
/*
* LoginServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import com.google.gson.Gson;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import uppa.project.bean.ProfileBean;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.Player;
import uppa.project.database.pojo.User;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.json.websocket.SimplePlayer;
import uppa.project.web.translation.Translator;
@WebServlet(name = "profileServlet", value = "/profile")
public class ProfileServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page de profil
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
User usersession = (User) request.getSession().getAttribute("user");
DAO<User> userDAO;
try {
userDAO = new Game_JPA_DAO_Factory().getDAOUser();
User user = userDAO.findById(usersession.getId().intValue());
request.getSession().setAttribute("user", user);
request.getRequestDispatcher("/WEB-INF/pages/profile.jsp").forward(request, response);
} catch (DAOException e) {
System.out.println(e.getMessage());
response.sendRedirect(request.getContextPath() + "/lobby");
}
}
/**
* Gestion de la modification de profil
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
Translator translator = (Translator) request.getSession().getAttribute("translator");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
ProfileBean profileBean = new ProfileBean()
.setTranslator(translator)
.setUsername(request.getParameter("username"))
.setOldEmail(request.getParameter("oldEmail"))
.setEmail(request.getParameter("email"))
.setOldPassword(request.getParameter("oldPassword"))
.setNewPassword(request.getParameter("password"))
.setConfirmPassword(request.getParameter("repassword"))
.setGender(request.getParameter("gender"))
;
Gson gson = new Gson();
HttpResponse httpResponse;
if (profileBean.validate()) {
request.getSession().setAttribute("user", profileBean.getUser());
httpResponse = new HttpResponse(
HttpResponseCode.OK,
"Register success"
);
} else {
httpResponse = profileBean.getError();
}
out.println(gson.toJson(httpResponse));
out.flush();
}
public void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException {
Translator translator = (Translator) request.getSession().getAttribute("translator");
int userID =Integer.parseInt(request.getParameter("userId"));
int firstData = Integer.parseInt(request.getParameter("pageNumber")) * 5;
try {
DAO<Player> playerDAO = new Game_JPA_DAO_Factory().getDAOPlayer();
Player[] players = playerDAO.findPlayerForPagination(userID, firstData);
SimplePlayer[] simplePlayers = new SimplePlayer[players.length];
for (int i = 0; i < players.length; i++) {
simplePlayers[i] = new SimplePlayer(players[i], translator);
}
Gson gson = new Gson();
String jsonPlayers = gson.toJson(simplePlayers);
// Configurer la réponse
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
// Envoyer la réponse JSON
PrintWriter out = response.getWriter();
out.println(jsonPlayers);
out.flush();
} catch (DAOException e) {
throw new RuntimeException(e);
}
}
public void destroy() {
}
}
@@ -0,0 +1,87 @@
/*
* RegisterServlet.java, 20/03/2024
* UPPA M1 TI 2023-2024
* Pas de copyright, aucun droits
*/
package uppa.project.web.servlet;
import com.google.gson.Gson;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import uppa.project.bean.RegisterBean;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
@WebServlet(name = "registerServlet", value = "/register")
public class RegisterServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page d'inscription
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
request.setAttribute("current", "register");
request.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(request, response);
}
/**
* Gestion de l'inscription
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
Translator translator = (Translator) request.getSession().getAttribute("translator");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
RegisterBean registerBean = new RegisterBean()
.setTranslator(translator)
.setUsername(request.getParameter("username"))
.setEmail(request.getParameter("email"))
.setPassword(request.getParameter("password"))
.setConfirmPassword(request.getParameter("repassword"))
.setBirth(request.getParameter("birth"))
.setGender(request.getParameter("gender"))
;
Gson gson = new Gson();
HttpResponse httpResponse;
if (registerBean.validate()) {
httpResponse = new HttpResponse(
HttpResponseCode.OK,
"Register success"
);
} else {
httpResponse = registerBean.getError();
}
out.println(gson.toJson(httpResponse));
out.flush();
}
public void destroy() {
}
}
@@ -0,0 +1,103 @@
package uppa.project.web.servlet;
import com.google.gson.Gson;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import uppa.project.bean.ResetPasswordBean;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.jpa.DAO_JPA_RecoveryPasswordToken;
import uppa.project.database.pojo.RecoveryPasswordToken;
import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
import uppa.project.web.translation.Translator;
@WebServlet(name = "resetPasswordServlet", value = "/reset-password")
public class ResetPasswordServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page de réinitialisation de mot de passe
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
RecoveryPasswordToken token = findRecoveryToken(request.getParameter("token"));
if (token == null) {
request.getRequestDispatcher("/WEB-INF/pages/errors/invalid-token-password.jsp").forward(request, response);
return;
}
if (token.getExpirationDate().compareTo(new java.util.Date()) < 0){
request.getRequestDispatcher("/WEB-INF/pages/errors/expired-token-password.jsp").forward(request, response);
return;
}
request.setAttribute("current", "reset-password");
request.getRequestDispatcher("/WEB-INF/pages/reset-password.jsp").forward(request, response);
}
/**
* Gestion de la réinitialisation de mot de passe
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
Translator translator = (Translator) request.getSession().getAttribute("translator");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
ResetPasswordBean resetPasswordBean = new ResetPasswordBean()
.setTranslator(translator)
.setToken(request.getParameter("token"))
.setPassword(request.getParameter("password"))
.setConfirmPassword(request.getParameter("repassword"))
;
Gson gson = new Gson();
HttpResponse httpResponse;
if (resetPasswordBean.validate()) {
httpResponse = new HttpResponse(
HttpResponseCode.OK,
"Register success"
);
} else {
httpResponse = new HttpResponse(HttpResponseCode.INTERNAL_SERVER_ERROR, resetPasswordBean.getErrorMessage());
}
out.println(gson.toJson(httpResponse));
out.flush();
}
/**
* Recherche d'un token de réinitialisation de mot de passe
*
* @param token le token
* @return le token de réinitialisation de mot de passe
*/
public static RecoveryPasswordToken findRecoveryToken(String token) {
try {
DAO_JPA_RecoveryPasswordToken daoJpaRecoveryPasswordToken = new DAO_JPA_RecoveryPasswordToken();
RecoveryPasswordToken[] recoveryPasswordTokens = daoJpaRecoveryPasswordToken.findByField("token",token);
if (recoveryPasswordTokens.length == 0) {
return null;
}
return recoveryPasswordTokens[0];
} catch (DAOException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,33 @@
package uppa.project.web.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import uppa.project.web.translation.Translator;
@WebServlet(name = "rulesServlet", value = "/rules")
public class RulesServlet extends HttpServlet {
public void init() {
}
/**
* Affichage de la page des règles
*
* @param request la requête
* @param response la réponse
* @throws IOException si une erreur d'entrée/sortie survient
* @throws ServletException si une erreur de servlet survient
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (request.getSession().getAttribute("translator") == null) {
request.getSession().setAttribute("language", "FR");
request.getSession().setAttribute("translator", Translator.generateTranslator(request.getSession(), request.getServletContext()));
}
request.getRequestDispatcher("/WEB-INF/pages/rules.jsp").forward(request, response);
}
public void destroy() {
}
}
@@ -0,0 +1,24 @@
package uppa.project.web.servlet;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import uppa.project.web.translation.Translator;
@WebServlet(name = "translationServlet", value = "/translate")
public class TranslationServlet extends HttpServlet {
public void init() {
}
public void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException {
if (request.getParameter("language") != null) {
String language = request.getParameter("language");
request.getSession().setAttribute("language", language);
Translator translator = Translator.generateTranslator(request.getSession(), request.getServletContext());
request.getSession().setAttribute("translator", translator);
}
}
}
@@ -0,0 +1,53 @@
package uppa.project.web.translation;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSession;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class Translator {
private final String language;
private final JsonParser parser;
private JsonObject translations;
public enum Language {EN, FR}
public Translator(Language language) {
this.language = language.name();
this.parser = new JsonParser();
}
public static Translator generateTranslator(HttpSession session , ServletContext context) {
Translator translator;
if (session.getAttribute("language") != null && session.getAttribute("language").equals(Translator.Language.EN.name())) {
translator = new Translator(Translator.Language.EN);
} else {
translator = new Translator(Translator.Language.FR);
}
translator.setJsonContent(context);
return translator;
}
public void setJsonContent(ServletContext context) {
InputStream is = context.getResourceAsStream("/WEB-INF/translations.json");
BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
//Parse the File as a JSON Object
JsonElement fileElement = parser.parse(reader);
this.translations = fileElement.getAsJsonObject();
}
public String translate(String text) {
return this.translations.get(text).getAsJsonObject().get(this.language).getAsString();
}
public String getLanguage() {
return language;
}
}
@@ -0,0 +1,115 @@
package uppa.project.web.websocket;
import com.google.gson.Gson;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.User;
import uppa.project.json.websocket.Message;
import uppa.project.json.websocket.SimpleInvitation;
import uppa.project.json.websocket.SimpleUser;
@ServerEndpoint(value = "/ws/users/{user_id}")
public class ConnectedUsersWS {
public static final HashMap<Session, User> users = new HashMap<>();
public static final ArrayList<Session> anonymousUsers = new ArrayList<>();
private static final Gson gson = new Gson();
private static void broadcast(String message) {
// Send the message to all anonymous users
for (Session session : anonymousUsers) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
// Send the message to all connected users
for (Session session : users.keySet()) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@OnOpen
public void onOpen(Session session, @PathParam("user_id") String userId) throws DAOException {
Message message;
int id = Integer.parseInt(userId);
if (id == 0) {
anonymousUsers.add(session);
} else {
// Get the new user
final DAO<User> userDAO = new Game_JPA_DAO_Factory().getDAOUser();
User user = userDAO.findById(id);
// Send the new user to all connected users
message = new Message("addUser", gson.toJson(new SimpleUser(user)));
broadcast(message.toJson());
// Send all connected users to the new user
users.put(session, user);
}
ArrayList<SimpleUser> connectedUsers = new ArrayList<>();
for (User u : users.values()) connectedUsers.add(new SimpleUser(u));
message = new Message("init", gson.toJson(connectedUsers));
session.getAsyncRemote().sendText(message.toJson());
}
@OnClose
public void onClose(Session session, @PathParam("user_id") String userId) {
int id = Integer.parseInt(userId);
if (id == 0) {
anonymousUsers.remove(session);
} else {
Message message = new Message("removeUser", gson.toJson(new SimpleUser(users.get(session))));
users.remove(session);
broadcast(message.toJson());
}
}
@OnError
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
@OnMessage
public void onMessage(String rawMessage, Session session) {
Message message = gson.fromJson(rawMessage, Message.class);
if (message.getType().equals("invite")) {
SimpleInvitation invitation = gson.fromJson(message.getData(), SimpleInvitation.class);
// Récupérer la session de l'utilisateur invité
for (Session s : users.keySet()) {
if (users.get(s).getId().intValue() == invitation.getTo().getId()) {
try {
s.getBasicRemote().sendText(message.toJson());
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
}
}
}
@@ -0,0 +1,397 @@
package uppa.project.web.websocket;
import com.google.gson.Gson;
import jakarta.persistence.EntityManager;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import uppa.project.bean.PlayerBean;
import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException;
import uppa.project.database.dao.EntityManagerProvider;
import uppa.project.database.dao.jpa.DAO_JPA_User;
import uppa.project.database.dao.jpa.Game_JPA_DAO_Factory;
import uppa.project.database.pojo.Card;
import uppa.project.database.pojo.Game;
import uppa.project.database.pojo.Player;
import uppa.project.database.pojo.User;
import uppa.project.json.websocket.ClickChoice;
import uppa.project.json.websocket.Message;
import uppa.project.json.websocket.SimpleGame;
import uppa.project.json.websocket.SimplePlayer;
import uppa.project.json.websocket.SimpleUser;
@ServerEndpoint(value = "/ws/game/{game_id}")
public class GameWS {
private static final HashMap<Game, ArrayList<Player>> games = new HashMap<>();
private static final HashMap<Game, Timer> timers = new HashMap<>();
Gson gson = new Gson();
private Game game;
private Player player;
@OnOpen
public void onOpen(Session session, @PathParam("game_id") String gameId) throws DAOException {
DAO<Game> gameDAO = new Game_JPA_DAO_Factory().getDAOGame();
this.game = gameDAO.findById(Integer.parseInt(gameId));
if (!games.containsKey(game)) games.put(game, new ArrayList<>());
}
@OnClose
public void onClose(Session session, @PathParam("game_id") String gameId) throws DAOException {
games.get(game).remove(this.player);
// Broadcast the new player
ArrayList<SimplePlayer> simplePlayerList = new ArrayList<>();
for (Player player : games.get(game)) simplePlayerList.add(new SimplePlayer(player));
broadcast(new Message("updatePlayerList", gson.toJson(simplePlayerList)).toJson());
}
@OnError
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
@OnMessage
public void onMessage(String rawMessage, Session session, @PathParam("game_id") String gameId) throws DAOException {
DAO<User> userDAO = new DAO_JPA_User();
Message message = gson.fromJson(rawMessage, Message.class);
if (message.getType().equals("connection")) {
SimpleUser simpleUser = gson.fromJson(message.getData(), SimpleUser.class);
// find the user
User user = userDAO.findById(simpleUser.getId());
this.player = new Player(game, user, session);
games.get(game).add(this.player);
ArrayList<SimplePlayer> simplePlayerList = new ArrayList<>();
for (Player p : games.get(game)) simplePlayerList.add(new SimplePlayer(p));
// Diffusion de la nouvelle liste de joueurs
broadcast(new Message("updatePlayerList", gson.toJson(simplePlayerList)).toJson());
}
if (message.getType().equals("start")) {
game.setGameState(Game.GameState.STARTED);
broadcast(new Message("start", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// Fin du timer
broadcast(new Message("timerEnd", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
timer.cancel();
}
}, game.getTimer() * 1000L);
timers.put(game, timer);
}
ArrayList<Card> playersCurrentCards = new ArrayList<>(games.get(game).size());
for (Player player : games.get(game)) {
playersCurrentCards.add(player.getDeck().getCards().get((player.getPartialRightClickCount()+player.getRightClickCount()) % player.getDeck().getCards().size()));
}
if (message.getType().equals("click")) {
ClickChoice choice = gson.fromJson(message.getData(), ClickChoice.class);
int playerScore = player.getScore();
Card gameCard = game.getDeck().getCards().get(game.getCurrentRound());
Card playerCard = player.getDeck().getCards().get((player.getPartialRightClickCount()+player.getRightClickCount()) % player.getDeck().getCards().size());
player.setCurrentClick(choice);
// Récupérer le nombre de joueurs ayant cliqué
int gameClickCount = 0;
for (Player player : games.get(game)) {
if (player.getCurrentClick() != null) gameClickCount++;
}
// Compteur de clics
player.incrementClickCount();
boolean isRapid = false;
// Compteur de clics rapides
if (gameClickCount == 1 && choice != ClickChoice.TIMER_END) {
isRapid = true;
};
// Vérifier le choix du joueur et attribuer les points
if (game.getDifficulty().equals(Game.Difficulty.EASY)) {
switch (choice) {
case COLOR_VALUE -> {
if (gameCard.equals(playerCard)) {
if (isRapid) {
player.incrementRapidClickCount();
playerScore++;
}
player.incrementRightClickCount();
player.setScore(playerScore + 2);
} else {
player.setScore(playerScore - 1);
}
}
case COLOR -> {
if (gameCard.getColor().equals(playerCard.getColor())) {
if (!gameCard.equals(playerCard)) {
if (isRapid) {
player.incrementRapidClickCount();
playerScore++;
}
player.incrementRightClickCount();
player.setScore(playerScore + 2);
} else {
player.incrementPartialRightClickCount();
player.setScore(playerScore + 1);
}
} else {
player.setScore(playerScore - 1);
}
}
case VALUE -> {
if (gameCard.getValue() == playerCard.getValue()) {
if (!gameCard.equals(playerCard)) {
if (isRapid) {
player.incrementRapidClickCount();
playerScore++;
}
player.incrementRightClickCount();
player.setScore(playerScore + 2);
} else {
player.incrementPartialRightClickCount();
player.setScore(playerScore + 1);
}
} else {
player.setScore(playerScore - 1);
}
}
case NONE -> {
if (!gameCard.getColor().equals(playerCard.getColor()) && gameCard.getValue() != playerCard.getValue()) {
if (isRapid) {
player.incrementRapidClickCount();
playerScore++;
}
player.incrementRightClickCount();
player.setScore(playerScore + 2);
} else {
player.setScore(playerScore - 1);
}
}
case TIMER_END -> {}
}
} else {
int nbSameCard = countSameCard(gameCard, playersCurrentCards);
int nbSameColor = countSameColor(gameCard, playersCurrentCards);
int nbSameValue = countSameValue(gameCard, playersCurrentCards);
int nbNone = countNone(gameCard, playersCurrentCards);
switch (choice) {
case COLOR_VALUE -> {
if ((nbSameCard >= nbSameColor) && (nbSameCard >= nbSameValue) && (nbSameCard >= nbNone)) {
if (isRapid) {
player.incrementRapidClickCount();
playerScore++;
}
player.incrementTmpRightClickCount();
player.setScore(playerScore + 2);
} else {
player.setScore(playerScore - 1);
}
}
case COLOR -> {
if ((nbSameCard >= nbSameColor) && (nbSameCard >= nbSameValue) && (nbSameCard >= nbNone)) {
player.incrementTmpPartialRightClickCount();
player.setScore(playerScore + 1);
} else if ((nbSameColor > nbSameCard) && (nbSameColor >= nbSameValue) && (nbSameColor >= nbNone)) {
if (isRapid) {
player.incrementRapidClickCount();
playerScore++;
}
player.incrementTmpRightClickCount();
player.setScore(playerScore + 2);
} else {
player.setScore(playerScore - 1);
}
}
case VALUE -> {
if ((nbSameCard >= nbSameColor) && (nbSameCard >= nbSameValue) && (nbSameCard >= nbNone)) {
player.incrementTmpPartialRightClickCount();
player.setScore(playerScore + 1);
} else if ((nbSameValue > nbSameCard) && (nbSameValue > nbSameColor) && (nbSameValue >= nbNone)) {
if (isRapid) {
player.incrementRapidClickCount();
playerScore++;
}
player.incrementTmpRightClickCount();
player.setScore(playerScore + 2);
} else {
player.setScore(playerScore - 1);
}
}
case NONE -> {
if ((nbNone > nbSameCard) && (nbNone >= nbSameColor) && (nbNone > nbSameValue)) {
if (isRapid) {
player.incrementRapidClickCount();
playerScore++;
}
player.incrementTmpRightClickCount();
player.setScore(playerScore + 2);
} else {
player.setScore(playerScore - 1);
}
}
case TIMER_END -> {}
}
}
// Diffuser le score du joueur
broadcast(new Message("updatePlayer", gson.toJson(new SimplePlayer(player))).toJson());
// Si tous les joueurs ont cliqué
if (gameClickCount >= games.get(game).size()) {
// Stopper le timer
timers.get(game).cancel();
// Réinitialiser les clics courrants
for (Player p : games.get(game)) {
p.setRightClickCount(p.getTmpRightClickCount());
p.setPartialRightClickCount(p.getTmpPartialRightClickCount());
p.setCurrentClick(null);
}
List<Player> players = games.get(game);
players.sort((p1, p2) -> {
if (p1.getScore() == p2.getScore()) {
return p2.getRapidClickCount() - p1.getRapidClickCount();
}
return p2.getScore() - p1.getScore();
});
Player theoricWinner = players.get(0);
Player second = players.get(1);
// Vérifier si la partie est terminée
if (game.nextRound() || (second.getScore() == theoricWinner.getScore() && second.getRapidClickCount() == theoricWinner.getRapidClickCount())) {
broadcast(new Message("nextRound", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// Diffuser la fin du timer
broadcast(new Message("timerEnd", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
timer.cancel();
}
}, game.getTimer() * 1000L);
timers.put(game, timer);
} else {
theoricWinner.setWinner();
EntityManager em = EntityManagerProvider.getFactory().createEntityManager();
em.getTransaction().begin();
for (Player p : games.get(game)) {
PlayerBean playerBean = new PlayerBean(p);
if (playerBean.validate()) System.out.println("Player " + p.getUser().getUsername() + " sauvegardé en base de données");
}
em.getTransaction().commit();
// Diffusion de la fin de la partie
broadcast(new Message("end", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
}
}
}
}
/**
* Retourne le nombre de joueurs avec une carte identique à celle du plateau
*
* @param gameCard carte du plateau
* @param currentCards liste des cartes des joueurs
* @return nombre de cartes identiques à celle du plateau
*/
private int countSameCard(Card gameCard, List<Card> currentCards) {
int counter = 0;
for (Card card : currentCards) {
if (gameCard.equals(card)) {
counter++;
}
}
return counter;
}
/**
* Retourne le nombre de joueurs avec une carte avec seulement la couleur correspondante à celle du plateau
*
* @param gameCard carte du plateau
* @param currentCards liste des cartes des joueurs
* @return nombre de couleurs identiques à celle du plateau
*/
private int countSameColor(Card gameCard, List<Card> currentCards) {
int counter = 0;
for (Card card : currentCards) {
if (gameCard.getColor().equals(card.getColor()) && !gameCard.getValue().equals(card.getValue())) {
counter++;
}
}
return counter;
}
/**
* Retourne le nombre de joueurs avec une carte avec seulement la valeur correspondante à celle du plateau
*
* @param gameCard carte du plateau
* @param currentCards liste des cartes des joueurs
* @return nombre de valeurs identiques à celle du plateau
*/
private int countSameValue(Card gameCard, List<Card> currentCards) {
int counter = 0;
for (Card card : currentCards) {
if (gameCard.getValue().equals(card.getValue()) && !gameCard.getColor().equals(card.getColor())) {
counter++;
}
}
return counter;
}
/**
* Retourne le nombre de joueurs avec une carte totalement différente de celle du plateau
*
* @param gameCard carte du plateau
* @param currentCards liste des cartes des joueurs
* @return nombre de cartes totalement différentes de celle du plateau
*/
private int countNone(Card gameCard, List<Card> currentCards) {
int counter = 0;
for (Card card : currentCards) {
if (!gameCard.getColor().equals(card.getColor()) && !gameCard.getValue().equals(card.getValue())) {
counter++;
}
}
return counter;
}
private void broadcast(String message) {
for (Player player : games.get(game)) {
try {
player.getSession().getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}