tmortagne (SVN) wrote:
Author: tmortagne Date: 2010-03-16 14:37:11 +0100 (Tue, 16 Mar 2010) New Revision: 27653
Added: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerListener.java Modified: platform/core/trunk/xwiki-core/pom.xml platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManager.java platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerPlugin.java platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/stats/impl/StatsUtil.java platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/stats/impl/xwiki/XWikiStatsReader.java platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/api/XWikiRightService.java platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/stats/impl/StatsUtilTest.java Log: XWIKI-4606: Statistics exclusions by user
Modified: platform/core/trunk/xwiki-core/pom.xml =================================================================== --- platform/core/trunk/xwiki-core/pom.xml 2010-03-16 13:07:30 UTC (rev 27652) +++ platform/core/trunk/xwiki-core/pom.xml 2010-03-16 13:37:11 UTC (rev 27653) @@ -1396,7 +1396,8 @@ **/user/impl/LDAP/LDAPProfileXClass.java, **/user/impl/exo/ExoAuthServiceImpl.java, **/user/impl/exo/ExoFilter.java, - **/user/impl/exo/ExoGroupServiceImpl.java + **/user/impl/exo/ExoGroupServiceImpl.java,
Should there be a comment here that this is excluded because of a fanout complexity violation? Caleb
+ **/stats/impl/xwiki/XWikiStatsReader.java </excludes> </configuration> </plugin>
Modified: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManager.java =================================================================== --- platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManager.java 2010-03-16 13:07:30 UTC (rev 27652) +++ platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManager.java 2010-03-16 13:37:11 UTC (rev 27653) @@ -23,17 +23,15 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.Hashtable; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map;
import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.xwiki.observation.EventListener; -import org.xwiki.observation.event.DocumentDeleteEvent; -import org.xwiki.observation.event.Event; -import org.xwiki.observation.remote.RemoteObservationManagerContext; +import org.xwiki.model.reference.DocumentReference; +import org.xwiki.model.reference.DocumentReferenceResolver;
import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; @@ -46,15 +44,16 @@ import com.xpn.xwiki.plugin.rightsmanager.utils.LevelTree; import com.xpn.xwiki.plugin.rightsmanager.utils.RequestLimit; import com.xpn.xwiki.plugin.rightsmanager.utils.UsersGroups; +import com.xpn.xwiki.user.api.XWikiRightService; import com.xpn.xwiki.web.Utils;
/** - * Hidden toolkit use by the plugin API that make all the plugin's actions. + * Hidden toolkit used by the plugin API that make all the plugin's actions. * * @version $Id$ * @since XWiki Core 1.1.2, XWiki Core 1.2M2 (public since 1.4M1) */ -public final class RightsManager implements EventListener +public final class RightsManager { /** * Name of the default space where users and groups are stored. @@ -134,26 +133,21 @@ // ////////////////////////////////////////////////////////////////////////////
/** - * The name of the listener. + * Unique instance of RightsManager. */ - private static final String NAME = "rightsmanager"; + private static RightsManager instance;
/** - * The events to match. + * Used to resolve document reference based on another reference. */ - private static final List<Event> EVENTS = new ArrayList<Event>() - { - { - add(new DocumentDeleteEvent()); - } - }; + private DocumentReferenceResolver<String> explicitDocumentReferenceResolver = + Utils.getComponent(DocumentReferenceResolver.class, "explicit");
- // //////////////////////////////////////////////////////////////////////////// - /** - * Unique instance of RightsManager. + * Used to resolve reference based on context. */ - private static RightsManager instance; + private DocumentReferenceResolver<String> currentDocumentReferenceResolver = + Utils.getComponent(DocumentReferenceResolver.class, "current");
/** * Hidden constructor of RightsManager only access via getInstance(). @@ -176,120 +170,6 @@ return instance; }
- /** - * Remove reference to provided user or group in all groups and rights in current wiki. - * - * @param userOrGroupWiki the wiki name of the group or user. - * @param userOrGroupSpace the space name of the group or user. - * @param userOrGroupName the name of the group or user. - * @param user indicate if it is a user or a group. - * @param context the XWiki context. - * @throws XWikiException error when browsing groups or rights. - */ - private void cleanDeletedUserOrGroupInLocalWiki(String userOrGroupWiki, String userOrGroupSpace, - String userOrGroupName, boolean user, XWikiContext context) throws XWikiException - { - removeUserOrGroupFromAllRights(userOrGroupWiki, userOrGroupSpace, userOrGroupName, user, context); - context.getWiki().getGroupService(context).removeUserOrGroupFromAllGroups(userOrGroupWiki, userOrGroupSpace, - userOrGroupName, context); - } - - /** - * Remove reference to provided user or group in all groups and rights in all wikis. - * - * @param userOrGroupWiki the wiki name of the group or user. - * @param userOrGroupSpace the space name of the group or user. - * @param userOrGroupName the name of the group or user. - * @param user indicate if it is a user or a group. - * @param context the XWiki context. - * @throws XWikiException error when browsing groups or rights. - */ - private void cleanDeletedUserOrGroup(String userOrGroupWiki, String userOrGroupSpace, String userOrGroupName, - boolean user, XWikiContext context) throws XWikiException - { - if (!context.getWiki().isVirtualMode()) { - cleanDeletedUserOrGroupInLocalWiki(userOrGroupWiki, userOrGroupSpace, userOrGroupName, user, context); - } else { - List<String> wikiList = context.getWiki().getVirtualWikisDatabaseNames(context); - - String database = context.getDatabase(); - try { - boolean foundMainWiki = false; - - for (String wikiName : wikiList) { - if (context.isMainWiki(wikiName)) { - foundMainWiki = true; - } - - context.setDatabase(wikiName); - cleanDeletedUserOrGroupInLocalWiki(userOrGroupWiki, userOrGroupSpace, userOrGroupName, user, - context); - } - - if (!foundMainWiki) { - context.setDatabase(context.getMainXWiki()); - cleanDeletedUserOrGroupInLocalWiki(userOrGroupWiki, userOrGroupSpace, userOrGroupName, user, - context); - } - } finally { - context.setDatabase(database); - } - } - } - - /** - * {@inheritDoc} - * - * @see org.xwiki.observation.EventListener#getName() - */ - public String getName() - { - return NAME; - } - - /** - * {@inheritDoc} - * - * @see org.xwiki.observation.EventListener#getEvents() - */ - public List<Event> getEvents() - { - return EVENTS; - } - - /** - * {@inheritDoc} - * - * @see org.xwiki.observation.EventListener#onEvent(org.xwiki.observation.event.Event, java.lang.Object, - * java.lang.Object) - */ - public void onEvent(Event event, Object source, Object data) - { - // Only take into account local events - if (!Utils.getComponent(RemoteObservationManagerContext.class).isRemoteState()) { - XWikiDocument document = ((XWikiDocument) source).getOriginalDocument(); - XWikiContext context = (XWikiContext) data; - - String userOrGroupWiki = document.getDatabase(); - String userOrGroupSpace = document.getSpace(); - String userOrGroupName = document.getName(); - - if (document.getObject("XWiki.XWikiUsers") != null) { - try { - cleanDeletedUserOrGroup(userOrGroupWiki, userOrGroupSpace, userOrGroupName, true, context); - } catch (XWikiException e) { - LOG.warn("Error when cleaning for deleted user", e); - } - } else if (document.getObject("XWiki.XWikiGroups") != null) { - try { - cleanDeletedUserOrGroup(userOrGroupWiki, userOrGroupSpace, userOrGroupName, false, context); - } catch (XWikiException e) { - LOG.warn("Error when cleaning for deleted group", e); - } - } - } - } - // Groups and users management
/** @@ -1201,14 +1081,12 @@
Map<String, Collection<String>> groupCache = groupCacheIn; if (groupCache == null) { - groupCache = new Hashtable<String, Collection<String>>(); + groupCache = new HashMap<String, Collection<String>>(); }
- Collection<String> memberList; + Collection<String> memberList = groupCache.get(groupName);
- if (groupCache.containsKey(groupName)) { - memberList = groupCache.get(groupName); - } else { + if (memberList == null) { memberList = context.getWiki().getGroupService(context).getAllMembersNamesForGroup(groupName, 0, 0, context); groupCache.put(groupName, memberList); @@ -1228,4 +1106,91 @@
return found; } + + /** + * Resolve passed user or group into users references list. + * + * @param userOrGroup the user or group + * @param context the XWikiContext the XWiki context + * @return the list of users references + * @throws XWikiException error when getting documents + */ + public Collection<DocumentReference> resolveUsers(DocumentReference userOrGroup, XWikiContext context) + throws XWikiException + { + Collection<DocumentReference> users = new LinkedHashSet<DocumentReference>(); + + // Try it as virtual user (guest, superadmin) + + if (userOrGroup.getLastSpaceReference().getName().equals(DEFAULT_USERORGROUP_SPACE) + && (userOrGroup.getName().equalsIgnoreCase(XWikiRightService.SUPERADMIN_USER) || userOrGroup.getName() + .equals(XWikiRightService.GUEST_USER))) { + users.add(userOrGroup); + } + + // resolve + + XWikiDocument document = context.getWiki().getDocument(userOrGroup, context); + + if (!document.isNew()) { + // Try it as user + + DocumentReference userClassReference = + new DocumentReference(document.getDatabase(), DEFAULT_USERORGROUP_SPACE, "XWikiUsers"); + + if (document.getXObject(userClassReference) != null) { + users.add(userOrGroup); + } + + // Try it as group + + DocumentReference groupClassReference = + new DocumentReference(document.getDatabase(), DEFAULT_USERORGROUP_SPACE, "XWikiGroups"); + + List<BaseObject> members = document.getXObjects(groupClassReference); + if (members != null) { + for (BaseObject memberObj : members) { + String member = memberObj.getStringValue("member"); + + users.addAll(resolveUsers(this.explicitDocumentReferenceResolver.resolve(member, userOrGroup), + context)); + } + } + } + + return users; + } + + /** + * Resolve passed user or group into users references list. + * + * @param userOrGroup the user or group + * @param context the XWikiContext the XWiki context + * @return the list of users references + * @throws XWikiException error when getting documents + */ + public Collection<DocumentReference> resolveUsers(String userOrGroup, XWikiContext context) throws XWikiException + { + return resolveUsers(this.currentDocumentReferenceResolver.resolve(userOrGroup), context); + } + + /** + * Resolve passed users and groups into users references list. + * + * @param referenceList the list of users and groups + * @param context the XWikiContext the XWiki context + * @return the list of users references + * @throws XWikiException error when getting documents + */ + public Collection<DocumentReference> resolveUsers(List<String> referenceList, XWikiContext context) + throws XWikiException + { + Collection<DocumentReference> users = new LinkedHashSet<DocumentReference>(); + + for (String reference : referenceList) { + users.addAll(resolveUsers(reference, context)); + } + + return users; + } }
Added: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerListener.java =================================================================== --- platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerListener.java (rev 0) +++ platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerListener.java 2010-03-16 13:37:11 UTC (rev 27653) @@ -0,0 +1,208 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package com.xpn.xwiki.plugin.rightsmanager; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xwiki.observation.EventListener; +import org.xwiki.observation.event.DocumentDeleteEvent; +import org.xwiki.observation.event.Event; +import org.xwiki.observation.remote.RemoteObservationManagerContext; + +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xpn.xwiki.web.Utils; + +/** + * Listener to user and groups events to apply related automatic task like cleaning groups and rights objects. + * + * @version $Id: RightsManager.java 22782 2009-08-18 13:50:24Z tmortagne $ + * @since XWiki Core 2.2.3 + */ +public final class RightsManagerListener implements EventListener +{ + /** + * The logging tool. + */ + private static final Log LOG = LogFactory.getLog(RightsManagerListener.class); + + /** + * The name of the listener. + */ + private static final String NAME = "rightsmanager"; + + /** + * The events to match. + */ + private static final List<Event> EVENTS = new ArrayList<Event>() + { + { + add(new DocumentDeleteEvent()); + } + }; + + // //////////////////////////////////////////////////////////////////////////// + + /** + * Unique instance of RightsManager. + */ + private static RightsManagerListener instance; + + /** + * Hidden constructor of RightsManager only access via getInstance(). + */ + private RightsManagerListener() + { + } + + /** + * @return a unique instance of RightsManager. Thread safe. + */ + public static RightsManagerListener getInstance() + { + synchronized (RightsManagerListener.class) { + if (instance == null) { + instance = new RightsManagerListener(); + } + } + + return instance; + } + + /** + * {@inheritDoc} + * + * @see org.xwiki.observation.EventListener#getName() + */ + public String getName() + { + return NAME; + } + + /** + * {@inheritDoc} + * + * @see org.xwiki.observation.EventListener#getEvents() + */ + public List<Event> getEvents() + { + return EVENTS; + } + + /** + * {@inheritDoc} + * + * @see org.xwiki.observation.EventListener#onEvent(org.xwiki.observation.event.Event, java.lang.Object, + * java.lang.Object) + */ + public void onEvent(Event event, Object source, Object data) + { + // Only take into account local events + if (!Utils.getComponent(RemoteObservationManagerContext.class).isRemoteState()) { + XWikiDocument document = ((XWikiDocument) source).getOriginalDocument(); + XWikiContext context = (XWikiContext) data; + + String userOrGroupWiki = document.getDatabase(); + String userOrGroupSpace = document.getSpace(); + String userOrGroupName = document.getName(); + + if (document.getObject("XWiki.XWikiUsers") != null) { + try { + cleanDeletedUserOrGroup(userOrGroupWiki, userOrGroupSpace, userOrGroupName, true, context); + } catch (XWikiException e) { + LOG.warn("Error when cleaning for deleted user", e); + } + } else if (document.getObject("XWiki.XWikiGroups") != null) { + try { + cleanDeletedUserOrGroup(userOrGroupWiki, userOrGroupSpace, userOrGroupName, false, context); + } catch (XWikiException e) { + LOG.warn("Error when cleaning for deleted group", e); + } + } + } + } + + /** + * Remove reference to provided user or group in all groups and rights in current wiki. + * + * @param userOrGroupWiki the wiki name of the group or user. + * @param userOrGroupSpace the space name of the group or user. + * @param userOrGroupName the name of the group or user. + * @param user indicate if it is a user or a group. + * @param context the XWiki context. + * @throws XWikiException error when browsing groups or rights. + */ + private void cleanDeletedUserOrGroupInLocalWiki(String userOrGroupWiki, String userOrGroupSpace, + String userOrGroupName, boolean user, XWikiContext context) throws XWikiException + { + RightsManager.getInstance().removeUserOrGroupFromAllRights(userOrGroupWiki, userOrGroupSpace, userOrGroupName, + user, context); + context.getWiki().getGroupService(context).removeUserOrGroupFromAllGroups(userOrGroupWiki, userOrGroupSpace, + userOrGroupName, context); + } + + /** + * Remove reference to provided user or group in all groups and rights in all wikis. + * + * @param userOrGroupWiki the wiki name of the group or user. + * @param userOrGroupSpace the space name of the group or user. + * @param userOrGroupName the name of the group or user. + * @param user indicate if it is a user or a group. + * @param context the XWiki context. + * @throws XWikiException error when browsing groups or rights. + */ + private void cleanDeletedUserOrGroup(String userOrGroupWiki, String userOrGroupSpace, String userOrGroupName, + boolean user, XWikiContext context) throws XWikiException + { + if (!context.getWiki().isVirtualMode()) { + cleanDeletedUserOrGroupInLocalWiki(userOrGroupWiki, userOrGroupSpace, userOrGroupName, user, context); + } else { + List<String> wikiList = context.getWiki().getVirtualWikisDatabaseNames(context); + + String database = context.getDatabase(); + try { + boolean foundMainWiki = false; + + for (String wikiName : wikiList) { + if (context.isMainWiki(wikiName)) { + foundMainWiki = true; + } + + context.setDatabase(wikiName); + cleanDeletedUserOrGroupInLocalWiki(userOrGroupWiki, userOrGroupSpace, userOrGroupName, user, + context); + } + + if (!foundMainWiki) { + context.setDatabase(context.getMainXWiki()); + cleanDeletedUserOrGroupInLocalWiki(userOrGroupWiki, userOrGroupSpace, userOrGroupName, user, + context); + } + } finally { + context.setDatabase(database); + } + } + } +}
Property changes on: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerListener.java ___________________________________________________________________ Name: svn:mime-type + text/plain
Modified: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerPlugin.java =================================================================== --- platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerPlugin.java 2010-03-16 13:07:30 UTC (rev 27652) +++ platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/plugin/rightsmanager/RightsManagerPlugin.java 2010-03-16 13:37:11 UTC (rev 27653) @@ -75,10 +75,10 @@ // removed in order to remove that user from its groups. // Make sure we allow this plugin to be initialized several times in a row; i.e. don't re-register the // listener if it's already registered. - RightsManager rightsManager = RightsManager.getInstance(); + RightsManagerListener rightsManagerListener = RightsManagerListener.getInstance(); ObservationManager observationManager = Utils.getComponent(ObservationManager.class); - if (observationManager.getListener(rightsManager.getName()) == null) { - observationManager.addListener(rightsManager); + if (observationManager.getListener(rightsManagerListener.getName()) == null) { + observationManager.addListener(rightsManagerListener); } }
Modified: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/stats/impl/StatsUtil.java =================================================================== --- platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/stats/impl/StatsUtil.java 2010-03-16 13:07:30 UTC (rev 27652) +++ platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/stats/impl/StatsUtil.java 2010-03-16 13:37:11 UTC (rev 27653) @@ -23,8 +23,10 @@
import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.List;
@@ -36,12 +38,13 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.xwiki.model.reference.DocumentReference; +import org.xwiki.query.Query; +import org.xwiki.query.QueryManager;
import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; -import org.xwiki.query.Query; -import org.xwiki.query.QueryManager; - +import com.xpn.xwiki.plugin.rightsmanager.RightsManager; import com.xpn.xwiki.user.api.XWikiRightService; import com.xpn.xwiki.util.Util; import com.xpn.xwiki.web.XWikiRequest; @@ -59,11 +62,26 @@ private static final Log LOG = LogFactory.getLog(StatsUtil.class);
/** + * Default separator for a list. + */ + private static final String LIST_SEPARATOR = ","; + + /** + * Default separator for a list in escaped form. + */ + private static final String ESCAPED_LIST_SEPARATOR = "\\,"; + + /** * The name of the property in XWiki configuration file containing the list of cookie domains. */ private static final String CFGPROP_COOKIEDOMAINS = "xwiki.authentication.cookiedomains";
/** + * Separator for the property in XWiki configuration file containing the list of cookie domains. + */ + private static final char CFGPROP_COOKIEDOMAINS_SEP = ','; + + /** * The name of the property in XWiki configuration file indicating if statistics are enabled. */ private static final String CFGPROP_STATS = "xwiki.stats"; @@ -74,6 +92,12 @@ private static final String CFGPROP_STATS_DEFAULT = "xwiki.stats.default";
/** + * The name of the property in XWiki configuration file containing the list of users and group to filter in + * statistics requests. + */ + private static final String CFGPROP_STATS_EXCLUDEDUSERSANDGROUPS = "xwiki.stats.excludedUsersAndGroups"; + + /** * The prefix name of the session property containing recent statistics actions. */ private static final String SESSPROP_RECENT_PREFFIX = "recent_"; @@ -94,6 +118,12 @@ private static final String PREFPROP_STATISTICS = "statistics";
/** + * The name of the XWiki preferences property containing the list of users and group to filter in statistics + * requests. + */ + private static final String PREFPROP_EXCLUDEDUSERSANDGROUPS = "statistics_excludedUsersAndGroups"; + + /** * The name of the request property containing the referer. */ private static final String REQPROP_REFERER = "referer"; @@ -158,7 +188,8 @@ * <ul> * <li>"yyyMMdd" for {@link PeriodType#DAY}</li> * <li>"yyyMM" for {@link PeriodType#MONTH}</li> - * </ul>. + * </ul> + * . * * @param date the date for which to return an integer representation. * @param type the date type. It can be {@link PeriodType#DAY} or {@link PeriodType#MONTH}. @@ -195,7 +226,8 @@ public static String[] getCookieDomains(XWikiContext context) { if (cookieDomains == null) { - cookieDomains = StringUtils.split(context.getWiki().Param(CFGPROP_COOKIEDOMAINS), ","); + cookieDomains = + StringUtils.split(context.getWiki().Param(CFGPROP_COOKIEDOMAINS), CFGPROP_COOKIEDOMAINS_SEP); }
return cookieDomains; @@ -345,7 +377,7 @@ } }
- if ((!context.getUser().equals(XWikiRightService.GUEST_USER_FULLNAME)) + if ((!context.getUser().equals(XWikiRightService.GUEST_USER_FULLNAME)) && (visitObject.getUser().equals(XWikiRightService.GUEST_USER_FULLNAME))) { // The user has changed from guest to an authenticated user // We want to record this @@ -653,4 +685,51 @@
return referer; } + + /** + * The list of users to filter in request. + * + * @param context the XWiki context + * @return the list of users references + * @throws XWikiException error when trying to resolve users + */ + public static Collection<DocumentReference> getFilteredUsers(XWikiContext context) throws XWikiException + { + List<String> userList; + + String users = context.getWiki().getXWikiPreference(PREFPROP_EXCLUDEDUSERSANDGROUPS, "", context); + + if (StringUtils.isEmpty(users)) { + users = context.getWiki().Param(CFGPROP_STATS_EXCLUDEDUSERSANDGROUPS); + } + + if (!StringUtils.isBlank(users)) { + userList = new ArrayList<String>(); + + int begin = 0; + boolean escaped = false; + for (int i = 0; i < users.length(); ++i) { + char c = users.charAt(i); + + if (!escaped) { + if (c == '\\') { + escaped = true; + } else if (c == ',') { + userList.add(users.substring(begin, i).replace(ESCAPED_LIST_SEPARATOR, LIST_SEPARATOR)); + begin = i + 1; + } + } else { + escaped = false; + } + } + + if (begin < users.length()) { + userList.add(users.substring(begin).replace(ESCAPED_LIST_SEPARATOR, LIST_SEPARATOR)); + } + } else { + userList = Collections.emptyList(); + } + + return RightsManager.getInstance().resolveUsers(userList, context); + } }
Modified: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/stats/impl/xwiki/XWikiStatsReader.java =================================================================== --- platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/stats/impl/xwiki/XWikiStatsReader.java 2010-03-16 13:07:30 UTC (rev 27652) +++ platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/stats/impl/xwiki/XWikiStatsReader.java 2010-03-16 13:37:11 UTC (rev 27653) @@ -32,7 +32,11 @@ import java.util.Map;
import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.joda.time.DateTime; +import org.xwiki.model.reference.DocumentReference; +import org.xwiki.model.reference.EntityReferenceSerializer;
import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; @@ -49,6 +53,7 @@ import com.xpn.xwiki.store.XWikiHibernateStore; import com.xpn.xwiki.web.DownloadAction; import com.xpn.xwiki.web.SaveAction; +import com.xpn.xwiki.web.Utils; import com.xpn.xwiki.web.ViewAction;
/** @@ -60,6 +65,17 @@ public class XWikiStatsReader { /** + * Logging tool. + */ + private static final Log LOG = LogFactory.getLog(XWikiStatsReader.class); + + /** + * Used to convert a proper Document Reference to a string but without the wiki name. + */ + private EntityReferenceSerializer<String> compactwikiEntityReferenceSerializer = + Utils.getComponent(EntityReferenceSerializer.class, "compactwiki"); + + /** * Return the statistics action stored. * * @param action the action. @@ -137,8 +153,7 @@ }
/** - * Shows how the statistics for the specified action have evolved over the specified period of - * time. + * Shows how the statistics for the specified action have evolved over the specified period of time. * * @param action the action for which to retrieve statistics. * @param scope the set of documents to consider. @@ -147,14 +162,13 @@ * @param context the XWiki context. * @return a map of (date, actionCount) pairs. */ - public Map<DateTime, Integer> getActionStatistics(String action, Scope scope, Period period, - Duration step, XWikiContext context) + public Map<DateTime, Integer> getActionStatistics(String action, Scope scope, Period period, Duration step, + XWikiContext context) { DateTime stepStart = new DateTime(period.getStart()); DateTime periodEnd = new DateTime(period.getEnd()); org.joda.time.Period stepDuration = - new org.joda.time.Period(step.getYears(), step.getMonths(), step.getWeeks(), step - .getDays(), 0, 0, 0, 0); + new org.joda.time.Period(step.getYears(), step.getMonths(), step.getWeeks(), step.getDays(), 0, 0, 0, 0);
Map<DateTime, Integer> activity = new HashMap<DateTime, Integer>(); while (stepStart.compareTo(periodEnd) < 0) { @@ -163,8 +177,8 @@ stepEnd = periodEnd; } List<DocumentStats> stats = - getDocumentStatistics(action, scope, new Period(stepStart.getMillis(), stepEnd - .getMillis()), RangeFactory.FIRST, context); + getDocumentStatistics(action, scope, new Period(stepStart.getMillis(), stepEnd.getMillis()), + RangeFactory.FIRST, context); int actionCount = 0; if (stats.size() > 0) { actionCount = stats.get(0).getPageViews(); @@ -179,18 +193,16 @@ /** * Retrieves document statistics. * - * @param action the action the results should be ordered by. It can be one of: "view", "save" - * or "download". If the action is "view" then the documents are ordered by the - * number of times they have been viewed so far. + * @param action the action the results should be ordered by. It can be one of: "view", "save" or "download". If the + * action is "view" then the documents are ordered by the number of times they have been viewed so far. * @param scope the set of documents for which to retrieve statistics. * @param period the period of time, including its start date but excluding its end date. - * @param range the sub-range to return from the entire result set. Use this parameter for - * pagination. + * @param range the sub-range to return from the entire result set. Use this parameter for pagination. * @param context the XWiki context. * @return A list of DocumentStats objects */ - public List<DocumentStats> getDocumentStatistics(String action, Scope scope, Period period, - Range range, XWikiContext context) + public List<DocumentStats> getDocumentStatistics(String action, Scope scope, Period period, Range range, + XWikiContext context) { List<DocumentStats> documentStatsList;
@@ -203,18 +215,17 @@ XWikiHibernateStore store = context.getWiki().getHibernateStore();
try { - String query = MessageFormat.format( - "select name, sum(pageViews) from DocumentStats" - + " where {0} and action=? and ? <= period and period < ? group by name order" - + " by sum(pageViews) {1}", nameFilter, sortOrder); + String query = + MessageFormat.format("select name, sum(pageViews) from DocumentStats" + + " where {0} and action=? and ? <= period and period < ? group by name order" + + " by sum(pageViews) {1}", nameFilter, sortOrder);
paramList.add(action); paramList.add(period.getStartCode()); paramList.add(period.getEndCode());
List< ? > solist = - store.search(query, range.getAbsoluteSize(), range.getAbsoluteStart(), paramList, - context); + store.search(query, range.getAbsoluteSize(), range.getAbsoluteStart(), paramList, context);
documentStatsList = getDocumentStatistics(solist, action); if (range.getSize() < 0) { @@ -233,8 +244,7 @@ * @param resultSet the result of a database query for document statistics. * @param action the action for which the statistics were retrieved. * @return a list of {@link com.xpn.xwiki.stats.impl.DocumentStats} objects. - * @see #getDocumentStatistics(String, Scope, com.xpn.xwiki.criteria.impl.Period , Range , - * XWikiContext) + * @see #getDocumentStatistics(String, Scope, com.xpn.xwiki.criteria.impl.Period , Range , XWikiContext) */ private List<DocumentStats> getDocumentStatistics(List< ? > resultSet, String action) { @@ -246,8 +256,7 @@ Object[] result = (Object[]) it.next(); // We can't represent a custom period (e.g. year, week or some time interval) in the // database and thus we use a default one, which sould be ignored - DocumentStats docStats = - new DocumentStats((String) result[0], action, now, PeriodType.DAY); + DocumentStats docStats = new DocumentStats((String) result[0], action, now, PeriodType.DAY); docStats.setPageViews(((Number) result[1]).intValue()); documentStatsList.add(docStats); } @@ -261,13 +270,12 @@ * @param domain the domain used for filtering the results. * @param scope the scope of referred documents for which to retrieve statistics. * @param period the period of time, including its start date but excluding its end date. - * @param range the sub-range to return from the entire result set. Use this parameter for - * pagination. + * @param range the sub-range to return from the entire result set. Use this parameter for pagination. * @param context the XWiki context. * @return a list of DocumentStats objects. */ - public List<DocumentStats> getBackLinkStatistics(String domain, Scope scope, Period period, - Range range, XWikiContext context) + public List<DocumentStats> getBackLinkStatistics(String domain, Scope scope, Period period, Range range, + XWikiContext context) { List<DocumentStats> documentStatsList;
@@ -279,18 +287,17 @@
XWikiHibernateStore store = context.getWiki().getHibernateStore(); try { - String query = MessageFormat.format( - "select name, sum(pageViews) from RefererStats" - + " where {0} and referer like ? and ? <= period and period < ? group by name" - + " order by sum(pageViews) {1}", nameFilter, sortOrder); + String query = + MessageFormat.format("select name, sum(pageViews) from RefererStats" + + " where {0} and referer like ? and ? <= period and period < ? group by name" + + " order by sum(pageViews) {1}", nameFilter, sortOrder);
paramList.add(getHqlValidDomain(domain)); paramList.add(period.getStartCode()); paramList.add(period.getEndCode());
List< ? > solist = - store.search(query, range.getAbsoluteSize(), range.getAbsoluteStart(), paramList, - context); + store.search(query, range.getAbsoluteSize(), range.getAbsoluteStart(), paramList, context);
documentStatsList = getDocumentStatistics(solist, "refer"); if (range.getSize() < 0) { @@ -306,17 +313,16 @@ /** * Retrieves referrer statistics. * - * @param domain the domain for which to retrieve statistics. To retrieve statistics for all - * domains use the empty string. + * @param domain the domain for which to retrieve statistics. To retrieve statistics for all domains use the empty + * string. * @param scope the scope of referred documents to use for filtering the results. * @param period the period of time, including its start date but excluding its end date. - * @param range the sub-range to return from the entire result set. Use this parameter for - * pagination. + * @param range the sub-range to return from the entire result set. Use this parameter for pagination. * @param context the XWiki context. * @return a list of RefererStats objects. */ - public List<RefererStats> getRefererStatistics(String domain, Scope scope, Period period, - Range range, XWikiContext context) + public List<RefererStats> getRefererStatistics(String domain, Scope scope, Period period, Range range, + XWikiContext context) { List<RefererStats> refererList;
@@ -338,8 +344,7 @@ paramList.add(period.getEndCode());
List< ? > solist = - store.search(query, range.getAbsoluteSize(), range.getAbsoluteStart(), paramList, - context); + store.search(query, range.getAbsoluteSize(), range.getAbsoluteStart(), paramList, context);
refererList = getRefererStatistics(solist); if (range.getSize() < 0) { @@ -353,8 +358,8 @@ }
/** - * Converts the rows retrieved from the database to a list of - * {@link com.xpn.xwiki.stats.impl.RefererStats} instances. + * Converts the rows retrieved from the database to a list of {@link com.xpn.xwiki.stats.impl.RefererStats} + * instances. * * @param resultSet The result of a database query for referer statistics * @return A list of {@link com.xpn.xwiki.stats.impl.RefererStats} objects @@ -379,60 +384,103 @@ }
/** - * Retrieves visit statistics. + * Generate the HQL query used in {@link #getVisitStatistics(String, Period, Range, XWikiContext)}. * - * @param action the action the results should be ordered by. It can be one of: "view", "save" - * or "download". If the action is "view" then the visitors are ordered by the number - * of pages they have viewed so far. + * @param action the action the results should be ordered by. It can be one of: "view", "save" or "download". If the + * action is "view" then the visitors are ordered by the number of pages they have viewed so far. * @param period the period of time, including its start date but excluding its end date. - * @param range the sub-range to return from the entire result set. Use this parameter for - * pagination. + * @param range the sub-range to return from the entire result set. Use this parameter for pagination. + * @param paramList the list of query parameters to fill. * @param context the XWiki context. - * @return a list of VisitStats objects. + * @return the HQL query */ - public List<VisitStats> getVisitStatistics(String action, Period period, Range range, + private String createVisitStatisticsQuery(String action, Period period, Range range, List<Object> paramList, XWikiContext context) { - List<VisitStats> visiStatList; + StringBuffer query = new StringBuffer("select name, sum(pageSaves), sum(pageViews), sum(downloads)");
- List<Object> paramList = new ArrayList<Object>(2); + query.append(" from VisitStats");
+ query.append(" where"); + + // user filter + + StringBuffer userListWhere = new StringBuffer(); + try { + for (DocumentReference user : StatsUtil.getFilteredUsers(context)) { + if (userListWhere.length() > 0) { + userListWhere.append(", "); + } + userListWhere.append('?'); + + paramList.add(this.compactwikiEntityReferenceSerializer.serialize(user)); + } + } catch (Exception e) { + LOG.error("Faild to get filter users list", e); + } + + if (userListWhere.length() > 0) { + query.append(" name NOT IN ("); + query.append(userListWhere); + query.append(") and "); + } + + // date filter + + query.append(" ? <= startDate and endDate < ? group by name"); + paramList.add(new Date(period.getStart())); + paramList.add(new Date(period.getEnd())); + + // order + + query.append(' '); + String sortOrder = getHqlSortOrderFromRange(range);
- String orderByClause; if (action.equals(SaveAction.ACTION_NAME)) { - orderByClause = "order by sum(pageSaves) " + sortOrder; + query.append("order by sum(pageSaves) " + sortOrder); } else if (action.equals(ViewAction.VIEW_ACTION)) { - orderByClause = "order by sum(pageViews) " + sortOrder; + query.append("order by sum(pageViews) " + sortOrder); } else if (action.equals(DownloadAction.ACTION_NAME)) { - orderByClause = "order by sum(downloads) " + sortOrder; + query.append("order by sum(downloads) " + sortOrder); } else { - orderByClause = - MessageFormat.format("order by sum(pageSaves) {0}," + " sum(pageViews) {0}," - + " sum(downloads) {0}", sortOrder); + query.append(MessageFormat.format("order by sum(pageSaves) {0}, sum(pageViews) {0}, sum(downloads) {0}", + sortOrder)); }
+ return query.toString(); + } + + /** + * Retrieves visit statistics. + * + * @param action the action the results should be ordered by. It can be one of: "view", "save" or "download". If the + * action is "view" then the visitors are ordered by the number of pages they have viewed so far. + * @param period the period of time, including its start date but excluding its end date. + * @param range the sub-range to return from the entire result set. Use this parameter for pagination. + * @param context the XWiki context. + * @return a list of VisitStats objects. + */ + public List<VisitStats> getVisitStatistics(String action, Period period, Range range, XWikiContext context) + { + List<VisitStats> visiStatList; + + List<Object> paramList = new ArrayList<Object>(2); + + String query = createVisitStatisticsQuery(action, period, range, paramList, context); + XWikiHibernateStore store = context.getWiki().getHibernateStore(); try { - String query = - "select name, sum(pageSaves), sum(pageViews), sum(downloads)" - + " from VisitStats" + " where ? <= startDate and endDate < ? group by name " - + orderByClause; - - paramList.add(new Date(period.getStart())); - paramList.add(new Date(period.getEnd())); - List< ? > solist = - store.search(query, range.getAbsoluteSize(), range.getAbsoluteStart(), paramList, - context); + store.search(query, range.getAbsoluteSize(), range.getAbsoluteStart(), paramList, context);
- visiStatList = - getVisitStatistics(solist, new DateTime(period.getStart()), new DateTime(period - .getEnd())); + visiStatList = getVisitStatistics(solist, new DateTime(period.getStart()), new DateTime(period.getEnd())); if (range.getSize() < 0) { Collections.reverse(visiStatList); } } catch (XWikiException e) { + LOG.error("Faild to search for vist statistics", e); + visiStatList = Collections.emptyList(); }
@@ -446,10 +494,9 @@ * @param startDate the start date used in the query. * @param endDate the end date used in the query. * @return a list of {@link com.xpn.xwiki.stats.impl.VisitStats} objects. - * @see #getVisitStatistics(com.xpn.xwiki.criteria.impl.Period , Range , XWikiContext) + * @see #getVisitStatistics(String, Period, Range, XWikiContext) */ - private List<VisitStats> getVisitStatistics(List< ? > resultSet, DateTime startDate, - DateTime endDate) + private List<VisitStats> getVisitStatistics(List< ? > resultSet, DateTime startDate, DateTime endDate) { List<VisitStats> stats = new ArrayList<VisitStats>(resultSet.size());
@@ -466,8 +513,7 @@ int downloads = ((Number) result[3]).intValue();
VisitStats vs = - new VisitStats(name, uniqueID, cookie, ip, userAgent, new Date(startDate - .getMillis()), PeriodType.DAY); + new VisitStats(name, uniqueID, cookie, ip, userAgent, new Date(startDate.getMillis()), PeriodType.DAY); vs.setStartDate(new Date(startDate.getMillis())); vs.setEndDate(new Date(endDate.getMillis())); vs.setPageSaves(pageSaves); @@ -492,12 +538,10 @@ * @param month the month. * @param context the XWiki context. * @return DocumentStats - statistics object. - * @deprecated use {@link #getDocumentStatistics(String, Scope, Period, Range , XWikiContext)} - * instead. + * @deprecated use {@link #getDocumentStatistics(String, Scope, Period, Range , XWikiContext)} instead. */ @Deprecated - public DocumentStats getDocMonthStats(String docname, String action, Date month, - XWikiContext context) + public DocumentStats getDocMonthStats(String docname, String action, Date month, XWikiContext context) { XWikiHibernateStore store = context.getWiki().getHibernateStore(); DocumentStats object = new DocumentStats(docname, action, month, PeriodType.MONTH); @@ -518,12 +562,10 @@ * @param context the XWiki context. * @return the monthly referer statistics. * @throws XWikiException error when searching for referer statistics. - * @deprecated use {@link #getRefererStatistics(String, Scope, Period, Range, XWikiContext)} - * instead. + * @deprecated use {@link #getRefererStatistics(String, Scope, Period, Range, XWikiContext)} instead. */ @Deprecated - public List< ? > getRefMonthStats(String docName, Date month, XWikiContext context) - throws XWikiException + public List< ? > getRefMonthStats(String docName, Date month, XWikiContext context) throws XWikiException { XWikiHibernateStore store = context.getWiki().getHibernateStore();
@@ -531,9 +573,7 @@ if (store != null) { List<Object> paramList = new ArrayList<Object>(1); paramList.add(docName); - solist = - store.search("from RefererStats as obj where obj.name=?", 0, 0, paramList, - context); + solist = store.search("from RefererStats as obj where obj.name=?", 0, 0, paramList, context); } else { solist = Collections.emptyList(); }
Modified: platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/api/XWikiRightService.java =================================================================== --- platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/api/XWikiRightService.java 2010-03-16 13:07:30 UTC (rev 27652) +++ platform/core/trunk/xwiki-core/src/main/java/com/xpn/xwiki/user/api/XWikiRightService.java 2010-03-16 13:37:11 UTC (rev 27653) @@ -40,9 +40,14 @@ public static final String SUPERADMIN_USER_FULLNAME = "XWiki." + SUPERADMIN_USER;
/** + * The Guest username. + */ + public static final String GUEST_USER = "XWikiGuest"; + + /** * The Guest full name. */ - public static final String GUEST_USER_FULLNAME = "XWiki.XWikiGuest"; + public static final String GUEST_USER_FULLNAME = "XWiki." + GUEST_USER;
/** * Checks if the wiki current user has the right to execute (@code action} on the document {@code doc}, along with
Modified: platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/stats/impl/StatsUtilTest.java =================================================================== --- platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/stats/impl/StatsUtilTest.java 2010-03-16 13:07:30 UTC (rev 27652) +++ platform/core/trunk/xwiki-core/src/test/java/com/xpn/xwiki/stats/impl/StatsUtilTest.java 2010-03-16 13:37:11 UTC (rev 27653) @@ -20,18 +20,45 @@ package com.xpn.xwiki.stats.impl;
import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Calendar; +import java.util.HashSet;
+import org.jmock.Mock; +import org.xwiki.model.reference.DocumentReference; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xpn.xwiki.objects.BaseObject; import com.xpn.xwiki.stats.impl.StatsUtil.PeriodType; +import com.xpn.xwiki.test.AbstractBridgedXWikiComponentTestCase;
-import junit.framework.TestCase; - /** * Unit tests for the {@link StatsUtil} class. + * + * @version $Id$ */ -public class StatsUtilTest extends TestCase +public class StatsUtilTest extends AbstractBridgedXWikiComponentTestCase { + private Mock mockXWiki; + /** + * {@inheritDoc} + * + * @see com.xpn.xwiki.test.AbstractBridgedXWikiComponentTestCase#setUp() + */ + @Override + protected void setUp() throws Exception + { + super.setUp(); + + this.mockXWiki = mock(XWiki.class); + + getContext().setWiki((XWiki) this.mockXWiki.proxy()); + } + + /** * Test for the {@link StatsUtil#getPeriodAsInt(java.util.Date, PeriodType)}. */ public void testGetPeriodAsInt() @@ -48,4 +75,62 @@ b = StatsUtil.getPeriodAsInt(cal.getTime(), PeriodType.DAY) + ""; assertEquals("Wrong day period format", a, b); } + + public void testGetFilteredUsers() throws XWikiException + { + this.mockXWiki.stubs().method("getXWikiPreference").will(returnValue(null)); + this.mockXWiki.stubs().method("Param").will(returnValue(null)); + + assertEquals(new HashSet<DocumentReference>(), StatsUtil.getFilteredUsers(getContext())); + + this.mockXWiki.stubs().method("Param").will(returnValue("XWiki.XWikiGuest")); + + assertEquals(new HashSet<DocumentReference>(Arrays.asList(new DocumentReference("xwiki", "XWiki", "XWikiGuest"))), StatsUtil.getFilteredUsers(getContext())); + + this.mockXWiki.stubs().method("Param").will(returnValue("XWiki.supeRadmin")); + + assertEquals(new HashSet<DocumentReference>(Arrays.asList(new DocumentReference("xwiki", "XWiki", "supeRadmin"))), StatsUtil.getFilteredUsers(getContext())); + + this.mockXWiki.stubs().method("Param").will(returnValue("invalid")); + this.mockXWiki.stubs().method("getDocument").will(returnValue(new XWikiDocument("xwiki", "Space", "invalid"))); + + assertEquals(new HashSet<DocumentReference>(), StatsUtil.getFilteredUsers(getContext())); + + DocumentReference userReference = new DocumentReference("xwiki", "XWiki", "user"); + final XWikiDocument userDoc = new XWikiDocument(userReference); + userDoc.addXObject(new DocumentReference("xwiki", "XWiki", "XWikiUsers"), new BaseObject()); + + this.mockXWiki.stubs().method("Param").will(returnValue("XWiki.user")); + this.mockXWiki.stubs().method("getDocument").with(eq(userReference), ANYTHING).will(returnValue(userDoc)); + + assertEquals(new HashSet<DocumentReference>(Arrays.asList(userReference)), StatsUtil + .getFilteredUsers(getContext())); + + DocumentReference user2Reference = new DocumentReference("xwiki", "XWiki", "user2"); + final XWikiDocument user2Doc = new XWikiDocument(user2Reference); + user2Doc.addXObject(new DocumentReference("xwiki", "XWiki", "XWikiUsers"), new BaseObject()); + + this.mockXWiki.stubs().method("Param").will(returnValue("XWiki.user,XWiki.user2")); + this.mockXWiki.stubs().method("getDocument").with(eq(user2Reference), ANYTHING).will(returnValue(user2Doc)); + + assertEquals(new HashSet<DocumentReference>(Arrays.asList(userReference, user2Reference)), StatsUtil + .getFilteredUsers(getContext())); + + DocumentReference user3Reference = new DocumentReference("otherwiki", "XWiki", "user3"); + final XWikiDocument user3Doc = new XWikiDocument(user3Reference); + user3Doc.addXObject(new DocumentReference("otherwiki", "XWiki", "XWikiUsers"), new BaseObject()); + + DocumentReference groupReference = new DocumentReference("otherwiki", "XWiki", "group"); + final XWikiDocument groupDoc = new XWikiDocument(groupReference); + BaseObject member = new BaseObject(); + member.setStringValue("member", "user3"); + groupDoc.addXObject(new DocumentReference("otherwiki", "XWiki", "XWikiGroups"), member); + + this.mockXWiki.stubs().method("Param").will(returnValue("XWiki.user,XWiki.user2,otherwiki:XWiki.group")); + this.mockXWiki.stubs().method("getDocument").with(eq(groupReference), ANYTHING).will(returnValue(groupDoc)); + this.mockXWiki.stubs().method("getDocument").with(eq(user3Reference), ANYTHING).will(returnValue(user3Doc)); + + assertEquals(new HashSet<DocumentReference>(Arrays.asList(userReference, user2Reference, user3Reference)), + StatsUtil.getFilteredUsers(getContext())); + } }
_______________________________________________ notifications mailing list [email protected] http://lists.xwiki.org/mailman/listinfo/notifications