From 56deb56c72aae5552123f5f243bf714e5d16fa3b Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Fri, 20 Mar 2026 15:33:33 +0100 Subject: [PATCH] global search fixed --- .../fabka/app/HttpServerApplication.java | 43 +++++++++++ .../fabka/repository/ForumRepository.java | 46 +++++++++++ .../fabka/repository/model/ForumMessage.java | 13 +++- .../repository/model/SearchResultItem.java | 73 ++++++++++++++++++ src/main/java/cz/kamma/fabka/web/Pages.java | 76 ++++++++++++++++++- src/main/resources/webapp/forum.html | 2 +- 6 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 src/main/java/cz/kamma/fabka/repository/model/SearchResultItem.java diff --git a/src/main/java/cz/kamma/fabka/app/HttpServerApplication.java b/src/main/java/cz/kamma/fabka/app/HttpServerApplication.java index 06dded0..35bd358 100644 --- a/src/main/java/cz/kamma/fabka/app/HttpServerApplication.java +++ b/src/main/java/cz/kamma/fabka/app/HttpServerApplication.java @@ -44,6 +44,7 @@ import cz.kamma.fabka.repository.model.PrivateMessageStats; import cz.kamma.fabka.repository.model.PrivateThreadRoot; import cz.kamma.fabka.repository.model.PrivateThreadSummary; import cz.kamma.fabka.repository.model.QuotedTextItem; +import cz.kamma.fabka.repository.model.SearchResultItem; import cz.kamma.fabka.repository.SettingsRepository; import cz.kamma.fabka.repository.model.UserIcon; import cz.kamma.fabka.repository.UserIconRepository; @@ -150,6 +151,48 @@ public class HttpServerApplication { boolean showError = "1".equals(ctx.queryParam("error")); Responses.html(ctx.exchange(), 200, Pages.loginPage(showError)); }); + + router.get("/search", ctx -> { + if (!isAuthenticated(ctx)) { + Responses.text(ctx.exchange(), 401, "Unauthorized"); + return; + } + + String searchText = valueOrDefault(ctx.queryParam("stext"), ""); + String f = ctx.queryParam("fid"); + long forumId = f != null && !f.isBlank() ? parseLong(f, 0) : 0; + + SessionData session = ctx.getSession(); + if (session == null) { + Responses.text(ctx.exchange(), 401, "Unauthorized"); + return; + } + + String username = String.valueOf(session.getAttribute(AUTH_USER_KEY)); + long userId = parseLong(session.getAttribute(AUTH_USER_ID_KEY), -1L); + + if (userId <= 0) { + Responses.text(ctx.exchange(), 401, "Unauthorized"); + return; + } + + List results = forumRepository.searchMessages(userId, searchText, forumId); + + int loggedUsersCount = sessionManager.countSessionsWithAttribute(AUTH_USER_KEY); + List loggedUsers = sessionManager.sessionAttributeValues(AUTH_USER_KEY); + PrivateMessageStats pmStats = privateMessageRepository.stats(userId); + + Responses.html(ctx.exchange(), 200, Pages.searchResultsPage( + username, + userId, + results, + searchText, + loggedUsersCount, + loggedUsers, + pmStats + )); + }); + router.get("/chat.jsp", ctx -> Responses.redirect(ctx.exchange(), "/chat")); router.get("/private.jsp", ctx -> { String oBy = ctx.queryParam("oBy"); diff --git a/src/main/java/cz/kamma/fabka/repository/ForumRepository.java b/src/main/java/cz/kamma/fabka/repository/ForumRepository.java index eca52c7..99441a1 100644 --- a/src/main/java/cz/kamma/fabka/repository/ForumRepository.java +++ b/src/main/java/cz/kamma/fabka/repository/ForumRepository.java @@ -24,6 +24,7 @@ import cz.kamma.fabka.repository.model.ForumDetail; import cz.kamma.fabka.repository.model.ForumMessage; import cz.kamma.fabka.repository.model.ForumSummary; import cz.kamma.fabka.repository.model.QuotedTextItem; +import cz.kamma.fabka.repository.model.SearchResultItem; import cz.kamma.fabka.repository.model.VoteStats; public class ForumRepository { @@ -282,6 +283,7 @@ public class ForumRepository { out.add(new ForumMessage( messageId, + forumId, authorIds.get(i), valueOrDefault(usernames.get(i), "N/A"), formatTs(createdTimes.get(i)), @@ -678,6 +680,50 @@ public class ForumRepository { return value == null || value.isBlank() ? defaultValue : value; } + public List searchMessages(long userId, String searchText, long forumId) { + List results = new ArrayList<>(); + if (searchText == null || searchText.isBlank()) { + return results; + } + + String sql = "SELECT fi.id, fi.forumid, fi.created, fi.createdby, fi.text, ua.username, ua.city, ua.created as createdua, f.name FROM forum_items fi, user_accounts ua, forum f WHERE " + + (forumId > 0 ? "fi.forumid=" + forumId + " AND " : "") + + "MATCH (fi.text) AGAINST (? IN BOOLEAN MODE) AND fi.deleted=0 AND fi.createdby=ua.id AND f.id=fi.forumid AND f.password IN (SELECT password FROM passwords WHERE userid=?)"; + + long startTime = System.nanoTime(); + try (Connection conn = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword); + PreparedStatement ps = conn.prepareStatement(sql)) { + ps.setString(1, searchText); + ps.setLong(2, userId); + System.out.println("[DEBUG] SEARCH SQL (forumId=" + forumId + "): " + sql); + + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + results.add(buildSearchResultFromResultSet(rs)); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + long durationMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime); + System.out.println("[DEBUG] SEARCH_MESSAGES_SQL: searchText='" + searchText + "', forumId=" + forumId + ", count=" + results.size() + ", duration=" + durationMs + "ms"); + return results; + } + + private SearchResultItem buildSearchResultFromResultSet(ResultSet rs) throws Exception { + long id = rs.getLong("id"); + long forumId = rs.getLong("forumid"); + Timestamp created = rs.getTimestamp("created"); + long createdBy = rs.getLong("createdby"); + String text = rs.getString("text"); + String username = rs.getString("username"); + String city = rs.getString("city"); + Timestamp createdua = rs.getTimestamp("createdua"); + String forumName = rs.getString("name"); + + return new SearchResultItem(id, forumId, created, createdBy, text, username, city, createdua, forumName); + } + private static String formatTs(Timestamp ts) { if (ts == null) { return "N/A"; diff --git a/src/main/java/cz/kamma/fabka/repository/model/ForumMessage.java b/src/main/java/cz/kamma/fabka/repository/model/ForumMessage.java index 24e772c..17f23df 100644 --- a/src/main/java/cz/kamma/fabka/repository/model/ForumMessage.java +++ b/src/main/java/cz/kamma/fabka/repository/model/ForumMessage.java @@ -4,6 +4,7 @@ import java.util.List; public class ForumMessage { private final long id; + private final long forumId; private final long authorId; private final String author; private final String authorJoinDate; @@ -19,11 +20,12 @@ public class ForumMessage { private final QuotedTextItem quotedItem; private final String createdAt; private final String text; - private final List attachments; + private List attachments; private final boolean sticky; public ForumMessage( long id, + long forumId, long authorId, String author, String authorJoinDate, @@ -43,6 +45,7 @@ public class ForumMessage { boolean sticky ) { this.id = id; + this.forumId = forumId; this.authorId = authorId; this.author = author; this.authorJoinDate = authorJoinDate; @@ -133,4 +136,12 @@ public class ForumMessage { public boolean isSticky() { return sticky; } + + public long getForumId() { + return forumId; + } + + public void setAttachments(List attachments) { + this.attachments = attachments; + } } diff --git a/src/main/java/cz/kamma/fabka/repository/model/SearchResultItem.java b/src/main/java/cz/kamma/fabka/repository/model/SearchResultItem.java new file mode 100644 index 0000000..7cd8784 --- /dev/null +++ b/src/main/java/cz/kamma/fabka/repository/model/SearchResultItem.java @@ -0,0 +1,73 @@ +package cz.kamma.fabka.repository.model; + +import java.sql.Timestamp; + +public class SearchResultItem { + private final long id; + private final long forumId; + private final Timestamp created; + private final long createdBy; + private final String text; + private final String username; + private final String city; + private final Timestamp createdua; + private final String forumName; + + public SearchResultItem( + long id, + long forumId, + Timestamp created, + long createdBy, + String text, + String username, + String city, + Timestamp createdua, + String forumName + ) { + this.id = id; + this.forumId = forumId; + this.created = created; + this.createdBy = createdBy; + this.text = text; + this.username = username; + this.city = city; + this.createdua = createdua; + this.forumName = forumName; + } + + public long getId() { + return id; + } + + public long getForumId() { + return forumId; + } + + public Timestamp getCreated() { + return created; + } + + public long getCreatedBy() { + return createdBy; + } + + public String getText() { + return text; + } + + public String getUsername() { + return username; + } + + public String getCity() { + return city; + } + + public Timestamp getCreatedua() { + return createdua; + } + + public String getForumName() { + return forumName; + } +} diff --git a/src/main/java/cz/kamma/fabka/web/Pages.java b/src/main/java/cz/kamma/fabka/web/Pages.java index 76c7ad7..55483c2 100644 --- a/src/main/java/cz/kamma/fabka/web/Pages.java +++ b/src/main/java/cz/kamma/fabka/web/Pages.java @@ -9,7 +9,6 @@ import java.util.Map; import java.util.stream.Collectors; import cz.kamma.fabka.repository.MysqlClientRepository; -import cz.kamma.fabka.repository.model.AttachmentData; import cz.kamma.fabka.repository.model.ForumAttachment; import cz.kamma.fabka.repository.model.ForumDetail; import cz.kamma.fabka.repository.model.ForumDisplayView; @@ -22,7 +21,7 @@ import cz.kamma.fabka.repository.model.PrivateMessageStats; import cz.kamma.fabka.repository.model.PrivateThreadRoot; import cz.kamma.fabka.repository.model.PrivateThreadSummary; import cz.kamma.fabka.repository.model.QuotedTextItem; -import cz.kamma.fabka.repository.model.UserIcon; +import cz.kamma.fabka.repository.model.SearchResultItem; public final class Pages { private static final String LOGIN_TEMPLATE = readTemplate("webapp/login.html"); @@ -532,6 +531,68 @@ public final class Pages { .replace("{{PAGE_LINKS}}", buildPageLinks(baseLink, currentPage, totalPages)); } + public static String searchResultsPage( + String username, + long currentUserId, + List results, + String searchText, + int loggedUsersCount, + List loggedUsers, + PrivateMessageStats pmStats + ) { + StringBuilder messageRows = new StringBuilder(); + if (results == null || results.isEmpty()) { + messageRows.append("
No message found.
"); + } else { + for (SearchResultItem result : results) { + messageRows.append("") + .append("") + .append("") + .append("") + .append("") + .append("
") + .append("
") + .append(formatTimestamp(result.getCreated())) + .append(" - ") + .append(escapeHtml(valueOrDefault(result.getForumName(), ""))).append("") + .append("
") + .append("") + .append("") + .append("") + .append("") + .append("") + .append("
 
") + .append("
Join Date: ").append(formatTimestamp(result.getCreatedua())).append("
") + .append("
Location: ").append(escapeHtml(valueOrDefault(result.getCity(), ""))).append("
") + .append("
") + .append("
") + .append(LegacyMessageFormatter.convertMessageToHtml(valueOrDefault(result.getText(), ""), null, null, null)) + .append("
\n"); + } + } + + String body = "" + + "" + + "kAmMa's Forum - Search Results" + + "" + + "" + + "" + + "" + + "" + + "
" + + "
" + + "

" + + renderCommonHeader(username, "Search Results", true, pmStats) + + "
" + + messageRows + + "
" + + renderCommonFooter(Math.max(0, loggedUsersCount), loggedUsers) + + "

" + + ""; + return body; + } + public static String mysqlClientPage( String username, List databases, @@ -908,7 +969,7 @@ public final class Pages { .replace("'", "'"); } - private static String readTemplate(String path) { + private static String readTemplate(String path) { try (InputStream in = Pages.class.getClassLoader().getResourceAsStream(path)) { if (in == null) { throw new IllegalStateException("Template not found: " + path); @@ -918,4 +979,13 @@ public final class Pages { throw new IllegalStateException("Failed to read template: " + path, ex); } } + + private static String formatTimestamp(java.sql.Timestamp ts) { + if (ts == null) { + return "N/A"; + } + java.time.ZoneId zone = java.time.ZoneId.of("Europe/Prague"); + java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"); + return ts.toLocalDateTime().atZone(zone).format(formatter); + } } diff --git a/src/main/resources/webapp/forum.html b/src/main/resources/webapp/forum.html index 70238c6..1d4b98a 100644 --- a/src/main/resources/webapp/forum.html +++ b/src/main/resources/webapp/forum.html @@ -17,7 +17,7 @@
-
+ Search in threads: