global search fixed
This commit is contained in:
parent
c98befaf26
commit
56deb56c72
@ -44,6 +44,7 @@ import cz.kamma.fabka.repository.model.PrivateMessageStats;
|
|||||||
import cz.kamma.fabka.repository.model.PrivateThreadRoot;
|
import cz.kamma.fabka.repository.model.PrivateThreadRoot;
|
||||||
import cz.kamma.fabka.repository.model.PrivateThreadSummary;
|
import cz.kamma.fabka.repository.model.PrivateThreadSummary;
|
||||||
import cz.kamma.fabka.repository.model.QuotedTextItem;
|
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.SettingsRepository;
|
||||||
import cz.kamma.fabka.repository.model.UserIcon;
|
import cz.kamma.fabka.repository.model.UserIcon;
|
||||||
import cz.kamma.fabka.repository.UserIconRepository;
|
import cz.kamma.fabka.repository.UserIconRepository;
|
||||||
@ -150,6 +151,48 @@ public class HttpServerApplication {
|
|||||||
boolean showError = "1".equals(ctx.queryParam("error"));
|
boolean showError = "1".equals(ctx.queryParam("error"));
|
||||||
Responses.html(ctx.exchange(), 200, Pages.loginPage(showError));
|
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<SearchResultItem> results = forumRepository.searchMessages(userId, searchText, forumId);
|
||||||
|
|
||||||
|
int loggedUsersCount = sessionManager.countSessionsWithAttribute(AUTH_USER_KEY);
|
||||||
|
List<String> 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("/chat.jsp", ctx -> Responses.redirect(ctx.exchange(), "/chat"));
|
||||||
router.get("/private.jsp", ctx -> {
|
router.get("/private.jsp", ctx -> {
|
||||||
String oBy = ctx.queryParam("oBy");
|
String oBy = ctx.queryParam("oBy");
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import cz.kamma.fabka.repository.model.ForumDetail;
|
|||||||
import cz.kamma.fabka.repository.model.ForumMessage;
|
import cz.kamma.fabka.repository.model.ForumMessage;
|
||||||
import cz.kamma.fabka.repository.model.ForumSummary;
|
import cz.kamma.fabka.repository.model.ForumSummary;
|
||||||
import cz.kamma.fabka.repository.model.QuotedTextItem;
|
import cz.kamma.fabka.repository.model.QuotedTextItem;
|
||||||
|
import cz.kamma.fabka.repository.model.SearchResultItem;
|
||||||
import cz.kamma.fabka.repository.model.VoteStats;
|
import cz.kamma.fabka.repository.model.VoteStats;
|
||||||
|
|
||||||
public class ForumRepository {
|
public class ForumRepository {
|
||||||
@ -282,6 +283,7 @@ public class ForumRepository {
|
|||||||
|
|
||||||
out.add(new ForumMessage(
|
out.add(new ForumMessage(
|
||||||
messageId,
|
messageId,
|
||||||
|
forumId,
|
||||||
authorIds.get(i),
|
authorIds.get(i),
|
||||||
valueOrDefault(usernames.get(i), "N/A"),
|
valueOrDefault(usernames.get(i), "N/A"),
|
||||||
formatTs(createdTimes.get(i)),
|
formatTs(createdTimes.get(i)),
|
||||||
@ -678,6 +680,50 @@ public class ForumRepository {
|
|||||||
return value == null || value.isBlank() ? defaultValue : value;
|
return value == null || value.isBlank() ? defaultValue : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SearchResultItem> searchMessages(long userId, String searchText, long forumId) {
|
||||||
|
List<SearchResultItem> 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) {
|
private static String formatTs(Timestamp ts) {
|
||||||
if (ts == null) {
|
if (ts == null) {
|
||||||
return "N/A";
|
return "N/A";
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import java.util.List;
|
|||||||
|
|
||||||
public class ForumMessage {
|
public class ForumMessage {
|
||||||
private final long id;
|
private final long id;
|
||||||
|
private final long forumId;
|
||||||
private final long authorId;
|
private final long authorId;
|
||||||
private final String author;
|
private final String author;
|
||||||
private final String authorJoinDate;
|
private final String authorJoinDate;
|
||||||
@ -19,11 +20,12 @@ public class ForumMessage {
|
|||||||
private final QuotedTextItem quotedItem;
|
private final QuotedTextItem quotedItem;
|
||||||
private final String createdAt;
|
private final String createdAt;
|
||||||
private final String text;
|
private final String text;
|
||||||
private final List<ForumAttachment> attachments;
|
private List<ForumAttachment> attachments;
|
||||||
private final boolean sticky;
|
private final boolean sticky;
|
||||||
|
|
||||||
public ForumMessage(
|
public ForumMessage(
|
||||||
long id,
|
long id,
|
||||||
|
long forumId,
|
||||||
long authorId,
|
long authorId,
|
||||||
String author,
|
String author,
|
||||||
String authorJoinDate,
|
String authorJoinDate,
|
||||||
@ -43,6 +45,7 @@ public class ForumMessage {
|
|||||||
boolean sticky
|
boolean sticky
|
||||||
) {
|
) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.forumId = forumId;
|
||||||
this.authorId = authorId;
|
this.authorId = authorId;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
this.authorJoinDate = authorJoinDate;
|
this.authorJoinDate = authorJoinDate;
|
||||||
@ -133,4 +136,12 @@ public class ForumMessage {
|
|||||||
public boolean isSticky() {
|
public boolean isSticky() {
|
||||||
return sticky;
|
return sticky;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getForumId() {
|
||||||
|
return forumId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachments(List<ForumAttachment> attachments) {
|
||||||
|
this.attachments = attachments;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,6 @@ import java.util.Map;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import cz.kamma.fabka.repository.MysqlClientRepository;
|
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.ForumAttachment;
|
||||||
import cz.kamma.fabka.repository.model.ForumDetail;
|
import cz.kamma.fabka.repository.model.ForumDetail;
|
||||||
import cz.kamma.fabka.repository.model.ForumDisplayView;
|
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.PrivateThreadRoot;
|
||||||
import cz.kamma.fabka.repository.model.PrivateThreadSummary;
|
import cz.kamma.fabka.repository.model.PrivateThreadSummary;
|
||||||
import cz.kamma.fabka.repository.model.QuotedTextItem;
|
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 {
|
public final class Pages {
|
||||||
private static final String LOGIN_TEMPLATE = readTemplate("webapp/login.html");
|
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));
|
.replace("{{PAGE_LINKS}}", buildPageLinks(baseLink, currentPage, totalPages));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String searchResultsPage(
|
||||||
|
String username,
|
||||||
|
long currentUserId,
|
||||||
|
List<SearchResultItem> results,
|
||||||
|
String searchText,
|
||||||
|
int loggedUsersCount,
|
||||||
|
List<String> loggedUsers,
|
||||||
|
PrivateMessageStats pmStats
|
||||||
|
) {
|
||||||
|
StringBuilder messageRows = new StringBuilder();
|
||||||
|
if (results == null || results.isEmpty()) {
|
||||||
|
messageRows.append("<div style='color:red'>No message found.</div>");
|
||||||
|
} else {
|
||||||
|
for (SearchResultItem result : results) {
|
||||||
|
messageRows.append("<table class='tborder' cellpadding='6' cellspacing='1' border='0' width='100%' align='center'>")
|
||||||
|
.append("<tbody>")
|
||||||
|
.append("<tr><td class='thead'>")
|
||||||
|
.append("<div class='normal'>")
|
||||||
|
.append(formatTimestamp(result.getCreated()))
|
||||||
|
.append(" - <a href='/forumdisplay?f=").append(result.getForumId()).append("'>")
|
||||||
|
.append(escapeHtml(valueOrDefault(result.getForumName(), ""))).append("</a>")
|
||||||
|
.append("</div></td></tr>")
|
||||||
|
.append("<tr><td class='alt2' style='padding:0'>")
|
||||||
|
.append("<table cellpadding='0' cellspacing='6' border='0' width='100%'><tbody><tr>")
|
||||||
|
.append("<td valign='middle' nowrap='nowrap'><img src='/process/showimage?userIcon=yes&uid=").append(result.getCreatedBy()).append("' width='80'/></td>")
|
||||||
|
.append("<td valign='middle' nowrap='nowrap'><div style='color: blue; font-weight:bold'><a href='#'>")
|
||||||
|
.append(escapeHtml(result.getUsername())).append("</a></div></td>")
|
||||||
|
.append("<td width='100%'> </td>")
|
||||||
|
.append("<td valign='top' nowrap='nowrap'><div class='smallfont'>")
|
||||||
|
.append("<div>Join Date: ").append(formatTimestamp(result.getCreatedua())).append("</div>")
|
||||||
|
.append("<div>Location: ").append(escapeHtml(valueOrDefault(result.getCity(), ""))).append("</div>")
|
||||||
|
.append("</div></td>")
|
||||||
|
.append("</tr></tbody></table>")
|
||||||
|
.append("</td></tr>")
|
||||||
|
.append("<tr><td class='alt1'><div>")
|
||||||
|
.append(LegacyMessageFormatter.convertMessageToHtml(valueOrDefault(result.getText(), ""), null, null, null))
|
||||||
|
.append("</div></td></tr>")
|
||||||
|
.append("</tbody></table>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String body = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
|
||||||
|
+ "<html xmlns='http://www.w3.org/1999/xhtml' dir='ltr' lang='en'><head>"
|
||||||
|
+ "<title>kAmMa's Forum - Search Results</title>"
|
||||||
|
+ "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>"
|
||||||
|
+ "<meta http-equiv='Expires' content='0'/>"
|
||||||
|
+ "<link rel='stylesheet' type='text/css' href='./css/all.css'/>"
|
||||||
|
+ "<script type='text/javascript' src='/client.js'></script>"
|
||||||
|
+ "</head><body>"
|
||||||
|
+ "<div align='center'>"
|
||||||
|
+ "<div class='page' style='width: 100%; text-align: left'>"
|
||||||
|
+ "<div style='padding: 0px 25px 0px 25px' align='left'><br/>"
|
||||||
|
+ renderCommonHeader(username, "Search Results", true, pmStats)
|
||||||
|
+ "<br/>"
|
||||||
|
+ messageRows
|
||||||
|
+ "<br/>"
|
||||||
|
+ renderCommonFooter(Math.max(0, loggedUsersCount), loggedUsers)
|
||||||
|
+ "</div></div></div><br/>"
|
||||||
|
+ "</body></html>";
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
public static String mysqlClientPage(
|
public static String mysqlClientPage(
|
||||||
String username,
|
String username,
|
||||||
List<String> databases,
|
List<String> databases,
|
||||||
@ -918,4 +979,13 @@ public final class Pages {
|
|||||||
throw new IllegalStateException("Failed to read template: " + path, ex);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
<table class='tborder' cellpadding='3' cellspacing='1' border='0'>
|
<table class='tborder' cellpadding='3' cellspacing='1' border='0'>
|
||||||
<tbody><tr>
|
<tbody><tr>
|
||||||
<td class='vbmenu_control' style='font-weight:normal'>
|
<td class='vbmenu_control' style='font-weight:normal'>
|
||||||
<form action='#' method='post'>
|
<form action='/search' method='get'>
|
||||||
Search in threads:
|
Search in threads:
|
||||||
<input type='text' class='bginput' style='font-size:11px' name='stext' tabindex='1'/>
|
<input type='text' class='bginput' style='font-size:11px' name='stext' tabindex='1'/>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user