/* This file is part of OpenMyEWB. OpenMyEWB is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenMyEWB is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMyEWB. If not, see <http://www.gnu.org/licenses/>. OpenMyEWB is Copyright 2005-2009 Nicolas Kruchten (nicolas@kruchten.com), Francis Kung, Engineers Without Borders Canada, Michael Trauttmansdorff, Jon Fishbein, David Kadish */ package ca.myewb.controllers.home; import java.math.BigInteger; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import org.apache.velocity.context.Context; import org.hibernate.Hibernate; import org.hibernate.Query; import ca.myewb.frame.Controller; import ca.myewb.frame.Permissions; import ca.myewb.frame.PostParamWrapper; import ca.myewb.frame.RedirectionException; import ca.myewb.frame.forms.SearchForm; import ca.myewb.model.EventModel; import ca.myewb.model.GroupModel; import ca.myewb.model.PostModel; import ca.myewb.model.WhiteboardModel; public class Search extends Controller { private String[] types = {"Posts", "Events", "Whiteboards"}; public void handle(Context ctx) throws Exception { if ((requestParams.get("Body") != null) && !requestParams.get("Body").equals("")) { throw new RedirectionException(path + "/home/Search/" + encode(requestParams)); } urlParams.processParams(new String[]{"filter", "pagenum"}, new String[]{"", "1"}); HashMap<String, String> terms = decode(urlParams.get("filter")); if(terms.get("Body").equals("")) { ctx.put("noterms", true); } else { ctx.put("noterms", false); int pagesize = 30; int start = 1; try { start = new Integer(urlParams.get("pagenum")).intValue(); } catch (Exception e) { start = 1; } if (start < 1) { start = 1; } int pageStart = (start - 1) * pagesize; int numSearchables = numMatchingSearchables(terms); ctx.put("searchables", matchingSearchables(terms, pageStart, pagesize)); int numPages = (numSearchables / pagesize); if ((numSearchables % pagesize) != 0) { numPages++; } ctx.put("pageNum", new Integer(start)); ctx.put("pageSize", new Integer(pagesize)); ctx.put("numPages", new Integer(numPages)); ctx.put("filterParam", urlParams.get("filter")); ctx.put("numSearchables", new Integer(numSearchables)); } ctx.put("form", new SearchForm(path + "/home/Search/", terms)); } private List matchingSearchables(HashMap<String, String> terms, int pageStart, int pagesize) { String sql = "select parentPost, parentEvent, parentWhiteboard " + getCommonQueryPart(terms) + " limit :start, :limit"; Query query = hibernateSession.createSQLQuery(sql) .addScalar("parentPost", Hibernate.INTEGER) .addScalar("parentEvent", Hibernate.INTEGER) .addScalar("parentWhiteboard", Hibernate.INTEGER) .setString("terms", terms.get("Body")) .setInteger("start", pageStart) .setInteger("limit", pagesize); if(!terms.get("Since").equals("")) query.setString("since", terms.get("Since")); List searchableIDs = query.list(); Vector<Object> searchables = new Vector<Object>(); for (Object temp : searchableIDs) { Object[] idArray = (Object[])temp; Integer parentPostId = (Integer)idArray[0]; Integer parentEventId = (Integer)idArray[1]; Integer parentWhiteboardId = (Integer)idArray[2]; if(parentPostId != null) { searchables.add(hibernateSession.load(PostModel.class, parentPostId)); } else if(parentEventId != null) { searchables.add(hibernateSession.load(EventModel.class, parentEventId)); } else if(parentWhiteboardId != null) { searchables.add(hibernateSession.load(WhiteboardModel.class, parentWhiteboardId)); } } return searchables; } private String getCommonQueryPart(HashMap<String, String> terms) { String sql = " from searchables where match(body) against (:terms) "; if ( !currentUser.isAdmin() ) { sql += " AND (groupid IN ("; Iterator<GroupModel> groups = Permissions.visibleGroups(currentUser, true, false).iterator(); sql += groups.next().getId(); while(groups.hasNext()) { sql += ", " + groups.next().getId(); } sql += ")) "; } if(!terms.get("Posts").equals("on")) sql += " and parentPost is null "; if(!terms.get("Events").equals("on")) sql += " and parentEvent is null "; if(!terms.get("Whiteboards").equals("on")) sql += " and parentWhiteboard is null "; if(!terms.get("Since").equals("")) sql += " and date >= :since "; return sql; } private int numMatchingSearchables(HashMap<String, String> terms) { String sql = "select count(*) " + getCommonQueryPart(terms); Query query = hibernateSession.createSQLQuery(sql) .setString("terms", terms.get("Body")); if(!terms.get("Since").equals("")) query.setString("since", terms.get("Since")); return((BigInteger)query.uniqueResult()).intValue(); } public HashMap<String, String> decode(String searchTerm) throws Exception { HashMap <String, String> lines = new HashMap<String, String>(); lines.put("Body", ""); lines.put("Since", ""); lines.put("Mask", "111"); String[] keys = searchTerm.split("&"); for(int i = 0; i < keys.length; i++) { String line = keys[i]; String[] keyValue = line.split("="); lines.put(keyValue[0], keyValue.length > 1 ? URLDecoder.decode(keyValue[1], "UTF-8") : ""); } String mask = lines.remove("Mask"); if(mask.equals("000")) mask = "111"; for(int i=0; i<types.length; i++) { if(mask.charAt(i) == '1') lines.put(types[i], "on"); else lines.put(types[i], ""); } return lines; } private String encode(PostParamWrapper requestParams) throws Exception { String bodyTerm = requestParams.get("Body") != null ? URLEncoder.encode(requestParams.get("Body").replaceAll("/"," "), "UTF-8") : ""; String sinceTerm = requestParams.get("Since") != null ? URLEncoder.encode(requestParams.get("Since"), "UTF-8") : ""; String mask = ""; for(String type: types) { if(requestParams.get(type) != null && requestParams.get(type).equals("on")) mask += "1"; else mask += "0"; } return "Body=" + bodyTerm + "&Since=" + sinceTerm + "&Mask=" + mask; } public Set<String> invisibleGroups() { Set<String> s = new HashSet<String>(); s.add("Org"); return s; } public String displayName() { return "Search"; } }