diff --git a/.vscode/settings.json b/.vscode/settings.json index e0f15db..7562748 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,18 @@ { - "java.configuration.updateBuildConfiguration": "automatic" -} \ No newline at end of file + "java.configuration.updateBuildConfiguration": "automatic", + "sqltools.connections": [ + { + "mysqlOptions": { + "authProtocol": "default" + }, + "previewLimit": 50, + "server": "localhost", + "port": 3306, + "driver": "MariaDB", + "name": "pixel", + "database": "pixel", + "username": "mysql", + "password": "mysql" + } + ] +} diff --git a/src/main/java/com/pixels/Frontend.java b/src/main/java/com/pixels/Frontend.java new file mode 100644 index 0000000..e7311a9 --- /dev/null +++ b/src/main/java/com/pixels/Frontend.java @@ -0,0 +1,18 @@ +package com.pixels; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +@WebServlet(name = "Frontend", urlPatterns = { "" }, loadOnStartup = 1) +public class Frontend extends HttpServlet { + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + request.getSession(); + request.getRequestDispatcher("index.html").forward(request, response); + } +} diff --git a/src/main/java/com/pixels/adapters/PixelAdapter.java b/src/main/java/com/pixels/adapters/PixelAdapter.java new file mode 100644 index 0000000..dd2cbe4 --- /dev/null +++ b/src/main/java/com/pixels/adapters/PixelAdapter.java @@ -0,0 +1,30 @@ +package com.pixels.adapters; + +import java.lang.reflect.Type; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.pixels.beans.Pixel; +import com.pixels.beans.User; + +public class PixelAdapter implements JsonSerializer { + + @Override + public JsonElement serialize(Pixel src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = new JsonObject(); + + json.addProperty("id", src.getId()); + json.addProperty("price", src.getPrice()); + json.addProperty("color", src.getColor()); + json.addProperty("description", src.getDescription()); + + User owner = src.getOwner(); + if (owner != null) { + json.addProperty("owner_username", owner.getUsername()); + } + + return json; + } +} diff --git a/src/main/java/com/pixels/adapters/UserAdapter.java b/src/main/java/com/pixels/adapters/UserAdapter.java new file mode 100644 index 0000000..7e35914 --- /dev/null +++ b/src/main/java/com/pixels/adapters/UserAdapter.java @@ -0,0 +1,37 @@ +package com.pixels.adapters; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.pixels.beans.Pixel; +import com.pixels.beans.User; + +public class UserAdapter implements JsonSerializer { + + Gson gson = new GsonBuilder().create(); + + @Override + public JsonElement serialize(User src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject json = new JsonObject(); + + json.addProperty("user", src.getUsername()); + json.addProperty("email", src.getEmail()); + json.addProperty("balance", src.getBalance()); + + List list = new ArrayList<>(); + for (Pixel pixel : src.getPixels()) { + list.add(pixel.getId()); + } + + json.add("pixels", gson.toJsonTree(list)); + + return json; + } +} diff --git a/src/main/java/com/pixels/beans/User.java b/src/main/java/com/pixels/beans/User.java index 133db83..8d1681a 100644 --- a/src/main/java/com/pixels/beans/User.java +++ b/src/main/java/com/pixels/beans/User.java @@ -28,32 +28,42 @@ public class User implements Serializable { // addresse mail de l'utilisateur @NonNull @NotBlank + @Column(unique = true) private String email; // mot de passe hashé en sha256 @NonNull @NotBlank - private String hashPassword; + private transient String password; // portefeuille - @OneToMany + @OneToMany(mappedBy = "owner") private List pixels; // le solde de l'utilisateur @NotNull private Integer balance = 0; - // pixels possédés - @OneToMany(mappedBy = "owner") - private List owned; + private transient String sessionID; public User(String username, String email, String password) { this.username = username; this.email = email; - this.hashPassword = Hash.sha256(password); + this.password = Hash.sha256(password); } - public void setHashPassword(String password) { - this.hashPassword = Hash.sha256(password); + public void setPassword(String password) { + this.password = Hash.sha256(password); } + + public boolean validPassword(String password) { + return this.password.equals(Hash.sha256(password)); + } + + public static User fromSessionID(String sessionID, EntityManager em) { + return em.createQuery("SELECT u FROM User u WHERE sessionID = :session_id", User.class) + .setParameter("session_id", sessionID) + .getSingleResult(); + } + } diff --git a/src/main/java/com/pixels/services/PixelService.java b/src/main/java/com/pixels/services/PixelService.java index 0ad0309..5af7c61 100644 --- a/src/main/java/com/pixels/services/PixelService.java +++ b/src/main/java/com/pixels/services/PixelService.java @@ -1,20 +1,30 @@ package com.pixels.services; +import java.util.Date; + import javax.ejb.Singleton; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import javax.ws.rs.Consumes; +import javax.ws.rs.CookieParam; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; +import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Cookie; import javax.ws.rs.core.MediaType; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.pixels.adapters.PixelAdapter; +import com.pixels.adapters.UserAdapter; import com.pixels.beans.Pixel; +import com.pixels.beans.Transaction; +import com.pixels.beans.User; @Singleton @Path("/pixel") @@ -23,7 +33,10 @@ public class PixelService { @PersistenceContext private EntityManager em; - Gson gson = new Gson(); + Gson gson = new GsonBuilder() + .registerTypeAdapter(Pixel.class, new PixelAdapter()) + .registerTypeAdapter(User.class, new UserAdapter()) + .create(); @GET @Produces(MediaType.APPLICATION_JSON) @@ -54,4 +67,42 @@ public class PixelService { em.merge(pixel); return gson.toJson(pixel); } + + @POST + @Path("{id}/buy/") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public String buy_pixel(@PathParam("id") Long id, @CookieParam("JSESSIONID") Cookie cookie, String json) { + // on récupère les informations du changement + Pixel pixel_json = gson.fromJson(json, Pixel.class); + + // on récupère le pixel de la db via son id + Pixel pixel = em.find(Pixel.class, id); + + // on récupère le nouveau proprio + User user = User.fromSessionID(cookie.getValue(), em); + + if (user.getBalance() >= pixel.getPrice() && pixel_json.getPrice() > pixel.getPrice()) { + // on update le pixel + pixel.setOwner(user); + pixel.setColor(pixel_json.getColor()); + pixel.setDescription(pixel_json.getDescription()); + pixel.setPrice(pixel_json.getPrice()); + + // on débite le user + user.setBalance(user.getBalance() - pixel_json.getPrice()); + + // on ajoute la transaction + Date now = new Date(System.currentTimeMillis()); + Transaction new_transaction = new Transaction(now, pixel); + em.persist(new_transaction); + + // on update le pixel dans la db + em.merge(pixel); + em.merge(user); + } + + return gson.toJson(pixel); + } + } diff --git a/src/main/java/com/pixels/services/UserService.java b/src/main/java/com/pixels/services/UserService.java index 0e2b3a6..1bd3293 100644 --- a/src/main/java/com/pixels/services/UserService.java +++ b/src/main/java/com/pixels/services/UserService.java @@ -1,22 +1,28 @@ package com.pixels.services; -import java.util.Date; +import java.util.logging.Logger; import javax.ejb.Singleton; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; +import javax.persistence.NoResultException; import javax.ws.rs.Consumes; +import javax.ws.rs.CookieParam; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; +import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Cookie; import javax.ws.rs.core.MediaType; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.pixels.adapters.PixelAdapter; +import com.pixels.adapters.UserAdapter; import com.pixels.beans.Pixel; -import com.pixels.beans.Transaction; import com.pixels.beans.User; @Singleton @@ -26,7 +32,12 @@ public class UserService { @PersistenceContext private EntityManager em; - Gson gson = new Gson(); + private final Logger LOGGER = Logger.getLogger("UserService"); + + Gson gson = new GsonBuilder() + .registerTypeAdapter(Pixel.class, new PixelAdapter()) + .registerTypeAdapter(User.class, new UserAdapter()) + .create(); @GET @Produces(MediaType.APPLICATION_JSON) @@ -36,45 +47,69 @@ public class UserService { } @GET - @Path("{id}") + @Path("{username}") @Produces(MediaType.APPLICATION_JSON) - public String single(@PathParam("id") Long id) { - User user = em.find(User.class, id); + public String single(@PathParam("username") String username) { + User user = em.find(User.class, username); if (user == null) { throw new NotFoundException(); } else { + LOGGER.info(gson.toJson(user.getPixels())); return gson.toJson(user); } } - @GET - @Path("{id_user}/buy/{id_pixel}") + @POST + @Path("signup") @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public String buy_pixel(@PathParam("id") Long id_pixel, @PathParam("id") Long id_user, String json) { - // on récupère les informations du changement - Pixel pixel_new_infos = gson.fromJson(json, Pixel.class); + public void signup(@CookieParam("JSESSIONID") Cookie cookie, String json) { + User json_user = gson.fromJson(json, User.class); + User new_user = new User( + json_user.getUsername(), + json_user.getEmail(), + json_user.getPassword()); + new_user.setSessionID(cookie.getValue()); + em.persist(new_user); + LOGGER.info("new user: " + new_user.getUsername()); + } - // on récupère le pixel de la db via son id - Pixel pixel = em.find(Pixel.class, id_pixel); + @POST + @Path("login") + @Consumes(MediaType.APPLICATION_JSON) + public void login(@CookieParam("JSESSIONID") Cookie cookie, String json) { + User user; + try { + // si on trouve l'utilsateur via son sessionID + user = User.fromSessionID(cookie.getValue(), em); + LOGGER.info(user.getUsername() + " already logged in"); + // TODO: renvoyer un json avec les creds + } catch (NoResultException e) { + // on parse le json en objet User + User json_user = gson.fromJson(json, User.class); - // on récupère le nouveau proprio - User user = em.find(User.class, id_user); + // on trouve le user à partir de son username + user = em.find(User.class, json_user.getUsername()); - // on update le pixel - pixel.setOwner(user); - pixel.setColor(pixel_new_infos.getColor()); - pixel.setDescription(pixel_new_infos.getDescription()); - pixel.setPrice(pixel.getPrice() + 1); + // si les identifiants sont valides + if (user.validPassword(json_user.getPassword())) { + user.setSessionID(cookie.getValue()); + em.merge(user); + LOGGER.info(user.getUsername() + " logged in"); + } else { + LOGGER.info("incorrect creds for " + user.getUsername()); + } + } + } - // on ajoute la transaction - Date now = new Date(System.currentTimeMillis()); - Transaction new_transaction = new Transaction(now, pixel); - em.persist(new_transaction); - - // on update le pixel dans la db - em.merge(pixel); - - return gson.toJson(pixel); + @POST + @Path("logout") + public void logout(@CookieParam("JSESSIONID") Cookie cookie) { + try { + User user = User.fromSessionID(cookie.getValue(), em); + user.setSessionID(null); + LOGGER.info(user.getUsername() + " logged out"); + } catch (NoResultException e) { + LOGGER.info("user not logged in, cannot logout"); + } } }