0
|
1 package nabble.view.web.forum;
|
|
2
|
|
3 import fschmidt.util.java.DateUtils;
|
|
4 import fschmidt.util.servlet.ServletUtils;
|
|
5 import nabble.model.Lucene;
|
|
6 import nabble.model.Node;
|
|
7 import nabble.model.NodeSearcher;
|
|
8 import nabble.model.Person;
|
|
9 import nabble.model.User;
|
|
10 import nabble.naml.compiler.Command;
|
|
11 import nabble.naml.compiler.CommandSpec;
|
|
12 import nabble.naml.compiler.IPrintWriter;
|
|
13 import nabble.naml.compiler.Interpreter;
|
|
14 import nabble.naml.compiler.Namespace;
|
|
15 import nabble.naml.compiler.ScopedInterpreter;
|
|
16 import nabble.naml.namespaces.TemplateException;
|
|
17 import nabble.view.lib.Jtp;
|
|
18 import nabble.view.web.template.NabbleNamespace;
|
|
19 import nabble.view.web.template.NodeList;
|
|
20 import nabble.view.web.template.ServletNamespace;
|
|
21 import nabble.view.web.template.UserNamespace;
|
|
22 import org.apache.lucene.queryParser.ParseException;
|
|
23 import org.apache.lucene.search.Filter;
|
|
24
|
|
25 import javax.servlet.ServletException;
|
|
26 import java.util.Collections;
|
|
27 import java.util.Date;
|
|
28 import java.util.List;
|
|
29 import java.util.Set;
|
|
30
|
|
31
|
|
32 @Namespace (
|
|
33 name = "search",
|
|
34 global = true
|
|
35 )
|
|
36 public final class SearchNamespace {
|
|
37 private final Node node;
|
|
38 private String query;
|
|
39 private Person user;
|
|
40 private int days;
|
|
41 private int searchSize = 0;
|
|
42 private List<Node> posts = Collections.emptyList();
|
|
43 public final NodeSearcher.Builder postQuery;
|
|
44 private NodeSearcher postSearcher;
|
|
45 private boolean hasQuery;
|
|
46 private boolean sortByDate;
|
|
47 private boolean didSearch = false;
|
|
48 private final ServletNamespace servletNs;
|
|
49 private boolean hasMore;
|
|
50
|
|
51 public SearchNamespace(Node node,ServletNamespace servletNs)
|
|
52 throws ServletException
|
|
53 {
|
|
54 this.node = node;
|
|
55 this.servletNs = servletNs;
|
|
56 postQuery = new NodeSearcher.Builder(node);
|
|
57 User currentUser = Jtp.getUser(servletNs.request,servletNs.response);
|
|
58 postQuery.setCurrentUser(currentUser);
|
|
59 }
|
|
60
|
|
61 public static final CommandSpec query_author = CommandSpec.NO_OUTPUT()
|
|
62 .dotParameter("author")
|
|
63 .build()
|
|
64 ;
|
|
65
|
|
66 @Command public void query_author(IPrintWriter out,Interpreter interp) {
|
|
67 if( user != null )
|
|
68 throw new RuntimeException("user already set");
|
|
69 String userId = interp.getArgString("author");
|
|
70 user = NabbleNamespace.current().site().getPerson(userId);
|
|
71 postQuery.addUser(user);
|
|
72 }
|
|
73
|
|
74 public static final CommandSpec do_search = new CommandSpec.Builder()
|
|
75 .parameters("length")
|
|
76 .optionalParameters("query","days","start","sort")
|
|
77 .build()
|
|
78 ;
|
|
79
|
|
80 @Command public void do_search(IPrintWriter out,Interpreter interp)
|
|
81 throws TemplateException, ServletException
|
|
82 {
|
|
83 query = interp.getArgString("query");
|
|
84 days = interp.getArgAsInt("days",0);
|
|
85
|
|
86 int start = interp.getArgAsInt("start",0);
|
|
87 int length = interp.getArgAsInt("length");
|
|
88 Date startDate = days==0 ? null : DateUtils.addDays(new Date(), -days);
|
|
89
|
|
90 hasQuery = query != null && query.length() > 0;
|
|
91 sortByDate = hasQuery ? "date".equals(interp.getArgString("sort")) : true;
|
|
92
|
|
93 try {
|
|
94 postQuery.addLine(query);
|
|
95 } catch(ParseException e) {
|
|
96 throw TemplateException.newInstance("search_query_parse_error",e);
|
|
97 }
|
|
98 postQuery.addNodeKind(Node.Kind.POST);
|
|
99 if (days != 0) {
|
|
100 Filter filter = Lucene.getCachedFilter(Lucene.getRangeFilter(startDate, null));
|
|
101 postQuery.setFilter(filter);
|
|
102 }
|
|
103 if (sortByDate) {
|
|
104 postQuery.setSort(NodeSearcher.SORT_BY_DATE);
|
|
105 postQuery.setDateRange(startDate, null);
|
|
106 }
|
|
107 postSearcher = postQuery.build();
|
|
108 try {
|
|
109 posts = postSearcher.getNodes(start, length);
|
|
110 searchSize = postSearcher.getTotalHits();
|
|
111 } catch(NodeSearcher.TooManyClauses e) {
|
|
112 throw TemplateException.newInstance("too_many_search_clauses",e);
|
|
113 }
|
|
114 hasMore = start + posts.size() < searchSize;
|
|
115 didSearch = true;
|
|
116 }
|
|
117
|
|
118 public static final CommandSpec _user = CommandSpec.DO;
|
|
119
|
|
120 @Command("user") public void _user(IPrintWriter out,ScopedInterpreter<UserNamespace> interp)
|
|
121 {
|
|
122 UserNamespace userNs = new UserNamespace(user);
|
|
123 out.print( interp.getArg(userNs,"do") );
|
|
124 }
|
|
125
|
|
126 @Command("days") public void _days(IPrintWriter out,Interpreter interp) {
|
|
127 out.print(days);
|
|
128 }
|
|
129
|
|
130 @Command public void has_days(IPrintWriter out,Interpreter interp) {
|
|
131 out.print( days > 0 );
|
|
132 }
|
|
133
|
|
134 @Command public void total_posts(IPrintWriter out,Interpreter interp) {
|
|
135 out.print(searchSize);
|
|
136 }
|
|
137
|
|
138 @Command public void has_results(IPrintWriter out,Interpreter interp) {
|
|
139 out.print( searchSize > 0 );
|
|
140 }
|
|
141
|
|
142 public static final CommandSpec highlight = CommandSpec.TEXT;
|
|
143
|
|
144 @Command public void highlight(IPrintWriter out,Interpreter interp) {
|
|
145 String text = interp.getArgString("text");
|
|
146 out.print( postSearcher.highlight(text,"<b>","</b>") );
|
|
147 }
|
|
148
|
|
149 public static final CommandSpec results = CommandSpec.DO;
|
|
150
|
|
151 @Command public void results(IPrintWriter out,ScopedInterpreter<NodeList> interp) {
|
|
152 NodeList seq = new NodeList(posts,node,hasMore);
|
|
153 out.print( interp.getArg(seq,"do") );
|
|
154 }
|
|
155
|
|
156 @Command public void has_resort(IPrintWriter out,Interpreter interp) {
|
|
157 out.print( hasQuery && searchSize > 1 );
|
|
158 }
|
|
159
|
|
160 @Command public void has_query(IPrintWriter out,Interpreter interp) {
|
|
161 out.print( hasQuery );
|
|
162 }
|
|
163
|
|
164 @Command public void sorted_by_date(IPrintWriter out,Interpreter interp) {
|
|
165 out.print( sortByDate );
|
|
166 }
|
|
167
|
|
168 @Command public void search_terms(IPrintWriter out,Interpreter interp) {
|
|
169 out.print( concatTerms(postSearcher.getSearchTerms()) );
|
|
170 }
|
|
171
|
|
172 private static String concatTerms(Set<String> searchTerms) {
|
|
173 StringBuilder buf = new StringBuilder();
|
|
174 for( String s : searchTerms ) {
|
|
175 if (buf.length() > 0) buf.append('|');
|
|
176 buf.append(s.replaceAll("\\p{Punct}", "\\\\$0"));
|
|
177 }
|
|
178 return buf.toString();
|
|
179 }
|
|
180
|
|
181 public static final CommandSpec fragment = new CommandSpec.Builder()
|
|
182 .dotParameter("text")
|
|
183 .parameters("size")
|
|
184 .build()
|
|
185 ;
|
|
186
|
|
187 @Command public void fragment(IPrintWriter out,Interpreter interp) {
|
|
188 String text = interp.getArgString("text");
|
|
189 String size = interp.getArgString("size");
|
|
190 int n;
|
|
191 try {
|
|
192 n = Integer.valueOf(size);
|
|
193 } catch (NumberFormatException e) {
|
|
194 throw new RuntimeException("Invalid \"size\" attribute: " + size);
|
|
195 }
|
|
196 out.print( Jtp.hideNull(postSearcher.getFragment(text, n, "...")) );
|
|
197 }
|
|
198
|
|
199 @Command public void descendants_ids_matching_search_query(IPrintWriter out, Interpreter interp)
|
|
200 throws TemplateException
|
|
201 {
|
|
202 String query = ServletUtils.getCookieValue(servletNs.request,"query");
|
|
203 String searchUserId = ServletUtils.getCookieValue(servletNs.request, "searchuser");
|
|
204 if ((query != null && !"".equals(query)) || searchUserId != null) {
|
|
205 try {
|
|
206 NodeSearcher.Builder luceneQuery = new NodeSearcher.Builder(NabbleNamespace.current().site(),node.getId());
|
|
207 luceneQuery.addLine(query);
|
|
208 luceneQuery.addNodeKind(Node.Kind.POST);
|
|
209 if( searchUserId != null && !"".equals(searchUserId) )
|
|
210 luceneQuery.addUser(searchUserId);
|
|
211
|
|
212 final StringBuilder builder = new StringBuilder();
|
|
213 luceneQuery.build().forEach(new NodeSearcher.Handler(){
|
|
214 public void handle(long nodeId) {
|
|
215 if (builder.length() > 0)
|
|
216 builder.append(',');
|
|
217 builder.append(nodeId);
|
|
218 }
|
|
219 });
|
|
220 out.print(builder.toString());
|
|
221 } catch (ParseException e) {} // ignore bad queries
|
|
222 }
|
|
223 }
|
|
224
|
|
225 }
|