Commit df7944c4 authored by Ryan Graham's avatar Ryan Graham Committed by ryang

* Added the ability to disable specific fields from being searched.

* Added internationalization (i18n) support.
* Updated UI to match later versions of Wildfire.

git-svn-id: http://svn.igniterealtime.org/svn/repos/wildfire/trunk@7393 b35dd754-fafc-0310-a699-88a17e54d16e
parent 1bd98d8d
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<title>Search Plugin Changelog</title> <title>Search Plugin Changelog</title>
<style type="text/css"> <style type="text/css">
BODY { BODY {
font-size : 100%; font-size : 100%;
...@@ -44,9 +44,16 @@ ...@@ -44,9 +44,16 @@
Search Plugin Changelog Search Plugin Changelog
</h1> </h1>
<p><b>1.3.0</b> -- February 28, 2007</p>
<ul>
<li>Added the ability to disable specific fields from being searched.</li>
<li>Added internationalization (i18n) support.</li>
<li>Updated UI to match later versions of Wildfire.</li>
</ul>
<p><b>1.2.1</b> -- September 7, 2006</p> <p><b>1.2.1</b> -- September 7, 2006</p>
<ul> <ul>
<li>Search results no longer shows edit and delete if users are read-only.</li> <li>Search results no longer shows edit and delete if users are read-only.</li>
</ul> </ul>
<p><b>1.2.1</b> -- October 06, 2006</p> <p><b>1.2.1</b> -- October 06, 2006</p>
......
...@@ -3,26 +3,26 @@ ...@@ -3,26 +3,26 @@
<plugin> <plugin>
<class>org.jivesoftware.wildfire.plugin.SearchPlugin</class> <class>org.jivesoftware.wildfire.plugin.SearchPlugin</class>
<name>Search</name> <name>Search</name>
<description>Provides support for Jabber Search (JEP-0055)</description> <description>Provides support for Jabber Search (XEP-0055)</description>
<author>Ryan Graham</author> <author>Ryan Graham</author>
<version>1.2.1</version> <version>1.3.0</version>
<date>10/06/2006</date> <date>02/28/2007</date>
<minServerVersion>3.1.0</minServerVersion> <minServerVersion>3.1.0</minServerVersion>
<adminconsole> <adminconsole>
<tab id="tab-server"> <tab id="tab-server">
<sidebar id="sidebar-server-settings"> <sidebar id="sidebar-server-settings">
<item id="search-props-edit-form" name="Search Properties" <item id="search-props-edit-form" name="Search Properties"
url="search-props-edit-form.jsp" url="search-props-edit-form.jsp"
description="Edit search service properties" /> description="Edit search service properties" />
</sidebar> </sidebar>
</tab> </tab>
<tab id="tab-users"> <tab id="tab-users">
<sidebar id="sidebar-users"> <sidebar id="sidebar-users">
<item id="advance-user-search" name="Advanced User Search" <item id="advance-user-search" name="Advanced User Search"
url="advance-user-search.jsp" url="advance-user-search.jsp"
description="Advanced user search" /> description="Advanced user search" />
</sidebar> </sidebar>
</tab> </tab>
</adminconsole> </adminconsole>
</plugin> </plugin>
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<title>Search Plugin Readme</title> <title>Search Plugin Readme</title>
<style type="text/css"> <style type="text/css">
BODY { BODY {
font-size : 100%; font-size : 100%;
...@@ -44,15 +44,13 @@ Search Plugin Readme ...@@ -44,15 +44,13 @@ Search Plugin Readme
</h1> </h1>
<h2>Overview</h2> <h2>Overview</h2>
<p> <p>
The search plugin adds Jabber Search <a href="http://www.jabber.org/jeps/jep-0055.html">JEP-0055</a> The search plugin adds Jabber Search <a href="http://www.xmpp.org/extensions/xep-0055.html">XEP-0055</a>
capabilities to Wildfire. This plugin is designed to work with various Jabber clients to allow capabilities to Wildfire. This plugin is designed to work with various Jabber clients to allow
other users to search for users currently registered on the same server they are. other users to search for users currently registered on the same server they are.
</p> </p>
<h2>Installation</h2> <h2>Installation</h2>
<p> <p>
Copy the file, &quot;search.jar&quot; into the plugins directory of your Wildfire installation. The plugin will Copy the file, &quot;search.jar&quot; into the plugins directory of your Wildfire installation. The plugin will
then be automatically deployed. To upgrade to a new version: 1) go to the plugin screen of the Admin then be automatically deployed. To upgrade to a new version: 1) go to the plugin screen of the Admin
...@@ -61,15 +59,16 @@ copy the new search.jar into the plugins directory of your Wildfire installation ...@@ -61,15 +59,16 @@ copy the new search.jar into the plugins directory of your Wildfire installation
</p> </p>
<h2>Configuration</h2> <h2>Configuration</h2>
<p>
The search plugin is configured via the "Search Service Properites" sidebar item located under the "Server" tab The search plugin is configured via the "Search Service Properites" sidebar item located under the "Server" tab
in the Wildfire Admin Console. By default, after the search plugin has been deployed all of its features in the Wildfire Admin Console. By default, after the search plugin has been deployed all of its features
are enabled. To enable or disable the plugin select the appropirate radio button and then click on the are enabled. To enable or disable the plugin select the appropirate radio button and then click on the
"Save Properties" button. To change the service name enter the new name for the service and then click on the "Save Properties" button. To change the service name enter the new name for the service and then click on the
"Save Properties" button "Save Properties" button. To disable a field from being searched by clients un-check the corresponding checkbox
and click on the "Save Properties" button.
</p>
<h2>Using the Plugin</h2> <h2>Using the Plugin</h2>
<p> <p>
Use of this plugin varies from client to client; however, basic instructions for accessing the search screen Use of this plugin varies from client to client; however, basic instructions for accessing the search screen
for some of the more popular clients are listed below. On the search screen there is a single for some of the more popular clients are listed below. On the search screen there is a single
...@@ -78,13 +77,16 @@ and/or email that you want to find. As an example, if you want to find your frie ...@@ -78,13 +77,16 @@ and/or email that you want to find. As an example, if you want to find your frie
if his last name is spelled "Smith" or "Smyth", try entering "John S*" in the search field and making if his last name is spelled "Smith" or "Smyth", try entering "John S*" in the search field and making
sure the name checkbox is selected. The "*" symbol acts as a wildcard so your search might return not sure the name checkbox is selected. The "*" symbol acts as a wildcard so your search might return not
only "John Smith" but all the users whose name begins with "John S", i.e. "John Slater", "John Salazar", etc. only "John Smith" but all the users whose name begins with "John S", i.e. "John Slater", "John Salazar", etc.
</p>
<li> <li>
Admin Console - Navigate to the "Advance User Search" sidebar item located in under the "Users/Groups" tab. Admin Console - Navigate to the "Advance User Search" sidebar item located in under the "Users/Groups" tab.
</li> </li>
<br> <br>
<li>
Spark - Use the search field along the bottom portion of the main Spark window.
</li>
<br>
<li> <li>
Exodus - After clicking on the magnifying glass with the red "+" sign, a screen will appear displaying the search Exodus - After clicking on the magnifying glass with the red "+" sign, a screen will appear displaying the search
service that will be used which will be used. Click on the "Next" button and the search screen will service that will be used which will be used. Click on the "Next" button and the search screen will
...@@ -109,6 +111,6 @@ view the search screen. ...@@ -109,6 +111,6 @@ view the search screen.
Psi - On the lower left-hand corner of the client, click on the main Psi toolbar, select "Service Discovery", and click on your username. After the service discovery windowappears, select the "User Search" entry and click on Psi - On the lower left-hand corner of the client, click on the main Psi toolbar, select "Service Discovery", and click on your username. After the service discovery windowappears, select the "User Search" entry and click on
the magnifying glass at the top of the window to view the search screen. the magnifying glass at the top of the window to view the search screen.
</li> </li>
<br> </p>
</body> </body>
</html> </html>
login.title=Admin Console
advance.user.search.title=User Search
advance.user.search.search_user=Search For User
advance.user.search.search=Search
advance.user.search.details=The following fields are available for searching. Wildcard (*) characters are allowed as part the of query.
advance.user.search.more_options=More Options
advance.user.search.less_options=Less Options
advance.user.search.users_found=Users Found
advance.user.search.online=Online
advance.user.search.username=Username
advance.user.search.name=Name
advance.user.search.created=Created
advance.user.search.edit=Edit
advance.user.search.delete=Delete
advance.user.search.no_users=No users in the system.
advance.user.search.available=Available
advance.user.search.chat_available=Free to chat
advance.user.search.away=Away
advance.user.search.extended=Extended away
advance.user.search.offline=Offline
search.props.edit.form.title=Search Service Properties
search.props.edit.form.directions=Use the form below to edit search service settings, these settings do not affect the user search in the admin console.
search.props.edit.form.successful_edit=Service properties edited successfully.
search.props.edit.form.error=Error setting the service name.
search.props.edit.form.service_enabled=Service Enabled
search.props.edit.form.service_enabled_directions=You can choose to enable or disable user searches from clients. Disabling this services does not prevent user searches from the admin console.
search.props.edit.form.enabled=Enabled
search.props.edit.form.enabled_details=Clients will be able to search for users.
search.props.edit.form.disabled=Disabled
search.props.edit.form.disabled_details=Clients will not be able to search for users.
search.props.edit.form.service_name=Service Name
search.props.edit.form.search_service_name=Search service Name
search.props.edit.form.search_service_name_details=Please enter a valid name.
search.props.edit.form.searchable_fields=Searchable Fields
search.props.edit.form.searchable_fields_details=Use the form below to enable which fields users can search on.
search.props.edit.form.fields=Fields
search.props.edit.form.save_properties=Save Properties
search.service_unavailable=This service is unavailable.
...@@ -11,9 +11,11 @@ import org.dom4j.DocumentHelper; ...@@ -11,9 +11,11 @@ import org.dom4j.DocumentHelper;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.QName; import org.dom4j.QName;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.PropertyEventDispatcher; import org.jivesoftware.util.PropertyEventDispatcher;
import org.jivesoftware.util.PropertyEventListener; import org.jivesoftware.util.PropertyEventListener;
import org.jivesoftware.util.StringUtils;
import org.jivesoftware.wildfire.XMPPServer; import org.jivesoftware.wildfire.XMPPServer;
import org.jivesoftware.wildfire.container.Plugin; import org.jivesoftware.wildfire.container.Plugin;
import org.jivesoftware.wildfire.container.PluginManager; import org.jivesoftware.wildfire.container.PluginManager;
...@@ -38,20 +40,21 @@ import java.util.*; ...@@ -38,20 +40,21 @@ import java.util.*;
/** /**
* Provides support for Jabber Search * Provides support for Jabber Search
* (<a href="http://www.jabber.org/jeps/jep-0055.html">JEP-0055</a>).<p> * (<a href="http://www.xmpp.org/extensions/xep-0055.html">XEP-0055</a>).<p>
* *
* The basic functionality is to query an information repository * The basic functionality is to query an information repository
* regarding the possible search fields, to send a search query, * regarding the possible search fields, to send a search query,
* and to receive search results. This implementation was primarily designed to use * and to receive search results. This implementation was primarily designed to use
* <a href="http://www.jabber.org/jeps/jep-0004.html">Data Forms</a>, but * <a href="http://www.xmpp.org/extensions/xep-0004.html">Data Forms</a>, but
* also supports non-dataform searches. * also supports non-dataform searches.
* <p/> * <p/>
* *
* @author Ryan Graham * @author <a href="mailto:ryan@version2software.com">Ryan Graham</a>
*/ */
public class SearchPlugin implements Component, Plugin, PropertyEventListener { public class SearchPlugin implements Component, Plugin, PropertyEventListener {
public static final String PLUGIN_SEARCH_SERVICENAME = "plugin.search.serviceName"; public static final String SERVICENAME = "plugin.search.serviceName";
public static final String PLUGIN_SEARCH_SERVICEENABLED = "plugin.search.serviceEnabled"; public static final String SERVICEENABLED = "plugin.search.serviceEnabled";
public static final String EXCLUDEDFIELDS = "plugin.search.excludedFields";
private UserManager userManager; private UserManager userManager;
private ComponentManager componentManager; private ComponentManager componentManager;
...@@ -59,36 +62,22 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -59,36 +62,22 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
private String serviceName; private String serviceName;
private boolean serviceEnabled; private boolean serviceEnabled;
private Collection<String> exculudedFields;
private static String serverName; private static String serverName;
private static String instructions = "The following fields are available for search. "
+ "Wildcard (*) characters are allowed as part of the query.";
private static Element probeResult;
private Collection<String> searchFields;
private TreeMap<String, String> fieldLookup = new TreeMap<String, String>(new CaseInsensitiveComparator()); private TreeMap<String, String> fieldLookup = new TreeMap<String, String>(new CaseInsensitiveComparator());
private Map<String, String> reverseFieldLookup = new HashMap<String, String>(); private Map<String, String> reverseFieldLookup = new HashMap<String, String>();
public SearchPlugin() { public SearchPlugin() {
serviceName = JiveGlobals.getProperty("plugin.search.serviceName", "search"); serviceName = JiveGlobals.getProperty(SERVICENAME, "search");
serviceEnabled = JiveGlobals.getBooleanProperty("plugin.search.serviceEnabled", true); serviceEnabled = JiveGlobals.getBooleanProperty(SERVICEENABLED, true);
exculudedFields = StringUtils.stringToCollection(JiveGlobals.getProperty(EXCLUDEDFIELDS, ""));
serverName = XMPPServer.getInstance().getServerInfo().getName(); serverName = XMPPServer.getInstance().getServerInfo().getName();
// See if the installed provider supports searching. If not, workaround
// by providing our own searching. // Some clients, such as Miranda, are hard-coded to search specific fields,
UserManager manager = UserManager.getInstance(); // so we map those fields to the fields that Wildfire actually supports.
try {
searchFields = manager.getSearchFields();
userManager = UserManager.getInstance();
searchFields = userManager.getSearchFields();
}
catch (UnsupportedOperationException uoe) {
// Use a SearchPluginUserManager instead.
searchFields = getSearchFields();
}
fieldLookup.put("jid", "Username"); fieldLookup.put("jid", "Username");
fieldLookup.put("username", "Username"); fieldLookup.put("username", "Username");
fieldLookup.put("first", "Name"); fieldLookup.put("first", "Name");
...@@ -97,7 +86,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -97,7 +86,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
fieldLookup.put("name", "Name"); fieldLookup.put("name", "Name");
fieldLookup.put("email", "Email"); fieldLookup.put("email", "Email");
} }
public String getName() { public String getName() {
return pluginManager.getName(this); return pluginManager.getName(this);
} }
...@@ -106,53 +95,17 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -106,53 +95,17 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
return pluginManager.getDescription(this); return pluginManager.getDescription(this);
} }
public void initializePlugin(PluginManager manager, File pluginDirectory) { public void initializePlugin(PluginManager manager, File pluginDirectory) {
pluginManager = manager; pluginManager = manager;
componentManager = ComponentManagerFactory.getComponentManager(); componentManager = ComponentManagerFactory.getComponentManager();
try { try {
componentManager.addComponent(serviceName, this); componentManager.addComponent(serviceName, this);
} }
catch (Exception e) { catch (ComponentException e) {
componentManager.getLog().error(e); componentManager.getLog().error(e);
} }
PropertyEventDispatcher.addListener(this); PropertyEventDispatcher.addListener(this);
if (probeResult == null) {
probeResult = DocumentHelper.createElement(QName.get("query", "jabber:iq:search"));
//non-data form
probeResult.addElement("instructions").addText(instructions);
XDataFormImpl searchForm = new XDataFormImpl(DataForm.TYPE_FORM);
searchForm.setTitle("User Search");
searchForm.addInstruction(instructions);
XFormFieldImpl field = new XFormFieldImpl("FORM_TYPE");
field.setType(FormField.TYPE_HIDDEN);
field.addValue("jabber:iq:search");
searchForm.addField(field);
field = new XFormFieldImpl("search");
field.setType(FormField.TYPE_TEXT_SINGLE);
field.setLabel("Search");
field.setRequired(true);
searchForm.addField(field);
for (String searchField : searchFields) {
//non-data form
probeResult.addElement(searchField);
field = new XFormFieldImpl(searchField);
field.setType(FormField.TYPE_BOOLEAN);
field.addValue("1");
field.setLabel(searchField);
field.setRequired(false);
searchForm.addField(field);
}
probeResult.add(searchForm.asXMLElement());
}
} }
public void initialize(JID jid, ComponentManager componentManager) { public void initialize(JID jid, ComponentManager componentManager) {
...@@ -174,12 +127,13 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -174,12 +127,13 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
userManager = null; userManager = null;
fieldLookup = null; fieldLookup = null;
reverseFieldLookup = null; reverseFieldLookup = null;
exculudedFields = null;
} }
public void shutdown() { public void shutdown() {
} }
public void processPacket(Packet p) { public void processPacket(Packet p) {
if (p instanceof IQ) { if (p instanceof IQ) {
IQ packet = (IQ) p; IQ packet = (IQ) p;
...@@ -240,12 +194,12 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -240,12 +194,12 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
} }
else if (IQ.Type.set.equals(packet.getType())) { else if (IQ.Type.set.equals(packet.getType())) {
return processSetPacket(packet); return processSetPacket(packet);
} else }
if (IQ.Type.result.equals(packet.getType()) || IQ.Type.error.equals(packet.getType())) { else if (IQ.Type.result.equals(packet.getType()) || IQ.Type.error.equals(packet.getType())) {
// Ignore // Ignore
} }
else { else {
// Unknown type was sent so // Unknown type was sent so return an error
IQ reply = new IQ(IQ.Type.error, packet.getID()); IQ reply = new IQ(IQ.Type.error, packet.getID());
reply.setFrom(packet.getTo()); reply.setFrom(packet.getTo());
reply.setTo(packet.getFrom()); reply.setTo(packet.getFrom());
...@@ -260,8 +214,8 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -260,8 +214,8 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
IQ replyPacket = IQ.createResultIQ(packet); IQ replyPacket = IQ.createResultIQ(packet);
Element reply = replyPacket.setChildElement("query", "jabber:iq:search"); Element reply = replyPacket.setChildElement("query", "jabber:iq:search");
XDataFormImpl unavailableForm = new XDataFormImpl(DataForm.TYPE_CANCEL); XDataFormImpl unavailableForm = new XDataFormImpl(DataForm.TYPE_CANCEL);
unavailableForm.setTitle("User Search"); unavailableForm.setTitle(LocaleUtils.getLocalizedString("advance.user.search.title", "search"));
unavailableForm.addInstruction("This service is unavailable."); unavailableForm.addInstruction(LocaleUtils.getLocalizedString("search.service_unavailable", "search"));
reply.add(unavailableForm.asXMLElement()); reply.add(unavailableForm.asXMLElement());
return replyPacket; return replyPacket;
...@@ -269,7 +223,43 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -269,7 +223,43 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
private IQ processGetPacket(IQ packet) { private IQ processGetPacket(IQ packet) {
IQ replyPacket = IQ.createResultIQ(packet); IQ replyPacket = IQ.createResultIQ(packet);
replyPacket.setChildElement(probeResult.createCopy());
Element queryResult = DocumentHelper.createElement(QName.get("query", "jabber:iq:search"));
String instructions = LocaleUtils.getLocalizedString("advance.user.search.details", "search");
// non-data form
queryResult.addElement("instructions").addText(instructions);
XDataFormImpl searchForm = new XDataFormImpl(DataForm.TYPE_FORM);
searchForm.setTitle(LocaleUtils.getLocalizedString("advance.user.search.title", "search"));
searchForm.addInstruction(instructions);
XFormFieldImpl field = new XFormFieldImpl("FORM_TYPE");
field.setType(FormField.TYPE_HIDDEN);
field.addValue("jabber:iq:search");
searchForm.addField(field);
field = new XFormFieldImpl("search");
field.setType(FormField.TYPE_TEXT_SINGLE);
field.setLabel(LocaleUtils.getLocalizedString("advance.user.search.search", "search"));
field.setRequired(true);
searchForm.addField(field);
for (String searchField : getFilteredSearchFields()) {
// non-data form
queryResult.addElement(searchField);
field = new XFormFieldImpl(searchField);
field.setType(FormField.TYPE_BOOLEAN);
field.addValue("1");
field.setLabel(searchField);
field.setRequired(false);
searchForm.addField(field);
}
queryResult.add(searchForm.asXMLElement());
replyPacket.setChildElement(queryResult);
return replyPacket; return replyPacket;
} }
...@@ -297,6 +287,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -297,6 +287,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
foundUsers.addAll(findUsers(field, query)); foundUsers.addAll(findUsers(field, query));
} }
//occasionally null a User is returned so filter them out
for (User user : foundUsers) { for (User user : foundUsers) {
if (user != null) { if (user != null) {
users.add(user); users.add(user);
...@@ -371,7 +362,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -371,7 +362,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
field.setLabel("JID"); field.setLabel("JID");
searchResults.addReportedField(field); searchResults.addReportedField(field);
for (String fieldName : searchFields) { for (String fieldName : getFilteredSearchFields()) {
field = new XFormFieldImpl(fieldName); field = new XFormFieldImpl(fieldName);
field.setLabel(fieldName); field.setLabel(fieldName);
searchResults.addReportedField(field); searchResults.addReportedField(field);
...@@ -444,7 +435,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -444,7 +435,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
public void setServiceName(String name) { public void setServiceName(String name) {
changeServiceName(name); changeServiceName(name);
JiveGlobals.setProperty(PLUGIN_SEARCH_SERVICENAME, name); JiveGlobals.setProperty(SERVICENAME, name);
} }
public boolean getServiceEnabled() { public boolean getServiceEnabled() {
...@@ -453,33 +444,67 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -453,33 +444,67 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
public void setServiceEnabled(boolean enabled) { public void setServiceEnabled(boolean enabled) {
serviceEnabled = enabled; serviceEnabled = enabled;
JiveGlobals.setProperty(PLUGIN_SEARCH_SERVICEENABLED, enabled ? "true" : "false"); JiveGlobals.setProperty(SERVICEENABLED, enabled ? "true" : "false");
}
/**
* Returns the collection of searchable field names that does not include the fields
* listed in the EXCLUDEDFIELDS property list.
*/
public Collection<String> getFilteredSearchFields() {
Collection<String> searchFields;
// See if the installed provider supports searching. If not, workaround
// by providing our own searching.
try {
userManager = UserManager.getInstance();
searchFields = userManager.getSearchFields();
}
catch (UnsupportedOperationException uoe) {
// Use a SearchPluginUserManager instead.
searchFields = getSearchPluginUserManagerSearchFields();
}
searchFields.removeAll(exculudedFields);
return searchFields;
}
public void setExcludedFields(Collection<String> exculudedFields) {
this.exculudedFields = exculudedFields;
JiveGlobals.setProperty(EXCLUDEDFIELDS, StringUtils.collectionToString(exculudedFields));
} }
public void propertySet(String property, Map params) { public void propertySet(String property, Map params) {
if (property.equals(PLUGIN_SEARCH_SERVICEENABLED)) { if (property.equals(SERVICEENABLED)) {
this.serviceEnabled = Boolean.parseBoolean((String)params.get("value")); this.serviceEnabled = Boolean.parseBoolean((String)params.get("value"));
} }
else if (property.equals(PLUGIN_SEARCH_SERVICENAME)) { else if (property.equals(SERVICENAME)) {
changeServiceName((String)params.get("value")); changeServiceName((String)params.get("value"));
} }
else if (property.equals(EXCLUDEDFIELDS)) {
exculudedFields = StringUtils.stringToCollection(JiveGlobals.getProperty(EXCLUDEDFIELDS, (String)params.get("value")));
}
} }
public void propertyDeleted(String property, Map params) { public void propertyDeleted(String property, Map params) {
if (property.equals(PLUGIN_SEARCH_SERVICEENABLED)) { if (property.equals(SERVICEENABLED)) {
this.serviceEnabled = true; this.serviceEnabled = true;
} }
else if (property.equals(PLUGIN_SEARCH_SERVICENAME)) { else if (property.equals(SERVICENAME)) {
changeServiceName("search"); changeServiceName("search");
} }
else if (property.equals(EXCLUDEDFIELDS)) {
exculudedFields = new ArrayList<String>();
}
} }
public void xmlPropertySet(String property, Map params) { public void xmlPropertySet(String property, Map params) {
// not used // not used
} }
public void xmlPropertyDeleted(String property, Map params) { public void xmlPropertyDeleted(String property, Map params) {
// not used // not used
} }
private void changeServiceName(String serviceName) { private void changeServiceName(String serviceName) {
...@@ -509,15 +534,9 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -509,15 +534,9 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
this.serviceName = serviceName; this.serviceName = serviceName;
} }
private class CaseInsensitiveComparator implements Comparator { private class CaseInsensitiveComparator implements Comparator<String> {
public int compare(Object o1, Object o2) { public int compare(String s1, String s2) {
String s1 = (String) o1; return s1.compareToIgnoreCase(s2);
String s2 = (String) o2;
return s1.toUpperCase().compareTo(s2.toUpperCase());
}
public boolean equals(Object o) {
return compare(this, o) == 0;
} }
} }
...@@ -534,7 +553,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -534,7 +553,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
* user. Typical fields are username, name, and email. These values can be * user. Typical fields are username, name, and email. These values can be
* used to contruct a data form. * used to contruct a data form.
*/ */
public Collection<String> getSearchFields() { public Collection<String> getSearchPluginUserManagerSearchFields() {
return Arrays.asList("Username", "Name", "Email"); return Arrays.asList("Username", "Name", "Email");
} }
...@@ -551,7 +570,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener { ...@@ -551,7 +570,7 @@ public class SearchPlugin implements Component, Plugin, PropertyEventListener {
public Collection<User> findUsers(String field, String query) { public Collection<User> findUsers(String field, String query) {
List<User> foundUsers = new ArrayList<User>(); List<User> foundUsers = new ArrayList<User>();
if (!getSearchFields().contains(field)) { if (!getSearchPluginUserManagerSearchFields().contains(field)) {
return foundUsers; return foundUsers;
} }
......
<%@ page import="java.util.*, <%@ page import="java.util.*,
java.net.URLEncoder, java.net.URLEncoder,
org.jivesoftware.util.*, org.jivesoftware.util.*,
org.jivesoftware.wildfire.PresenceManager, org.jivesoftware.wildfire.PresenceManager,
org.jivesoftware.wildfire.user.*, org.jivesoftware.wildfire.user.*,
org.jivesoftware.wildfire.XMPPServer, org.jivesoftware.wildfire.XMPPServer,
org.xmpp.packet.Presence" org.xmpp.packet.Presence"
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<html> <html>
<head> <head>
<title>User Search</title> <title><fmt:message key="advance.user.search.title" /></title>
<meta name="pageID" content="advance-user-search"/> <meta name="pageID" content="advance-user-search"/>
</head> </head>
<body> <body>
...@@ -48,52 +48,51 @@ ...@@ -48,52 +48,51 @@
<form name="f" action="advance-user-search.jsp"> <form name="f" action="advance-user-search.jsp">
<input type="hidden" name="search" value="true"/> <input type="hidden" name="search" value="true"/>
<input type="hidden" name="moreOptions" value="<%=moreOptions %>"/> <input type="hidden" name="moreOptions" value="<%=moreOptions %>"/>
<fieldset>
<legend><fmt:message key="user.search.search_user" /></legend> <div class="jive-contentBoxHeader"><fmt:message key="advance.user.search.search_user" /></div>
<div> <div class="jive-contentBox">
<table cellpadding="3" cellspacing="1" border="0" width="600"> <table cellpadding="3" cellspacing="1" border="0" width="600">
<tr class="c1"> <tr class="c1">
<td width="1%" colspan="2" nowrap> <td width="1%" colspan="2" nowrap>
Search: <fmt:message key="advance.user.search.search" />
&nbsp;<input type="text" name="criteria" value="<%=(criteria != null ? criteria : "") %>" size="30" maxlength="75"/> &nbsp;<input type="text" name="criteria" value="<%=(criteria != null ? criteria : "") %>" size="30" maxlength="75"/>
&nbsp;<input type="submit" name="search" value="<fmt:message key="user.search.search" />"/> &nbsp;<input type="submit" name="search" value="<fmt:message key="advance.user.search.search" />"/>
</td> </td>
</tr> </tr>
<% if (moreOptions) { %> <% if (moreOptions) { %>
<tr class="c1"> <tr class="c1">
<td width="1%" colspan="2" nowrap>Wildcard (*) characters are allowed as part the of query. The following fields are available for searching:</td> <td width="1%" colspan="2" nowrap><fmt:message key="advance.user.search.details" />:</td>
</tr> </tr>
<% for (String searchField : searchFields) { %> <% for (String searchField : searchFields) { %>
<tr class="c1"> <tr class="c1">
<td width="1%" nowrap><%=searchField %>:</td> <td width="1%" nowrap><%=searchField %>:</td>
<td class="c2"> <td class="c2">
<% if (criteria == null) { %> <% if (criteria == null) { %>
<input type="checkbox" checked name="<%=searchField %>"/> <input type="checkbox" checked name="<%=searchField %>"/>
<% } else { %> <% } else { %>
<input type="checkbox" <%=selectedFields.contains(searchField) ? "checked" : "" %> name="<%=searchField %>"/> <input type="checkbox" <%=selectedFields.contains(searchField) ? "checked" : "" %> name="<%=searchField %>"/>
<% } %> <% } %>
</td> </td>
</tr> </tr>
<% } %> <% } %>
<tr> <tr>
<td nowrap>&raquo;&nbsp;<a href="advance-user-search.jsp?moreOptions=false">Less Options</a></td> <td nowrap>&raquo;&nbsp;<a href="advance-user-search.jsp?moreOptions=false"><fmt:message key="advance.user.search.less_options" /></a></td>
</tr> </tr>
<% } else { %> <% } else { %>
<tr> <tr>
<td nowrap>&raquo;&nbsp;<a href="advance-user-search.jsp?moreOptions=true">More Options</a></td> <td nowrap>&raquo;&nbsp;<a href="advance-user-search.jsp?moreOptions=true"><fmt:message key="advance.user.search.more_options" /></a></td>
</tr> </tr>
<% } %> <% } %>
</table> </table>
</div> </div>
</fieldset> </form>
</form>
<% if (criteria != null) { %> <% if (criteria != null) { %>
<p> <p>
Users Found: <%=users.size() %> <fmt:message key="advance.user.search.users_found" />: <%=users.size() %>
</p> </p>
<div class="jive-table"> <div class="jive-table">
...@@ -101,14 +100,14 @@ Users Found: <%=users.size() %> ...@@ -101,14 +100,14 @@ Users Found: <%=users.size() %>
<thead> <thead>
<tr> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<th nowrap><fmt:message key="session.details.online" /></th> <th nowrap><fmt:message key="advance.user.search.online" /></th>
<th nowrap><fmt:message key="user.create.username" /></th> <th nowrap><fmt:message key="advance.user.search.username" /></th>
<th nowrap><fmt:message key="user.create.name" /></th> <th nowrap><fmt:message key="advance.user.search.name" /></th>
<th nowrap><fmt:message key="user.summary.created" /></th> <th nowrap><fmt:message key="advance.user.search.created" /></th>
<% // Don't allow editing or deleting if users are read-only. <% // Don't allow editing or deleting if users are read-only.
if (!UserManager.getUserProvider().isReadOnly()) { %> if (!UserManager.getUserProvider().isReadOnly()) { %>
<th nowrap><fmt:message key="user.summary.edit" /></th> <th nowrap><fmt:message key="advance.user.search.edit" /></th>
<th nowrap><fmt:message key="global.delete" /></th> <th nowrap><fmt:message key="advance.user.search.delete" /></th>
<% } %> <% } %>
</tr> </tr>
</thead> </thead>
...@@ -116,14 +115,14 @@ Users Found: <%=users.size() %> ...@@ -116,14 +115,14 @@ Users Found: <%=users.size() %>
<% if (users.isEmpty()) { %> <% if (users.isEmpty()) { %>
<tr> <tr>
<td align="center" colspan="7"><fmt:message key="user.summary.not_user" /></td> <td align="center" colspan="7"><fmt:message key="advance.user.search.no_users" /></td>
</tr> </tr>
<% <%
} else { } else {
int i = 0; int i = 0;
PresenceManager presenceManager = XMPPServer.getInstance().getPresenceManager(); PresenceManager presenceManager = XMPPServer.getInstance().getPresenceManager();
for (User user : users) { for (User user : users) {
i++; i++;
%> %>
...@@ -136,26 +135,26 @@ Users Found: <%=users.size() %> ...@@ -136,26 +135,26 @@ Users Found: <%=users.size() %>
Presence presence = presenceManager.getPresence(user); Presence presence = presenceManager.getPresence(user);
if (presence.getShow() == null) { if (presence.getShow() == null) {
%> <img src="images/user-green-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="user.properties.available" />"> <% %> <img src="images/user-green-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="advance.user.search.available" />"> <%
} }
if (presence.getShow() == Presence.Show.chat) { if (presence.getShow() == Presence.Show.chat) {
%> <img src="images/user-green-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="session.details.chat_available" />"> <% %> <img src="images/user-green-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="advance.user.search.chat_available" />"> <%
} }
if (presence.getShow() == Presence.Show.away) { if (presence.getShow() == Presence.Show.away) {
%> <img src="images/user-yellow-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="session.details.away" />"> <% %> <img src="images/user-yellow-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="advance.user.search.away" />"> <%
} }
if (presence.getShow() == Presence.Show.xa) { if (presence.getShow() == Presence.Show.xa) {
%> <img src="images/user-yellow-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="session.details.extended" />"> <% %> <img src="images/user-yellow-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="advance.user.search.extended" />"> <%
} }
if (presence.getShow() == Presence.Show.dnd) { if (presence.getShow() == Presence.Show.dnd) {
%> <img src="images/user-red-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="session.details.not_disturb" />"> <% %> <img src="images/user-red-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="advance.user.search.not_disturb" />"> <%
} }
} else { } else {
%> <img src="images/user-clear-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="user.properties.offline" />"> <% %> <img src="images/user-clear-16x16.gif" width="16" height="16" border="0" alt="<fmt:message key="advance.user.search.offline" />"> <%
} }
%> %>
</td> </td>
......
<%@ page import="java.util.*, <%@ page import="java.util.*,
org.jivesoftware.wildfire.XMPPServer, org.jivesoftware.wildfire.XMPPServer,
org.jivesoftware.wildfire.plugin.SearchPlugin, org.jivesoftware.wildfire.plugin.SearchPlugin,
org.jivesoftware.wildfire.user.*,
org.jivesoftware.util.*" org.jivesoftware.util.*"
%> %>
...@@ -11,9 +12,9 @@ ...@@ -11,9 +12,9 @@
boolean save = request.getParameter("save") != null; boolean save = request.getParameter("save") != null;
boolean success = request.getParameter("success") != null; boolean success = request.getParameter("success") != null;
String searchName = ParamUtils.getParameter(request, "searchname"); String searchName = ParamUtils.getParameter(request, "searchname");
boolean searchEnabled = ParamUtils.getBooleanParameter(request, "searchEnabled"); boolean searchEnabled = ParamUtils.getBooleanParameter(request, "searchEnabled");
SearchPlugin plugin = (SearchPlugin) XMPPServer.getInstance().getPluginManager().getPlugin("search"); SearchPlugin plugin = (SearchPlugin) XMPPServer.getInstance().getPluginManager().getPlugin("search");
// Handle a save // Handle a save
Map errors = new HashMap(); Map errors = new HashMap();
...@@ -23,8 +24,17 @@ ...@@ -23,8 +24,17 @@
} }
if (errors.size() == 0) { if (errors.size() == 0) {
plugin.setServiceEnabled(searchEnabled); plugin.setServiceEnabled(searchEnabled);
plugin.setServiceName(searchName.trim()); plugin.setServiceName(searchName.trim());
ArrayList<String> excludedFields = new ArrayList<String>();
for (String field : UserManager.getInstance().getSearchFields()) {
if (!ParamUtils.getBooleanParameter(request, field)) {
excludedFields.add(field);
}
}
plugin.setExcludedFields(excludedFields);
response.sendRedirect("search-props-edit-form.jsp?success=true"); response.sendRedirect("search-props-edit-form.jsp?success=true");
return; return;
} }
...@@ -38,17 +48,18 @@ ...@@ -38,17 +48,18 @@
} }
searchEnabled = plugin.getServiceEnabled(); searchEnabled = plugin.getServiceEnabled();
Collection<String> searchableFields = plugin.getFilteredSearchFields();
%> %>
<html> <html>
<head> <head>
<title>Search Service Properties</title> <title><fmt:message key="search.props.edit.form.title" /></title>
<meta name="pageID" content="search-props-edit-form"/> <meta name="pageID" content="search-props-edit-form"/>
</head> </head>
<body> <body>
<p> <p>
Use the form below to edit search service settings, these settings do not affect the user search in the admin console.<br> <fmt:message key="search.props.edit.form.directions" />
</p> </p>
<% if (success) { %> <% if (success) { %>
...@@ -58,7 +69,7 @@ Use the form below to edit search service settings, these settings do not affect ...@@ -58,7 +69,7 @@ Use the form below to edit search service settings, these settings do not affect
<tbody> <tbody>
<tr><td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0"></td> <tr><td class="jive-icon"><img src="images/success-16x16.gif" width="16" height="16" border="0"></td>
<td class="jive-icon-label"> <td class="jive-icon-label">
Service properties edited successfully. <fmt:message key="search.props.edit.form.successful_edit" />
</td></tr> </td></tr>
</tbody> </tbody>
</table> </table>
...@@ -71,7 +82,7 @@ Use the form below to edit search service settings, these settings do not affect ...@@ -71,7 +82,7 @@ Use the form below to edit search service settings, these settings do not affect
<tbody> <tbody>
<tr><td class="jive-icon"><img src="images/error-16x16.gif" width="16" height="16" border="0"></td> <tr><td class="jive-icon"><img src="images/error-16x16.gif" width="16" height="16" border="0"></td>
<td class="jive-icon-label"> <td class="jive-icon-label">
Error setting the service name. <fmt:message key="search.props.edit.form.error" />
</td></tr> </td></tr>
</tbody> </tbody>
</table> </table>
...@@ -81,11 +92,10 @@ Use the form below to edit search service settings, these settings do not affect ...@@ -81,11 +92,10 @@ Use the form below to edit search service settings, these settings do not affect
<form action="search-props-edit-form.jsp?save" method="post"> <form action="search-props-edit-form.jsp?save" method="post">
<fieldset> <div class="jive-contentBoxHeader"><fmt:message key="search.props.edit.form.service_enabled" /></div>
<legend>Service Enabled</legend> <div class="jive-contentBox">
<div>
<p> <p>
You can choose to enable or disable user searches from clients. Disabling this services does not prevent user searches from the admin console. <fmt:message key="search.props.edit.form.service_enabled_directions" />
</p> </p>
<table cellpadding="3" cellspacing="0" border="0" width="100%"> <table cellpadding="3" cellspacing="0" border="0" width="100%">
<tbody> <tbody>
...@@ -95,7 +105,7 @@ Use the form below to edit search service settings, these settings do not affect ...@@ -95,7 +105,7 @@ Use the form below to edit search service settings, these settings do not affect
<%= ((searchEnabled) ? "checked" : "") %>> <%= ((searchEnabled) ? "checked" : "") %>>
</td> </td>
<td width="99%"> <td width="99%">
<label for="rb01"><b>Enabled</b></label> - Clients will be able to search for users. <label for="rb01"><b><fmt:message key="search.props.edit.form.enabled" /></b></label> - <fmt:message key="search.props.edit.form.enabled_details" />
</td> </td>
</tr> </tr>
<tr> <tr>
...@@ -104,24 +114,21 @@ Use the form below to edit search service settings, these settings do not affect ...@@ -104,24 +114,21 @@ Use the form below to edit search service settings, these settings do not affect
<%= ((!searchEnabled) ? "checked" : "") %>> <%= ((!searchEnabled) ? "checked" : "") %>>
</td> </td>
<td width="99%"> <td width="99%">
<label for="rb02"><b>Disabled</b></label> - Clients will not be able to search for users. <label for="rb02"><b><fmt:message key="search.props.edit.form.disabled" /></b></label> - <fmt:message key="search.props.edit.form.disabled_details" />
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</fieldset>
<br><br> <br>
<fieldset> <div class="jive-contentBoxHeader"><fmt:message key="search.props.edit.form.service_name" /></div>
<legend>Service Name</legend> <div class="jive-contentBox">
<div>
<table cellpadding="3" cellspacing="0" border="0"> <table cellpadding="3" cellspacing="0" border="0">
<tr> <tr>
<td class="c1"> <td class="c1">
Search service name: <fmt:message key="search.props.edit.form.search_service_name" />:
</td> </td>
<td> <td>
<input type="text" size="30" maxlength="150" name="searchname" value="<%= (searchName != null ? searchName : "") %>">.<%=XMPPServer.getInstance().getServerInfo().getName() %> <input type="text" size="30" maxlength="150" name="searchname" value="<%= (searchName != null ? searchName : "") %>">.<%=XMPPServer.getInstance().getServerInfo().getName() %>
...@@ -129,19 +136,39 @@ Use the form below to edit search service settings, these settings do not affect ...@@ -129,19 +136,39 @@ Use the form below to edit search service settings, these settings do not affect
<% if (errors.containsKey("searchname")) { %> <% if (errors.containsKey("searchname")) { %>
<span class="jive-error-text"> <span class="jive-error-text">
<br>Please enter a valid name. <br><fmt:message key="search.props.edit.form.search_service_name_details" />
</span> </span>
<% } %> <% } %>
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
</fieldset>
<br>
<div class="jive-contentBoxHeader"><fmt:message key="search.props.edit.form.searchable_fields" /></div>
<div class="jive-contentBox">
<p>
<fmt:message key="search.props.edit.form.searchable_fields_details" />
</p>
<table class="jive-table" cellpadding="3" cellspacing="0" border="0" width="400">
<tr>
<th align="center" width="1%"><fmt:message key="search.props.edit.form.enabled" /></th>
<th align="left" width="99%"><fmt:message key="search.props.edit.form.fields" /></th>
</tr>
<% for (String field : UserManager.getInstance().getSearchFields()) { %>
<tr>
<td align="center" width="1%"><input type="checkbox" <%=searchableFields.contains(field) ? "checked" : "" %> name="<%=field %>"></td>
<td align="left" width="99%"><%=field %></td>
</tr>
<% } %>
</table>
</div>
<br><br> <br>
<input type="submit" value="Save Properties"> <input type="submit" value="<fmt:message key="search.props.edit.form.save_properties" />">
</form> </form>
</body> </body>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment