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
+		}
+	}
+
+}