From 19fd84fd60cca54adcd9fc157c3a1363635194a2 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Sun, 7 Jan 2024 18:56:27 +0100 Subject: [PATCH] implemented trading ~2h work --- .../nanopenguin/mtcg/application/Trade.java | 125 ++++++++++++++++++ .../mtcg/application/UserCards.java | 3 +- .../application/service/TradingService.java | 76 +++++++++-- src/at/nanopenguin/mtcg/db/Table.java | 1 + 4 files changed, 190 insertions(+), 15 deletions(-) create mode 100644 src/at/nanopenguin/mtcg/application/Trade.java diff --git a/src/at/nanopenguin/mtcg/application/Trade.java b/src/at/nanopenguin/mtcg/application/Trade.java new file mode 100644 index 0000000..f755f15 --- /dev/null +++ b/src/at/nanopenguin/mtcg/application/Trade.java @@ -0,0 +1,125 @@ +package at.nanopenguin.mtcg.application; + +import at.nanopenguin.mtcg.application.service.schemas.TradingDeal; +import at.nanopenguin.mtcg.db.DbQuery; +import at.nanopenguin.mtcg.db.SqlCommand; +import at.nanopenguin.mtcg.db.Table; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.val; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.UUID; + +public class Trade { + public static TradingDeal[] get() throws SQLException { + val dbQueryBuilder = DbQuery.builder() + .command(SqlCommand.SELECT) + .table(Table.TRADES) + .column("uuid AS id") + .column("card AS cardToTrade") + .column("card_type AS type") + .column("min_dmg AS minimumDamage"); + + ArrayList trades = new ArrayList<>(); + for (val row : dbQueryBuilder.executeQuery()) { + trades.add(new ObjectMapper().convertValue(row, TradingDeal.class)); + } + return trades.toArray(new TradingDeal[0]); + } + + public static boolean addTrade(TradingDeal tradingDeal, UUID userUuid) throws SQLException { + if (DbQuery.builder() + .customSql(""" + SELECT * + FROM cards + WHERE uuid = ?::uuid + AND owner = ?::uuid + AND trade = false + AND deck = false; + """) + .value(tradingDeal.cardToTrade()) + .value(userUuid) + .executeQuery().isEmpty()) + return false; + + String sql = tradingDeal.id() != null ? + "INSERT INTO trades (uuid, card, card_type, min_dmg, user_uuid) VALUES (?::uuid, ?::uuid, ?::cardtype, ?, ?::uuid);" : + "INSERT INTO trades (card, card_type, min_dmg, user_uuid) VALUES (?::uuid, ?::cardtype, ?, ?::uuid);"; + + val dbQueryBuilder = DbQuery.builder() + .customSql(sql); + if (tradingDeal.id() != null) dbQueryBuilder.value(tradingDeal.id()); + dbQueryBuilder + .value(tradingDeal.cardToTrade()) + .value(tradingDeal.type()) + .value(tradingDeal.minimumDamage()) + .value(userUuid) + .executeUpdate(); + + return true; + } + + public static synchronized boolean acceptTrade(UUID tradeUuid, UUID cardUuid, UUID userUuid) throws SQLException, NullPointerException { + + val tradeResult = DbQuery.builder() + .command(SqlCommand.SELECT) + .table(Table.TRADES) + .condition("uuid", tradeUuid) + .executeQuery(); + + if (tradeResult.isEmpty()) throw new NullPointerException(); + + TradingDeal trade = new ObjectMapper().convertValue(tradeResult.get(0), TradingDeal.class); + + val offeredResult = DbQuery.builder() + .command(SqlCommand.SELECT) + .table(Table.CARDS) + .condition("deck", false) + .condition("owner", userUuid) + .executeQuery(); + + if (offeredResult.isEmpty()) return false; + val card = offeredResult.get(0); + if (!((String) card.get("name")).toLowerCase().endsWith(trade.type())) return false; + + DbQuery.builder() + .command(SqlCommand.UPDATE) + .table(Table.CARDS) + .parameter("owner", userUuid) + .parameter("trade", false) + .condition("uuid", trade.cardToTrade()) + .executeUpdate(); + + DbQuery.builder() + .command(SqlCommand.UPDATE) + .table(Table.CARDS) + .parameter("owner", tradeResult.get(0).get("user_uuid")) + .parameter("trade", false) + .condition("uuid", cardUuid) + .executeUpdate(); + + DbQuery.builder() + .command(SqlCommand.DELETE) + .table(Table.TRADES) + .condition("uuid", tradeUuid) + .executeUpdate(); + + return true; + } + + public static boolean removeTrade(UUID tradeUuid, UUID userUuid) throws SQLException { + if (DbQuery.builder() + .command(SqlCommand.SELECT) + .table(Table.TRADES) + .condition("uuid", tradeUuid) + .executeQuery().isEmpty()) throw new NullPointerException(); + + return DbQuery.builder() + .command(SqlCommand.DELETE) + .table(Table.TRADES) + .condition("uuid", tradeUuid) + .condition("user_uuid", userUuid) + .executeUpdate() > 0; + } +} diff --git a/src/at/nanopenguin/mtcg/application/UserCards.java b/src/at/nanopenguin/mtcg/application/UserCards.java index a33d400..fd302a7 100644 --- a/src/at/nanopenguin/mtcg/application/UserCards.java +++ b/src/at/nanopenguin/mtcg/application/UserCards.java @@ -29,11 +29,12 @@ public class UserCards extends User { return cards.toArray(new Card[0]); } - public static synchronized boolean setDeck(UUID[] cards, UUID userUuid) throws SQLException { + public static boolean setDeck(UUID[] cards, UUID userUuid) throws SQLException { if (DbQuery.builder() .command(SqlCommand.SELECT) .table(Table.CARDS) .condition("owner", userUuid) + .condition("trade", false) .condition("uuid", Arrays.asList(cards)) .executeQuery().size() != 4) return false; diff --git a/src/at/nanopenguin/mtcg/application/service/TradingService.java b/src/at/nanopenguin/mtcg/application/service/TradingService.java index 20f6f60..9bfa56f 100644 --- a/src/at/nanopenguin/mtcg/application/service/TradingService.java +++ b/src/at/nanopenguin/mtcg/application/service/TradingService.java @@ -1,28 +1,76 @@ package at.nanopenguin.mtcg.application.service; +import at.nanopenguin.mtcg.application.SessionHandler; +import at.nanopenguin.mtcg.application.TokenValidity; +import at.nanopenguin.mtcg.application.Trade; +import at.nanopenguin.mtcg.application.service.schemas.TradingDeal; import at.nanopenguin.mtcg.http.HttpMethod; import at.nanopenguin.mtcg.http.HttpRequest; import at.nanopenguin.mtcg.http.HttpStatus; import at.nanopenguin.mtcg.http.Response; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.val; + +import java.sql.SQLException; +import java.util.UUID; public class TradingService implements Service { - @Override - public Response handleRequest(HttpRequest request) throws JsonProcessingException { - try { - if (request.getPath().split("/")[1].equals("tradings")) { - return switch (request.getMethod()) { - case GET -> new Response(HttpStatus.NOT_IMPLEMENTED); - case POST -> new Response(HttpStatus.NOT_IMPLEMENTED); // request.getPath().split("/").length > 2 => path variable - case DELETE -> new Response(HttpStatus.NOT_IMPLEMENTED); - default -> new Response(HttpStatus.NOT_FOUND); - }; - } + public Response handleRequest(HttpRequest request) throws JsonProcessingException, ArrayIndexOutOfBoundsException, SQLException { - return new Response(HttpStatus.NOT_FOUND); - } catch (ArrayIndexOutOfBoundsException e) { - return new Response(HttpStatus.BAD_REQUEST); + UUID authToken = SessionHandler.tokenFromHttpHeader(request.getHttpHeader("Authorization")); + if (SessionHandler.getInstance().verifyUUID(authToken) != TokenValidity.VALID) + return new Response(HttpStatus.UNAUTHORIZED); + UUID userUuid = SessionHandler.getInstance().userUuidFromToken(authToken); + + if (request.getPath().split("/")[1].equals("tradings")) { + return switch (request.getMethod()) { + case GET -> { + val result = Trade.get(); + if (result.length == 0) yield new Response(HttpStatus.NO_CONTENT); + yield new Response(HttpStatus.OK, new ObjectMapper().writeValueAsString(result)); + } + case POST -> { + if (request.getPath().split("/").length < 3) { + try { + yield new Response(Trade.addTrade(new ObjectMapper().readValue(request.getBody(), TradingDeal.class), userUuid) ? + HttpStatus.CREATED : HttpStatus.FORBIDDEN); + } catch (SQLException e) { + if (!e.getSQLState().equals("23505")) + throw e; + yield new Response(HttpStatus.CONFLICT); + } + } + + try { + yield new Response(Trade.acceptTrade( + UUID.fromString(request.getPath().split("/")[3]), + UUID.fromString(request.getBody()), + userUuid) ? + HttpStatus.OK : + HttpStatus.FORBIDDEN); + } + catch (NullPointerException e) { + yield new Response(HttpStatus.NOT_FOUND); + } + } + case DELETE -> { + try { + yield new Response(Trade.removeTrade( + UUID.fromString(request.getPath().split("/")[3]), + userUuid) ? + HttpStatus.OK : + HttpStatus.FORBIDDEN); + } + catch (NullPointerException e) { + yield new Response(HttpStatus.NOT_FOUND); + } + } + default -> new Response(HttpStatus.NOT_FOUND); + }; } + + return new Response(HttpStatus.NOT_FOUND); } } \ No newline at end of file diff --git a/src/at/nanopenguin/mtcg/db/Table.java b/src/at/nanopenguin/mtcg/db/Table.java index 17e3244..e210150 100644 --- a/src/at/nanopenguin/mtcg/db/Table.java +++ b/src/at/nanopenguin/mtcg/db/Table.java @@ -7,6 +7,7 @@ public enum Table { USERS("users"), CARDS("cards"), PACKAGES("packages"), + TRADES("trades"), NAN(null); public final String table;