Mercurial Hosting > nabble
diff src/nabble/view/web/forum/SearchNamespace.java @ 0:7ecd1a4ef557
add content
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 21 Mar 2019 19:15:52 -0600 |
parents | |
children | 18cf4872fd7f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/nabble/view/web/forum/SearchNamespace.java Thu Mar 21 19:15:52 2019 -0600 @@ -0,0 +1,225 @@ +package nabble.view.web.forum; + +import fschmidt.util.java.DateUtils; +import fschmidt.util.servlet.ServletUtils; +import nabble.model.Lucene; +import nabble.model.Node; +import nabble.model.NodeSearcher; +import nabble.model.Person; +import nabble.model.User; +import nabble.naml.compiler.Command; +import nabble.naml.compiler.CommandSpec; +import nabble.naml.compiler.IPrintWriter; +import nabble.naml.compiler.Interpreter; +import nabble.naml.compiler.Namespace; +import nabble.naml.compiler.ScopedInterpreter; +import nabble.naml.namespaces.TemplateException; +import nabble.view.lib.Jtp; +import nabble.view.web.template.NabbleNamespace; +import nabble.view.web.template.NodeList; +import nabble.view.web.template.ServletNamespace; +import nabble.view.web.template.UserNamespace; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.search.Filter; + +import javax.servlet.ServletException; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Set; + + +@Namespace ( + name = "search", + global = true +) +public final class SearchNamespace { + private final Node node; + private String query; + private Person user; + private int days; + private int searchSize = 0; + private List<Node> posts = Collections.emptyList(); + public final NodeSearcher.Builder postQuery; + private NodeSearcher postSearcher; + private boolean hasQuery; + private boolean sortByDate; + private boolean didSearch = false; + private final ServletNamespace servletNs; + private boolean hasMore; + + public SearchNamespace(Node node,ServletNamespace servletNs) + throws ServletException + { + this.node = node; + this.servletNs = servletNs; + postQuery = new NodeSearcher.Builder(node); + User currentUser = Jtp.getUser(servletNs.request,servletNs.response); + postQuery.setCurrentUser(currentUser); + } + + public static final CommandSpec query_author = CommandSpec.NO_OUTPUT() + .dotParameter("author") + .build() + ; + + @Command public void query_author(IPrintWriter out,Interpreter interp) { + if( user != null ) + throw new RuntimeException("user already set"); + String userId = interp.getArgString("author"); + user = NabbleNamespace.current().site().getPerson(userId); + postQuery.addUser(user); + } + + public static final CommandSpec do_search = new CommandSpec.Builder() + .parameters("length") + .optionalParameters("query","days","start","sort") + .build() + ; + + @Command public void do_search(IPrintWriter out,Interpreter interp) + throws TemplateException, ServletException + { + query = interp.getArgString("query"); + days = interp.getArgAsInt("days",0); + + int start = interp.getArgAsInt("start",0); + int length = interp.getArgAsInt("length"); + Date startDate = days==0 ? null : DateUtils.addDays(new Date(), -days); + + hasQuery = query != null && query.length() > 0; + sortByDate = hasQuery ? "date".equals(interp.getArgString("sort")) : true; + + try { + postQuery.addLine(query); + } catch(ParseException e) { + throw TemplateException.newInstance("search_query_parse_error",e); + } + postQuery.addNodeKind(Node.Kind.POST); + if (days != 0) { + Filter filter = Lucene.getCachedFilter(Lucene.getRangeFilter(startDate, null)); + postQuery.setFilter(filter); + } + if (sortByDate) { + postQuery.setSort(NodeSearcher.SORT_BY_DATE); + postQuery.setDateRange(startDate, null); + } + postSearcher = postQuery.build(); + try { + posts = postSearcher.getNodes(start, length); + searchSize = postSearcher.getTotalHits(); + } catch(NodeSearcher.TooManyClauses e) { + throw TemplateException.newInstance("too_many_search_clauses",e); + } + hasMore = start + posts.size() < searchSize; + didSearch = true; + } + + public static final CommandSpec _user = CommandSpec.DO; + + @Command("user") public void _user(IPrintWriter out,ScopedInterpreter<UserNamespace> interp) + { + UserNamespace userNs = new UserNamespace(user); + out.print( interp.getArg(userNs,"do") ); + } + + @Command("days") public void _days(IPrintWriter out,Interpreter interp) { + out.print(days); + } + + @Command public void has_days(IPrintWriter out,Interpreter interp) { + out.print( days > 0 ); + } + + @Command public void total_posts(IPrintWriter out,Interpreter interp) { + out.print(searchSize); + } + + @Command public void has_results(IPrintWriter out,Interpreter interp) { + out.print( searchSize > 0 ); + } + + public static final CommandSpec highlight = CommandSpec.TEXT; + + @Command public void highlight(IPrintWriter out,Interpreter interp) { + String text = interp.getArgString("text"); + out.print( postSearcher.highlight(text,"<b>","</b>") ); + } + + public static final CommandSpec results = CommandSpec.DO; + + @Command public void results(IPrintWriter out,ScopedInterpreter<NodeList> interp) { + NodeList seq = new NodeList(posts,node,hasMore); + out.print( interp.getArg(seq,"do") ); + } + + @Command public void has_resort(IPrintWriter out,Interpreter interp) { + out.print( hasQuery && searchSize > 1 ); + } + + @Command public void has_query(IPrintWriter out,Interpreter interp) { + out.print( hasQuery ); + } + + @Command public void sorted_by_date(IPrintWriter out,Interpreter interp) { + out.print( sortByDate ); + } + + @Command public void search_terms(IPrintWriter out,Interpreter interp) { + out.print( concatTerms(postSearcher.getSearchTerms()) ); + } + + private static String concatTerms(Set<String> searchTerms) { + StringBuilder buf = new StringBuilder(); + for( String s : searchTerms ) { + if (buf.length() > 0) buf.append('|'); + buf.append(s.replaceAll("\\p{Punct}", "\\\\$0")); + } + return buf.toString(); + } + + public static final CommandSpec fragment = new CommandSpec.Builder() + .dotParameter("text") + .parameters("size") + .build() + ; + + @Command public void fragment(IPrintWriter out,Interpreter interp) { + String text = interp.getArgString("text"); + String size = interp.getArgString("size"); + int n; + try { + n = Integer.valueOf(size); + } catch (NumberFormatException e) { + throw new RuntimeException("Invalid \"size\" attribute: " + size); + } + out.print( Jtp.hideNull(postSearcher.getFragment(text, n, "...")) ); + } + + @Command public void descendants_ids_matching_search_query(IPrintWriter out, Interpreter interp) + throws TemplateException + { + String query = ServletUtils.getCookieValue(servletNs.request,"query"); + String searchUserId = ServletUtils.getCookieValue(servletNs.request, "searchuser"); + if ((query != null && !"".equals(query)) || searchUserId != null) { + try { + NodeSearcher.Builder luceneQuery = new NodeSearcher.Builder(NabbleNamespace.current().site(),node.getId()); + luceneQuery.addLine(query); + luceneQuery.addNodeKind(Node.Kind.POST); + if( searchUserId != null && !"".equals(searchUserId) ) + luceneQuery.addUser(searchUserId); + + final StringBuilder builder = new StringBuilder(); + luceneQuery.build().forEach(new NodeSearcher.Handler(){ + public void handle(long nodeId) { + if (builder.length() > 0) + builder.append(','); + builder.append(nodeId); + } + }); + out.print(builder.toString()); + } catch (ParseException e) {} // ignore bad queries + } + } + +}