view src/nabble/view/web/forum/SearchNamespace.java @ 19:18cf4872fd7f

remove anonymous posting
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 29 May 2020 22:58:25 -0600
parents 7ecd1a4ef557
children
line wrap: on
line source

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);
		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
		}
	}

}