0
|
1 <%
|
|
2 package nabble.view.web.tools;
|
|
3
|
|
4 import com.google.gson.Gson;
|
|
5 import nabble.model.ModelHome;
|
|
6 import nabble.model.Node;
|
|
7 import nabble.model.Site;
|
|
8 import nabble.view.lib.Jtp;
|
|
9 import nabble.view.lib.Shared;
|
|
10
|
|
11 import javax.servlet.http.HttpServlet;
|
|
12 import javax.servlet.http.HttpServletRequest;
|
|
13 import javax.servlet.http.HttpServletResponse;
|
|
14 import java.io.IOException;
|
|
15 import java.io.InputStreamReader;
|
|
16 import java.io.PrintWriter;
|
|
17 import java.io.Reader;
|
|
18 import java.net.URL;
|
|
19 import java.net.URLEncoder;
|
|
20 import java.util.List;
|
|
21 import java.util.regex.Matcher;
|
|
22 import java.util.regex.Pattern;
|
|
23
|
|
24
|
|
25 public final class SpamSearch extends HttpServlet {
|
|
26
|
|
27 private static final String GOOGLE_URL = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&key=AIzaSyCjUKhbJVpU83CiRPJ1WV1x7WyszYSntC0&q=";
|
|
28 private static final String CHARSET = "UTF-8";
|
|
29
|
|
30 private static final Pattern POST_PTN = Pattern.compile("/.*-t(d\\d+)|((p\\d+)(p\\d+)?)\\.html$");
|
|
31
|
|
32 /**
|
|
33 * Defines five blocks per page because google usually returns a block with four results.
|
|
34 * So it shows 20 results per page.
|
|
35 */
|
|
36 private static final int BLOCKS_PER_PAGE = 6;
|
|
37
|
|
38 static String extractDomain(String url) {
|
|
39 int posDoubleSlash = url.indexOf("://");
|
|
40 if (posDoubleSlash == -1)
|
|
41 return null;
|
|
42 int posNextSlash = url.indexOf('/', posDoubleSlash+3);
|
|
43 return url.substring(posDoubleSlash+3, posNextSlash);
|
|
44 }
|
|
45
|
|
46 private static Long getPostId(String url) {
|
|
47 Matcher m = POST_PTN.matcher(url);
|
|
48 if (m.find()) {
|
|
49 if (m.group(4) != null)
|
|
50 return Long.valueOf(m.group(4).substring(1));
|
|
51 else if (m.group(3) != null)
|
|
52 return Long.valueOf(m.group(3).substring(1));
|
|
53 else if (m.group(1) != null)
|
|
54 return Long.valueOf(m.group(1).substring(1));
|
|
55 }
|
|
56 return null;
|
|
57 }
|
|
58
|
|
59 private static Long getSiteId(String domain) {
|
|
60 if (domain.endsWith(Jtp.getDefaultHost())) {
|
|
61 domain = domain.replace('.'+Jtp.getDefaultHost(), "");
|
|
62 int dot = domain.lastIndexOf('.');
|
|
63 return Long.valueOf(domain.substring(dot+1));
|
|
64 }
|
|
65 return null;
|
|
66 }
|
|
67
|
|
68 public void printResult(GoogleResults results, int j, PrintWriter out) {
|
|
69 if (results.getResponseData() != null) {
|
|
70 GoogleResults.Result result = results.getResponseData().getResults().get(j);
|
|
71 String url = result.getUrl();
|
|
72 String title = result.getTitle();
|
|
73 String content = result.getContent();
|
|
74
|
|
75 Long siteId = null;
|
|
76 Long postId = getPostId(url);
|
|
77 if (postId != null) {
|
|
78 String domain = extractDomain(url);
|
|
79 if (domain != null) {
|
|
80 siteId = getSiteId(domain);
|
|
81 siteId = siteId == null? ModelHome.getSiteIdFromDomain(domain) : siteId;
|
|
82 }
|
|
83 }
|
|
84 Site site = siteId == null? null : ModelHome.getSite(siteId);
|
|
85 Node node = site == null? null : site.getNode(postId);
|
|
86 %>
|
|
87 <% if (node != null && !node.getMessage().isDeleted()) { %>
|
|
88 <tr>
|
|
89 <td><input type="checkbox" class="checkBox" value="<%=siteId%>|<%=postId%>" name="results"/></td>
|
|
90 <td>
|
|
91 <a href="<%=url%>"><%=title%></a><br/>
|
|
92 <div class="clickable">
|
|
93 <span class='url'><%=url%></span><br/>
|
|
94 <%=content%><br/>
|
|
95 <% if (node.getDescendantCount() > 1) { %>
|
|
96 <span class="badge" style="font-weight:bold;background:red;color:white">Has Replies</span>
|
|
97 <% } %>
|
|
98 <% Node.MailToList mail = node.getMailToList(); %>
|
|
99 <% if (mail != null && mail.isPending()) { %>
|
|
100 <span class="badge" style="font-weight:bold;background:green;color:white">Pending</span>
|
|
101 <% } %>
|
|
102 </div>
|
|
103 </td>
|
|
104 </tr>
|
|
105 <% } else { %>
|
|
106 <tr>
|
|
107 <td></td>
|
|
108 <td class="grayP">
|
|
109 <a href='<%=url%>'><%=title%></a><br/>
|
|
110 <span class='url'><%=url%></span><br/>
|
|
111 <%=content%>
|
|
112 </td>
|
|
113 </tr>
|
|
114 <% } %>
|
|
115 <%
|
|
116 }
|
|
117 }
|
|
118
|
|
119 public void getResults(String query, String site,HttpServletRequest request,PrintWriter out)
|
|
120 throws IOException
|
|
121 {
|
|
122 int start = 0;
|
|
123 int page = 0;
|
|
124
|
|
125 if(request.getParameter("start") != null)
|
|
126 start = Integer.parseInt(request.getParameter("start"));
|
|
127
|
|
128 if(request.getParameter("page") != null)
|
|
129 page = Integer.parseInt(request.getParameter("page"));
|
|
130
|
|
131 if(!"".equals(query)) {
|
|
132 %>
|
|
133 <div>Page <%=page%></div>
|
|
134 <table>
|
|
135 <%
|
|
136 for (int k = 0; k < BLOCKS_PER_PAGE; k++) {
|
|
137 URL url = new URL(GOOGLE_URL+ URLEncoder.encode("site:"+site+" "+query, CHARSET)+"&start="+start );
|
|
138 Reader reader = new InputStreamReader(url.openStream(), CHARSET);
|
|
139 GoogleResults results = new Gson().fromJson(reader, GoogleResults.class);
|
|
140 if (results.getResponseData() != null) {
|
|
141 int block_size = results.getResponseData().getResults().size();
|
|
142 start += block_size;
|
|
143 for (int j = 0; j < block_size; j++) {
|
|
144 printResult(results,j,out);
|
|
145 }
|
|
146 }
|
|
147 }
|
|
148 %>
|
|
149 </table>
|
|
150 <br />
|
|
151 Page <%=page%> –
|
|
152 <a href='?start=<%=start%>&site=<%=site%>&query=<%=query%>&page=<%=(page+1)%>'>Next</a>
|
|
153 <br />
|
|
154 <br />
|
|
155 <input type="submit" value="Delete Selected Posts" />
|
|
156 <%
|
|
157 }
|
|
158 }
|
|
159
|
|
160
|
|
161 protected void service(HttpServletRequest request,HttpServletResponse response)
|
|
162 throws IOException
|
|
163 {
|
|
164 String query = request.getParameter("query");
|
|
165 query = query == null? "" : query;
|
|
166
|
|
167 String site = request.getParameter("site");
|
|
168 site = site == null? Jtp.getDefaultHost() : site;
|
|
169
|
|
170 boolean isDelete = "POST".equals(request.getMethod()) && "delete".equals(request.getParameter("action"));
|
|
171 int deleteCounter = 0;
|
|
172 if (isDelete) {
|
|
173 String[] results = request.getParameterValues("results");
|
|
174 for (String r : results) {
|
|
175 String[] parts = r.split("\\|");
|
|
176 long siteId = Long.valueOf(parts[0]);
|
|
177 long nodeId = Long.valueOf(parts[1]);
|
|
178 Node n = ModelHome.getSite(siteId).getNode(nodeId);
|
|
179 if (n != null) {
|
|
180 n.deleteMessageOrNode();
|
|
181 deleteCounter++;
|
|
182 }
|
|
183 }
|
|
184 }
|
|
185
|
|
186 PrintWriter out = response.getWriter();
|
|
187 %>
|
|
188 <html>
|
|
189 <head>
|
|
190 <title>Nabble Search</title>
|
|
191 <% Shared.loadJavascript(request, out); %>
|
|
192 <% javascript(out); %>
|
|
193 <% css(out); %>
|
|
194 </head>
|
|
195 <body>
|
|
196 <h1>Nabble Search</h1>
|
|
197 <form action="SpamSearch.jtp" method="get">
|
|
198 Search for <input type="text" name="query" value="<%=query%>" /> in <input type="text" name="site" value="<%=site%>" />
|
|
199 <input type="submit" value="Search" />
|
|
200 <input type="hidden" value="0" name="start" />
|
|
201 <input type="hidden" value="1" name="page" />
|
|
202 </form>
|
|
203 <% if (isDelete) { %>
|
|
204 <div style="color:red;padding:.5em 0">Deleted <%=deleteCounter%> nodes.</div>
|
|
205 <% } %>
|
|
206 <div id='results'>
|
|
207 <form action="SpamSearch.jtp" method="post">
|
|
208 <input type="hidden" value="delete" name="action" />
|
|
209 <input type="hidden" name="query" value="<%=query%>"/>
|
|
210 <input type="hidden" name="site" value="<%=site%>" />
|
|
211 <% getResults(query,site,request,out); %>
|
|
212 </form>
|
|
213 </div>
|
|
214 </body>
|
|
215 </html>
|
|
216 <%
|
|
217 }
|
|
218
|
|
219 private void javascript(PrintWriter out) {
|
|
220 %>
|
|
221 <script type="text/javascript">
|
|
222 $(document).ready(function() {
|
|
223 $('div.clickable').each(function() {
|
|
224 var $this = $(this);
|
|
225 var $checkbox = $this.parent().prev().children().eq(0);
|
|
226 $this.click(function() {
|
|
227 var checked = $checkbox.attr('checked');
|
|
228 if (checked) {
|
|
229 $this.removeClass('selected-row');
|
|
230 $checkbox.removeAttr('checked');
|
|
231 } else {
|
|
232 $this.addClass('selected-row');
|
|
233 $checkbox.attr('checked', true);
|
|
234 }
|
|
235 });
|
|
236 });
|
|
237 });
|
|
238 </script>
|
|
239 <%
|
|
240 }
|
|
241 private void css(PrintWriter out) {
|
|
242 %>
|
|
243 <style type="text/css">
|
|
244 body {
|
|
245 padding: 1em;
|
|
246 font-family: Verdana, Sans-serif;
|
|
247 font-size:.84em;
|
|
248 }
|
|
249 span.url{
|
|
250 color: green;
|
|
251 }
|
|
252 #results table {
|
|
253 width: 100%;
|
|
254 }
|
|
255 #results table td {
|
|
256 vertical-align:top;
|
|
257 padding-bottom: 1em;
|
|
258 }
|
|
259 #results td.grayP , td.grayP a , td.grayP span {
|
|
260 color: #C8C8C8 !important;
|
|
261 }
|
|
262 form input {
|
|
263 margin-bottom: 15px;
|
|
264 }
|
|
265 span.badge {
|
|
266 font-size:90%;
|
|
267 -moz-border-radius: 5px;
|
|
268 -webkit-border-radius: 5px;
|
|
269 border-radius: 5px;
|
|
270 padding: .2em .4em;
|
|
271 }
|
|
272 div.clickable { cursor:pointer; }
|
|
273 .selected-row { background:#ffffcc; }
|
|
274 </style>
|
|
275 <%
|
|
276 }
|
|
277 }
|
|
278
|
|
279
|
|
280 class GoogleResults {
|
|
281
|
|
282 private ResponseData responseData;
|
|
283 public ResponseData getResponseData() { return responseData; }
|
|
284 public void setResponseData(ResponseData responseData) { this.responseData = responseData; }
|
|
285 public String toString() { return "ResponseData[" + responseData + "]"; }
|
|
286
|
|
287 static class ResponseData {
|
|
288 private List<Result> results;
|
|
289 public List<Result> getResults() { return results; }
|
|
290 public void setResults(List<Result> results) { this.results = results; }
|
|
291 public String toString() { return "Results[" + results + "]"; }
|
|
292 }
|
|
293
|
|
294 static class Result {
|
|
295 private String url;
|
|
296 private String title;
|
|
297 private String content;
|
|
298 public String getUrl() { return url; }
|
|
299 public String getTitle() { return title; }
|
|
300 public String getContent() { return content; }
|
|
301 public void setUrl(String url) { this.url = url; }
|
|
302 public void setTitle(String title) { this.title = title; }
|
|
303 public String toString() { return "Result[url:" + url +",title:" + title + "]"; }
|
|
304 }
|
|
305 }
|
|
306
|
|
307
|
|
308 %> |