From f6c6930e50d9e5a9107eae08e7a7b3550bb666da Mon Sep 17 00:00:00 2001 From: Adrian Victor Date: Sat, 28 Mar 2026 13:51:31 -0300 Subject: [PATCH] Add search functionality to Database, add search HTTP handler, add better JSON method to HttpResponse, add missing handlers to Server auth ignore list. --- README.md | 2 +- .../livingroom/data/Database.java | 26 +++++++++++-- .../livingroom/http/Handlers.java | 1 + .../livingroom/http/HttpResponse.java | 13 +++++++ .../adrianvictor/livingroom/http/Server.java | 2 +- .../http/handlers/SearchHandler.java | 37 +++++++++++++++++++ 6 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 src/main/java/org/adrianvictor/livingroom/http/handlers/SearchHandler.java diff --git a/README.md b/README.md index fa5ae1b..83a15c7 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,10 @@ The server includes a (working but very WIP) HTTP API for third-party clients an - [x] Authentication - [x] Library info - [x] Game info +- [x] Search - [x] Downloads - [ ] Resumable downloads - [ ] User Management -- [ ] Search ### Web interface - [x] Authentication diff --git a/src/main/java/org/adrianvictor/livingroom/data/Database.java b/src/main/java/org/adrianvictor/livingroom/data/Database.java index f0a3e02..675eb62 100644 --- a/src/main/java/org/adrianvictor/livingroom/data/Database.java +++ b/src/main/java/org/adrianvictor/livingroom/data/Database.java @@ -2,7 +2,6 @@ package org.adrianvictor.livingroom.data; import org.adrianvictor.livingroom.Logger; import org.adrianvictor.livingroom.Main; -import org.adrianvictor.livingroom.config.AppConfig; import org.adrianvictor.livingroom.data.catalog.Item; import org.adrianvictor.livingroom.data.catalog.Property; import org.json.simple.JSONObject; @@ -96,7 +95,7 @@ public class Database { String sql = "SELECT id FROM games WHERE name=?"; try (Connection conn = DriverManager.getConnection(url); - PreparedStatement stmt = conn.prepareStatement(sql);) { + PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setString(1, name); try (ResultSet rs = stmt.executeQuery()) { return rs.next(); @@ -111,7 +110,7 @@ public class Database { String sql = "SELECT * FROM games WHERE id=?"; try (Connection conn = DriverManager.getConnection(url); - PreparedStatement stmt = conn.prepareStatement(sql);) { + PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setString(1, String.valueOf(id)); try (ResultSet rs = stmt.executeQuery()) { List processed = processResultSet(rs); @@ -127,9 +126,28 @@ public class Database { } } + public List search(String term) { + String sql = "SELECT * FROM games WHERE name LIKE ?"; + List result = new ArrayList<>(); + + try (Connection conn = DriverManager.getConnection(url); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, "%" + term + "%"); // partial match + + try (ResultSet rs = stmt.executeQuery()) { + result.addAll(processResultSet(rs)); + } + + } catch (SQLException e) { + Logger.error(e.getMessage()); + } + + return result; + } + public List getAllGames() { String sql = "SELECT * FROM games"; - JSONParser parser = new JSONParser(); List result = new ArrayList<>(); try (Connection conn = DriverManager.getConnection(url); diff --git a/src/main/java/org/adrianvictor/livingroom/http/Handlers.java b/src/main/java/org/adrianvictor/livingroom/http/Handlers.java index 92f931f..ec4a194 100644 --- a/src/main/java/org/adrianvictor/livingroom/http/Handlers.java +++ b/src/main/java/org/adrianvictor/livingroom/http/Handlers.java @@ -15,6 +15,7 @@ public class Handlers { map.put(new StaticWebHandler(), "/static"); map.put(new WebRedirectHandler(), "/"); map.put(new LoginHandler(), "/login"); + map.put(new SearchHandler(), "/search"); } public static HashMap getAll() { diff --git a/src/main/java/org/adrianvictor/livingroom/http/HttpResponse.java b/src/main/java/org/adrianvictor/livingroom/http/HttpResponse.java index 27f328f..046f100 100644 --- a/src/main/java/org/adrianvictor/livingroom/http/HttpResponse.java +++ b/src/main/java/org/adrianvictor/livingroom/http/HttpResponse.java @@ -1,5 +1,7 @@ package org.adrianvictor.livingroom.http; +import org.json.simple.JSONObject; + import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -33,6 +35,17 @@ public record HttpResponse( ); } + public static HttpResponse json(int status, Map extraFields) { + JSONObject json = new JSONObject(); + json.putAll(extraFields); + + return new HttpResponse( + status, + json.toJSONString().getBytes(StandardCharsets.UTF_8), + Map.of("Content-Type", "application/json") + ); + } + public static HttpResponse ok(byte[] body, String contentType) { return ok(body, contentType, new HashMap<>()); } diff --git a/src/main/java/org/adrianvictor/livingroom/http/Server.java b/src/main/java/org/adrianvictor/livingroom/http/Server.java index d634716..6613d48 100644 --- a/src/main/java/org/adrianvictor/livingroom/http/Server.java +++ b/src/main/java/org/adrianvictor/livingroom/http/Server.java @@ -68,7 +68,7 @@ public class Server { exchange.getResponseHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); exchange.getResponseHeaders().add("Access-Control-Allow-Headers", "Content-Type"); - if (!(handler instanceof WebHandler) && !(handler instanceof LoginHandler)) { + if (!(handler instanceof WebHandler) && !(handler instanceof LoginHandler) && !(handler instanceof StaticWebHandler) && !(handler instanceof WebRedirectHandler)) { Session session = AuthenticationHelper.getAuthenticatedSession(exchange); if (session == null) { try { diff --git a/src/main/java/org/adrianvictor/livingroom/http/handlers/SearchHandler.java b/src/main/java/org/adrianvictor/livingroom/http/handlers/SearchHandler.java new file mode 100644 index 0000000..cf26270 --- /dev/null +++ b/src/main/java/org/adrianvictor/livingroom/http/handlers/SearchHandler.java @@ -0,0 +1,37 @@ +package org.adrianvictor.livingroom.http.handlers; + +import com.sun.net.httpserver.HttpExchange; +import org.adrianvictor.livingroom.data.Database; +import org.adrianvictor.livingroom.data.catalog.Item; +import org.adrianvictor.livingroom.http.Handler; +import org.adrianvictor.livingroom.http.HttpResponse; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SearchHandler implements Handler { + + @Override + public HttpResponse result(String baseAddress, String path, HttpExchange exchange) { + String[] parts = path.split("/"); + + if (parts.length < 1) { + Map map = new HashMap<>(); + map.put("message", "Invalid usage. Usage: ./query"); + return HttpResponse.json(400, map); + } + + List games = Database.getInstance().search(parts[1]); + JSONArray json = new JSONArray(); + for (Item g : games) { + json.add(new JSONObject(g.getPropertiesString())); + } + Map extraFields = new HashMap<>(); + extraFields.put("result", json.toJSONString()); + extraFields.put("success", "true"); + return HttpResponse.json(200, extraFields); + } +}