diff src/nabble/view/web/tools/SpamSearch.jtp @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children 72765b66e2c3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/nabble/view/web/tools/SpamSearch.jtp	Thu Mar 21 19:15:52 2019 -0600
@@ -0,0 +1,308 @@
+<%
+package nabble.view.web.tools;
+
+import com.google.gson.Gson;
+import nabble.model.ModelHome;
+import nabble.model.Node;
+import nabble.model.Site;
+import nabble.view.lib.Jtp;
+import nabble.view.lib.Shared;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public final class SpamSearch extends HttpServlet {
+
+	private static final String GOOGLE_URL = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&key=AIzaSyCjUKhbJVpU83CiRPJ1WV1x7WyszYSntC0&q=";
+    private static final String CHARSET = "UTF-8";
+
+	private static final Pattern POST_PTN = Pattern.compile("/.*-t(d\\d+)|((p\\d+)(p\\d+)?)\\.html$");
+
+	/**
+	 * Defines five blocks per page because google usually returns a block with four results.
+	 * So it shows 20 results per page.
+	*/
+	private static final int BLOCKS_PER_PAGE = 6;
+
+	static String extractDomain(String url) {
+		int posDoubleSlash = url.indexOf("://");
+		if (posDoubleSlash == -1)
+			return null;
+		int posNextSlash = url.indexOf('/', posDoubleSlash+3);
+		return url.substring(posDoubleSlash+3, posNextSlash);
+	}
+
+	private static Long getPostId(String url) {
+		Matcher m = POST_PTN.matcher(url);
+		if (m.find()) {
+			if (m.group(4) != null)
+				return Long.valueOf(m.group(4).substring(1));
+			else if (m.group(3) != null)
+				return Long.valueOf(m.group(3).substring(1));
+			else if (m.group(1) != null)
+				return Long.valueOf(m.group(1).substring(1));
+		}
+		return null;
+	}
+
+	private static Long getSiteId(String domain) {
+		if (domain.endsWith(Jtp.getDefaultHost())) {
+			domain = domain.replace('.'+Jtp.getDefaultHost(), "");
+			int dot = domain.lastIndexOf('.');
+			return Long.valueOf(domain.substring(dot+1));
+		}
+		return null;
+	}
+
+	public void printResult(GoogleResults results, int j, PrintWriter out) {
+		if (results.getResponseData() != null) {
+			GoogleResults.Result result = results.getResponseData().getResults().get(j);
+			String url = result.getUrl();
+			String title = result.getTitle();
+			String content = result.getContent();
+
+			Long siteId = null;
+			Long postId = getPostId(url);
+			if (postId != null) {
+				String domain = extractDomain(url);
+				if (domain != null) {
+					siteId = getSiteId(domain);
+					siteId = siteId == null? ModelHome.getSiteIdFromDomain(domain) : siteId;
+				}
+			}
+			Site site = siteId == null? null : ModelHome.getSite(siteId);
+			Node node = site == null? null : site.getNode(postId);
+			%>
+			<% if (node != null && !node.getMessage().isDeleted()) { %>
+				<tr>
+					<td><input type="checkbox" class="checkBox" value="<%=siteId%>|<%=postId%>" name="results"/></td>
+					<td>
+						<a href="<%=url%>"><%=title%></a><br/>
+						<div class="clickable">
+							<span class='url'><%=url%></span><br/>
+							<%=content%><br/>
+							<% if (node.getDescendantCount() > 1) { %>
+								<span class="badge" style="font-weight:bold;background:red;color:white">Has Replies</span>
+							<% } %>
+							<% Node.MailToList mail = node.getMailToList(); %>
+							<% if (mail != null && mail.isPending()) { %>
+								<span class="badge" style="font-weight:bold;background:green;color:white">Pending</span>
+							<% } %>
+						</div>
+					</td>
+				</tr>
+			<% } else { %>
+				<tr>
+					<td></td>
+					<td class="grayP">
+						<a href='<%=url%>'><%=title%></a><br/>
+						<span class='url'><%=url%></span><br/>
+						<%=content%>
+					</td>
+				</tr>
+			<% } %>
+		<%
+		}
+	}
+
+	public void getResults(String query, String site,HttpServletRequest request,PrintWriter out)
+		throws IOException
+	{
+		int start = 0;
+		int page = 0;
+
+		if(request.getParameter("start") != null)
+			start = Integer.parseInt(request.getParameter("start"));
+
+		if(request.getParameter("page") != null)
+			page = Integer.parseInt(request.getParameter("page"));
+
+		if(!"".equals(query)) {
+			%>
+			<div>Page <%=page%></div>
+			<table>
+			<%
+			for (int k = 0; k < BLOCKS_PER_PAGE; k++) {
+				URL url = new URL(GOOGLE_URL+ URLEncoder.encode("site:"+site+" "+query, CHARSET)+"&start="+start );
+				Reader reader = new InputStreamReader(url.openStream(), CHARSET);
+				GoogleResults results = new Gson().fromJson(reader, GoogleResults.class);
+				if (results.getResponseData() != null) {
+					int block_size = results.getResponseData().getResults().size();
+					start += block_size;
+					for (int j = 0; j < block_size; j++) {
+							printResult(results,j,out);
+					}
+				}
+			}
+			%>
+			</table>
+			<br />
+			Page <%=page%> &ndash;
+			<a href='?start=<%=start%>&site=<%=site%>&query=<%=query%>&page=<%=(page+1)%>'>Next</a>
+			<br />
+			<br />
+			<input type="submit" value="Delete Selected Posts" />
+			<%
+		}
+	}
+
+
+	protected void service(HttpServletRequest request,HttpServletResponse response)
+		throws IOException
+	{
+		String query = request.getParameter("query");
+		query = query == null? "" : query;
+
+		String site = request.getParameter("site");
+		site = site == null? Jtp.getDefaultHost() : site;
+
+		boolean isDelete = "POST".equals(request.getMethod()) && "delete".equals(request.getParameter("action"));
+		int deleteCounter = 0;
+		if (isDelete) {
+			String[] results = request.getParameterValues("results");
+			for (String r : results) {
+				String[] parts = r.split("\\|");
+				long siteId = Long.valueOf(parts[0]);
+				long nodeId = Long.valueOf(parts[1]);
+				Node n = ModelHome.getSite(siteId).getNode(nodeId);
+				if (n != null) {
+					n.deleteMessageOrNode();
+					deleteCounter++;
+				}
+			}
+		}
+
+		PrintWriter out = response.getWriter();
+		%>
+		<html>
+			<head>
+				<title>Nabble Search</title>
+				<% Shared.loadJavascript(request, out); %>
+				<% javascript(out); %>
+				<% css(out); %>
+			</head>
+			<body>
+				<h1>Nabble Search</h1>
+				<form action="SpamSearch.jtp" method="get">
+					Search for <input type="text" name="query" value="<%=query%>" /> in <input type="text" name="site" value="<%=site%>" />
+					<input type="submit" value="Search" />
+					<input type="hidden" value="0" name="start" />
+					<input type="hidden" value="1" name="page" />
+				</form>
+				<% if (isDelete) { %>
+				<div style="color:red;padding:.5em 0">Deleted <%=deleteCounter%> nodes.</div>
+				<% } %>
+				<div id='results'>
+					<form action="SpamSearch.jtp" method="post">
+						<input type="hidden" value="delete" name="action" />
+						<input type="hidden" name="query" value="<%=query%>"/>
+						<input type="hidden" name="site" value="<%=site%>" />
+						<% getResults(query,site,request,out); %>
+					</form>
+				</div>
+			</body>
+		</html>
+		<%
+	}
+
+	private void javascript(PrintWriter out) {
+		%>
+			<script type="text/javascript">
+				$(document).ready(function() {
+					$('div.clickable').each(function() {
+						var $this = $(this);
+						var $checkbox = $this.parent().prev().children().eq(0);
+						$this.click(function() {
+							var checked = $checkbox.attr('checked');
+							if (checked) {
+								$this.removeClass('selected-row');
+								$checkbox.removeAttr('checked');
+							} else {
+								$this.addClass('selected-row');
+								$checkbox.attr('checked', true);
+							}
+						});
+					});
+				});
+			</script>
+		<%
+	}
+	private void css(PrintWriter out) {
+		%>
+		<style type="text/css">
+			body {
+				padding: 1em;
+				font-family: Verdana, Sans-serif;
+				font-size:.84em;
+			}
+			span.url{
+				color: green;
+			}
+			#results table {
+				width: 100%;
+			}
+			#results table td {
+				vertical-align:top;
+				padding-bottom: 1em;
+			}
+			#results td.grayP , td.grayP a , td.grayP span {
+				color: #C8C8C8 !important;
+			}
+			form input {
+				margin-bottom: 15px;
+			}
+			span.badge {
+				font-size:90%;
+				-moz-border-radius: 5px;
+				-webkit-border-radius: 5px;
+				border-radius: 5px;
+				padding: .2em .4em;
+			}
+			div.clickable { cursor:pointer; }
+			.selected-row { background:#ffffcc; }
+		</style>
+		<%
+	}
+}
+
+
+class GoogleResults {
+
+    private ResponseData responseData;
+    public ResponseData getResponseData() { return responseData; }
+    public void setResponseData(ResponseData responseData) { this.responseData = responseData; }
+    public String toString() { return "ResponseData[" + responseData + "]"; }
+
+    static class ResponseData {
+        private List<Result> results;
+        public List<Result> getResults() { return results; }
+        public void setResults(List<Result> results) { this.results = results; }
+        public String toString() { return "Results[" + results + "]"; }
+    }
+
+    static class Result {
+        private String url;
+        private String title;
+        private String content;
+        public String getUrl() { return url; }
+        public String getTitle() { return title; }
+        public String getContent() { return content; }
+        public void setUrl(String url) { this.url = url; }
+        public void setTitle(String title) { this.title = title; }
+        public String toString() { return "Result[url:" + url +",title:" + title + "]"; }
+    }
+}
+
+
+%>
\ No newline at end of file