1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.plugin.rightsmanager

File RightsManager.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart1.png
82% of files have more coverage

Code metrics

122
232
36
1
1,154
530
108
0.47
6.44
36
3

Classes

Class Line # Actions
RightsManager 58 232 0% 108 351
0.110%
 

Contributing tests

This file is covered by 1 test. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20   
21    package com.xpn.xwiki.plugin.rightsmanager;
22   
23    import java.util.ArrayList;
24    import java.util.Collection;
25    import java.util.HashMap;
26    import java.util.Iterator;
27    import java.util.LinkedHashSet;
28    import java.util.List;
29    import java.util.Map;
30   
31    import org.apache.commons.lang3.StringUtils;
32    import org.xwiki.model.reference.DocumentReference;
33    import org.xwiki.model.reference.DocumentReferenceResolver;
34    import org.xwiki.model.reference.EntityReference;
35   
36    import com.xpn.xwiki.XWikiContext;
37    import com.xpn.xwiki.XWikiException;
38    import com.xpn.xwiki.doc.XWikiDocument;
39    import com.xpn.xwiki.internal.plugin.rightsmanager.ReferenceUserIterator;
40    import com.xpn.xwiki.objects.BaseObject;
41    import com.xpn.xwiki.objects.classes.BaseClass;
42    import com.xpn.xwiki.objects.classes.ListClass;
43    import com.xpn.xwiki.objects.classes.PropertyClass;
44    import com.xpn.xwiki.plugin.rightsmanager.utils.AllowDeny;
45    import com.xpn.xwiki.plugin.rightsmanager.utils.LevelTree;
46    import com.xpn.xwiki.plugin.rightsmanager.utils.RequestLimit;
47    import com.xpn.xwiki.plugin.rightsmanager.utils.UsersGroups;
48    import com.xpn.xwiki.user.impl.xwiki.XWikiRightServiceImpl;
49    import com.xpn.xwiki.web.Utils;
50   
51    /**
52    * Hidden toolkit used by the plugin API that make all the plugin's actions.
53    *
54    * @version $Id: e5439f3834eaf470d44b565906c02799abfe815f $
55    * @since 1.1.2
56    * @since 1.2M2
57    */
 
58    public final class RightsManager
59    {
60    /**
61    * Name of the default space where users and groups are stored.
62    */
63    public static final String DEFAULT_USERORGROUP_SPACE = "XWiki";
64   
65    /**
66    * Separator symbol between wiki name and page full name.
67    */
68    private static final String WIKIFULLNAME_SEP = ":";
69   
70    /**
71    * Separator symbol between space name and page name.
72    */
73    private static final String SPACEPAGENAME_SEP = ".";
74   
75    /**
76    * Full name of the wiki preferences document.
77    */
78    private static final String WIKI_PREFERENCES = "XWiki.XWikiPreferences";
79   
80    /**
81    * Name of the space preferences document.
82    */
83    private static final String SPACE_PREFERENCES = "WebPreferences";
84   
85    /**
86    * Name of the "levels" field for the {@link #RIGHTS_CLASS} and {@link #GLOBAL_RIGHTS_CLASS} classes.
87    */
88    private static final String RIGHTSFIELD_LEVELS = "levels";
89   
90    /**
91    * Name of the "users" field for the {@link #RIGHTS_CLASS} and {@link #GLOBAL_RIGHTS_CLASS} classes.
92    */
93    private static final String RIGHTSFIELD_USERS = "users";
94   
95    /**
96    * Name of the "groups" field for the {@link #RIGHTS_CLASS} and {@link #GLOBAL_RIGHTS_CLASS} classes.
97    */
98    private static final String RIGHTSFIELD_GROUPS = "groups";
99   
100    /**
101    * Name of the "allow" field for the {@link #RIGHTS_CLASS} and {@link #GLOBAL_RIGHTS_CLASS} classes.
102    */
103    private static final String RIGHTSFIELD_ALLOW = "allow";
104   
105    /**
106    * Separator symbols of the list fields for the {@link #RIGHTS_CLASS} and {@link #GLOBAL_RIGHTS_CLASS} classes.
107    */
108    private static final String RIGHTSLISTFIELD_SEP = ",|";
109   
110    /**
111    * Join symbol of the list fields for the {@link #RIGHTS_CLASS} and {@link #GLOBAL_RIGHTS_CLASS} classes.
112    */
113    private static final String RIGHTSLISTFIELD_JOIN = "|";
114   
115    /**
116    * Symbol use in HQL "like" command that means "all characters".
117    */
118    private static final String HQLLIKE_ALL_SYMBOL = "%";
119   
120    // ////////////////////////////////////////////////////////////////////////////
121   
122    /**
123    * Unique instance of RightsManager.
124    */
125    private static RightsManager instance;
126   
127    /**
128    * Used to resolve document reference based on another reference.
129    */
130    private DocumentReferenceResolver<String> explicitDocumentReferenceResolver = Utils.getComponent(
131    DocumentReferenceResolver.TYPE_STRING, "explicit");
132   
133    /**
134    * Used to resolve reference based on context.
135    */
136    private DocumentReferenceResolver<String> currentDocumentReferenceResolver = Utils.getComponent(
137    DocumentReferenceResolver.TYPE_STRING, "current");
138   
139    /**
140    * Hidden constructor of RightsManager only access via getInstance().
141    */
 
142  3 toggle private RightsManager()
143    {
144    }
145   
146    /**
147    * @return a unique instance of RightsManager. Thread safe.
148    */
 
149  33 toggle public static RightsManager getInstance()
150    {
151  33 synchronized (RightsManager.class) {
152  33 if (instance == null) {
153  3 instance = new RightsManager();
154    }
155    }
156   
157  33 return instance;
158    }
159   
160    // Groups and users management
161   
162    /**
163    * Get the number of users or groups in the main wiki and the current wiki.
164    *
165    * @param user indicate if methods search for users or groups.
166    * @param matchFields the field to math with values. It is a table of table with :
167    * <ul>
168    * <li>fiedname : the name of the field</li>
169    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
170    * <li>pattern matching : based on HQL "like" command</li>
171    * </ul>
172    * @param context the XWiki context.
173    * @return the number of groups in the main wiki and the current wiki.
174    * @throws XWikiException error when getting number of users or groups.
175    */
 
176  0 toggle public int countAllUsersOrGroups(boolean user, Object[][] matchFields, XWikiContext context) throws XWikiException
177    {
178  0 if (context.isMainWiki()) {
179  0 return countAllLocalUsersOrGroups(user, matchFields, context);
180    }
181   
182  0 return countAllGlobalUsersOrGroups(user, matchFields, context)
183    + countAllLocalUsersOrGroups(user, matchFields, context);
184    }
185   
186    /**
187    * Get the number of users or groups in the provided wiki.
188    *
189    * @param user indicate if methods search for users or groups.
190    * @param wikiName the name of the wiki where to search for users or groups.
191    * @param matchFields the field to math with values. It is a table of table with :
192    * <ul>
193    * <li>fiedname : the name of the field</li>
194    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
195    * <li>pattern matching : based on HQL "like" command</li>
196    * </ul>
197    * @param context the XWiki context.
198    * @return the number of groups in the provided wiki.
199    * @throws XWikiException error when getting number of users or groups.
200    */
 
201  0 toggle public int countAllWikiUsersOrGroups(boolean user, String wikiName, Object[][] matchFields, XWikiContext context)
202    throws XWikiException
203    {
204  0 if (context.isMainWiki()) {
205  0 return countAllLocalUsersOrGroups(user, matchFields, context);
206    }
207   
208  0 String database = context.getWikiId();
209   
210  0 try {
211  0 context.setWikiId(wikiName);
212  0 return countAllLocalUsersOrGroups(user, matchFields, context);
213    } finally {
214  0 context.setWikiId(database);
215    }
216    }
217   
218    /**
219    * Get the number of users or groups in the main wiki.
220    *
221    * @param user indicate if methods search for users or groups.
222    * @param matchFields the field to math with values. It is a table of table with :
223    * <ul>
224    * <li>fiedname : the name of the field</li>
225    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
226    * <li>pattern matching : based on HQL "like" command</li>
227    * </ul>
228    * @param context the XWiki context.
229    * @return the number of groups in the main wiki.
230    * @throws XWikiException error when getting number of users or groups.
231    */
 
232  0 toggle public int countAllGlobalUsersOrGroups(boolean user, Object[][] matchFields, XWikiContext context)
233    throws XWikiException
234    {
235  0 if (context.isMainWiki()) {
236  0 return countAllLocalUsersOrGroups(user, matchFields, context);
237    }
238   
239  0 return countAllWikiUsersOrGroups(user, context.getMainXWiki(), matchFields, context);
240    }
241   
242    /**
243    * Get the number of users or groups in the current wiki.
244    *
245    * @param user indicate if methods search for users or groups.
246    * @param matchFields the field to math with values. It is a table of table with :
247    * <ul>
248    * <li>fiedname : the name of the field</li>
249    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
250    * <li>pattern matching : based on HQL "like" command</li>
251    * </ul>
252    * @param context the XWiki context.
253    * @return the number of groups in the current wiki.
254    * @throws XWikiException error when getting number of users or groups.
255    */
 
256  5 toggle public int countAllLocalUsersOrGroups(boolean user, Object[][] matchFields, XWikiContext context)
257    throws XWikiException
258    {
259  5 if (user) {
260  1 return context.getWiki().getGroupService(context).countAllMatchedUsers(matchFields, context);
261    } else {
262  4 return context.getWiki().getGroupService(context).countAllMatchedGroups(matchFields, context);
263    }
264    }
265   
266    /**
267    * Get all users or groups in the main wiki and the current.
268    *
269    * @param user indicate if it is a user or a group.
270    * @param matchFields the field to math with values. It is a table of table with :
271    * <ul>
272    * <li>fiedname : the name of the field</li>
273    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
274    * <li>pattern matching : based on HQL "like" command</li>
275    * </ul>
276    * @param withdetails indicate if the methods return {@link List} or {@link String} or {@link List} of
277    * {@link XWikiDocument}.
278    * @param limit the maximum number of result to return and index of the first element.
279    * @param order the fields to order from. It is a table of table with :
280    * <ul>
281    * <li>fieldname : the name of the field</li>
282    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
283    * </ul>
284    * @param context the XWiki context.
285    * @return a {@link List} of {@link String} containing user or group name if <code>withdetails</code> is false,
286    * otherwise a {@link List} of {@link XWikiDocument} containing user or group.
287    * @throws XWikiException error when searching from users or groups.
288    */
 
289  0 toggle public List<?> getAllMatchedUsersOrGroups(boolean user, Object[][] matchFields, boolean withdetails,
290    RequestLimit limit, Object[][] order, XWikiContext context) throws XWikiException
291    {
292  0 if (context.isMainWiki()) {
293  0 return getAllMatchedLocalUsersOrGroups(user, matchFields, withdetails, limit, order, context);
294    }
295   
296  0 List<Object> userOrGroupList = new ArrayList<Object>();
297   
298  0 int nbGlobalUsersOrGroups = countAllGlobalUsersOrGroups(user, null, context);
299   
300  0 int newstart = limit.getStart();
301   
302    // Get global groups
303  0 if (newstart < nbGlobalUsersOrGroups) {
304  0 userOrGroupList.addAll(getAllMatchedGlobalUsersOrGroups(user, matchFields, withdetails, new RequestLimit(
305    limit.getNb(), newstart), order, context));
306  0 newstart = 0;
307    } else {
308  0 newstart = newstart - nbGlobalUsersOrGroups;
309    }
310   
311    // Get local groups
312  0 if (limit.getNb() > userOrGroupList.size()) {
313  0 userOrGroupList.addAll(getAllMatchedLocalUsersOrGroups(user, matchFields, withdetails, new RequestLimit(
314    limit.getNb() - userOrGroupList.size(), newstart), order, context));
315  0 } else if (limit.getNb() <= 0) {
316  0 userOrGroupList.addAll(getAllMatchedLocalUsersOrGroups(user, matchFields, withdetails, new RequestLimit(0,
317    newstart), order, context));
318    }
319   
320  0 return userOrGroupList;
321    }
322   
323    /**
324    * Get all users or groups in the main wiki.
325    *
326    * @param user indicate if it is a user or a group.
327    * @param matchFields the field to math with values. It is a table of table with :
328    * <ul>
329    * <li>fiedname : the name of the field</li>
330    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
331    * <li>pattern matching : based on HQL "like" command</li>
332    * </ul>
333    * @param withdetails indicate if the methods return {@link List} or {@link String} or {@link List} of
334    * {@link XWikiDocument}.
335    * @param limit the maximum number of result to return and index of the first element.
336    * @param order the fields to order from. It is a table of table with :
337    * <ul>
338    * <li>fieldname : the name of the field</li>
339    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
340    * </ul>
341    * @param context the XWiki context.
342    * @return a {@link List} of {@link String} containing user or group name if <code>withdetails</code> is false,
343    * otherwise a {@link List} of {@link XWikiDocument} containing user or group.
344    * @throws XWikiException error when searching from users or groups.
345    */
 
346  0 toggle public List<?> getAllMatchedGlobalUsersOrGroups(boolean user, Object[][] matchFields, boolean withdetails,
347    RequestLimit limit, Object[][] order, XWikiContext context) throws XWikiException
348    {
349  0 if (context.isMainWiki()) {
350  0 return getAllMatchedLocalUsersOrGroups(user, matchFields, withdetails, limit, order, context);
351    }
352   
353  0 return getAllMatchedWikiUsersOrGroups(user, context.getMainXWiki(), matchFields, withdetails, limit, order,
354    context);
355    }
356   
357    /**
358    * Get all users or groups in the provided wiki.
359    *
360    * @param user indicate if it is a user or a group.
361    * @param wikiName the name of the wiki where to search.
362    * @param matchFields the field to math with values. It is a table of table with :
363    * <ul>
364    * <li>fiedname : the name of the field</li>
365    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
366    * <li>pattern matching : based on HQL "like" command</li>
367    * </ul>
368    * @param withdetails indicate if the methods return {@link List} or {@link String} or {@link List} of
369    * {@link XWikiDocument}.
370    * @param limit the maximum number of result to return and index of the first element.
371    * @param order the fields to order from. It is a table of table with :
372    * <ul>
373    * <li>fieldname : the name of the field</li>
374    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
375    * </ul>
376    * @param context the XWiki context.
377    * @return a {@link List} of {@link String} containing user or group name if <code>withdetails</code> is false,
378    * otherwise a {@link List} of {@link XWikiDocument} containing user or group.
379    * @throws XWikiException error when searching from users or groups.
380    */
 
381  0 toggle public List<?> getAllMatchedWikiUsersOrGroups(boolean user, String wikiName, Object[][] matchFields,
382    boolean withdetails, RequestLimit limit, Object[][] order, XWikiContext context) throws XWikiException
383    {
384  0 if (context.isMainWiki()) {
385  0 return getAllMatchedLocalUsersOrGroups(user, matchFields, withdetails, limit, order, context);
386    }
387   
388  0 String database = context.getWikiId();
389   
390  0 try {
391  0 context.setWikiId(wikiName);
392   
393  0 List<?> localGroupList =
394    getAllMatchedLocalUsersOrGroups(user, matchFields, withdetails, limit, order, context);
395   
396  0 if (localGroupList != null && !withdetails) {
397  0 List<String> wikiGroupList = new ArrayList<String>(localGroupList.size());
398  0 for (Object groupName : localGroupList) {
399  0 wikiGroupList.add(wikiName + WIKIFULLNAME_SEP + groupName);
400    }
401   
402  0 localGroupList = wikiGroupList;
403    }
404   
405  0 return localGroupList;
406    } finally {
407  0 context.setWikiId(database);
408    }
409    }
410   
411    /**
412    * Get all users or groups in the current wiki.
413    *
414    * @param user indicate if it is a user or a group.
415    * @param matchFields the field to math with values. It is a table of table with :
416    * <ul>
417    * <li>fiedname : the name of the field</li>
418    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
419    * <li>pattern matching : based on HQL "like" command</li>
420    * </ul>
421    * @param withdetails indicate if the methods return {@link List} or {@link String} or {@link List} of
422    * {@link XWikiDocument}.
423    * @param limit the maximum number of result to return and index of the first element.
424    * @param order the fields to order from. It is a table of table with :
425    * <ul>
426    * <li>fieldname : the name of the field</li>
427    * <li>fieldtype : for example StringProperty. If null the field is considered as document field</li>
428    * </ul>
429    * @param context the XWiki context.
430    * @return a {@link List} of {@link String} containing user or group name if <code>withdetails</code> is false,
431    * otherwise a {@link List} of {@link XWikiDocument} containing user or group.
432    * @throws XWikiException error when searching from users or groups.
433    */
 
434  5 toggle public List<?> getAllMatchedLocalUsersOrGroups(boolean user, Object[][] matchFields, boolean withdetails,
435    RequestLimit limit, Object[][] order, XWikiContext context) throws XWikiException
436    {
437  5 if (user) {
438  1 return context.getWiki().getGroupService(context)
439    .getAllMatchedUsers(matchFields, withdetails, limit.getNb(), limit.getStart(), order, context);
440    } else {
441  4 return context.getWiki().getGroupService(context)
442    .getAllMatchedGroups(matchFields, withdetails, limit.getNb(), limit.getStart(), order, context);
443    }
444    }
445   
446    /**
447    * Get all groups containing provided user.
448    *
449    * @param member the name of the member (user or group).
450    * @param nb the maximum number of result to return.
451    * @param start the index of the first found member to return.
452    * @param context the XWiki context.
453    * @return the {@link Collection} of {@link String} containing group name.
454    * @throws XWikiException error when browsing groups.
455    */
 
456  0 toggle public Collection<String> getAllGroupsNamesForMember(String member, int nb, int start, XWikiContext context)
457    throws XWikiException
458    {
459  0 return context.getWiki().getGroupService(context).getAllGroupsNamesForMember(member, nb, start, context);
460    }
461   
462    /**
463    * Get all users provided group contains.
464    *
465    * @param group the name of the group.
466    * @param nb the maximum number of result to return.
467    * @param start the index of the first found user to return.
468    * @param context the XWiki context.
469    * @return the {@link Collection} of {@link String} containing user name.
470    * @throws XWikiException error when browsing groups.
471    */
 
472  0 toggle public Collection<String> getAllMembersNamesForGroup(String group, int nb, int start, XWikiContext context)
473    throws XWikiException
474    {
475  0 return context.getWiki().getGroupService(context).getAllMembersNamesForGroup(group, nb, start, context);
476    }
477   
478    /**
479    * Get members of provided group.
480    *
481    * @param group the group.
482    * @param matchField a string to search in result to filter.
483    * @param nb the maximum number of result to return.
484    * @param start the index of the first found user to return.
485    * @param orderAsc if true, the result is ordered ascendent, if false it descendant. If null no order is applied.
486    * @param context the XWiki context.
487    * @return the {@link Collection} of {@link String} containing member name.
488    * @throws XWikiException error when browsing groups.
489    * @since 1.6M1
490    */
 
491  7 toggle public Collection<String> getAllMatchedMembersNamesForGroup(String group, String matchField, int nb, int start,
492    Boolean orderAsc, XWikiContext context) throws XWikiException
493    {
494  7 return context.getWiki().getGroupService(context)
495    .getAllMatchedMembersNamesForGroup(group, matchField, nb, start, orderAsc, context);
496    }
497   
498    /**
499    * Return the number of groups containing provided member.
500    *
501    * @param member the name of the member (user or group).
502    * @param context the XWiki context.
503    * @return the number of groups.
504    * @throws XWikiException error when getting number of users.
505    */
 
506  0 toggle public int countAllGroupsNamesForMember(String member, XWikiContext context) throws XWikiException
507    {
508  0 return context.getWiki().getGroupService(context).countAllGroupsNamesForMember(member, context);
509    }
510   
511    /**
512    * Return the number of members provided group contains.
513    *
514    * @param group the name of the group.
515    * @param context the XWiki context.
516    * @return the number of members.
517    * @throws XWikiException error when getting number of groups.
518    */
 
519  9 toggle public int countAllMembersNamesForGroup(String group, XWikiContext context) throws XWikiException
520    {
521  9 return context.getWiki().getGroupService(context).countAllMembersNamesForGroup(group, context);
522    }
523   
524    // Rights management
525   
526    /**
527    * Get the {@link LevelTree} {@link Map} for the provided rights levels.
528    *
529    * @param preferences the document containing rights preferences.
530    * @param levelsToMatch the levels names to check ("view", "edit", etc.).
531    * @param global indicate it is global rights (wiki or space) or document rights.
532    * @param context the XWiki context.
533    * @return the {@link Map} containing [levelname : {@link LevelTree}].
534    * @throws XWikiException error when browsing rights preferences.
535    */
 
536  0 toggle private Map<String, LevelTree> getLevelTreeMap(XWikiDocument preferences, List<String> levelsToMatch,
537    boolean global, XWikiContext context) throws XWikiException
538    {
539  0 Map<String, LevelTree> rightsMap = new HashMap<String, LevelTree>();
540   
541  0 fillLevelTreeMap(rightsMap, preferences, levelsToMatch, global, true, context);
542   
543  0 return rightsMap;
544    }
545   
546    /**
547    * Get the {@link LevelTree} {@link Map} for he provided rights levels.
548    *
549    * @param spaceOrPage the space of page where to get XWikiRights. If null get wiki rights.
550    * @param levelsToMatch the levels names to check ("view", "edit", etc.).
551    * @param context the XWiki context.
552    * @return the {@link Map} containing [levelname : {@link LevelTree}].
553    * @throws XWikiException error when browsing rights preferences.
554    */
 
555  0 toggle public Map<String, LevelTree> getLevelTreeMap(String spaceOrPage, List<String> levelsToMatch, XWikiContext context)
556    throws XWikiException
557    {
558  0 XWikiDocument preferences = getXWikiPreferencesDoc(spaceOrPage, context);
559   
560  0 return getLevelTreeMap(preferences, levelsToMatch, isGlobal(preferences, spaceOrPage), context);
561    }
562   
563    /**
564    * Fill the {@link LevelTree} {@link Map}.
565    *
566    * @param rightsMap the {@link LevelTree} {@link Map} to fill.
567    * @param levelInherited the levels names for which to find inheritance.
568    * @param bobj the object containing rights preferences.
569    * @param levelsToMatch the levels names to check ("view", "edit", etc.).
570    * @param direct if true fill the {@link LevelTree#direct} field, otherwise fill the {@link LevelTree#inherited}.
571    * @param context the XWiki context.
572    */
 
573  0 toggle private void fillLevelTreeMap(Map<String, LevelTree> rightsMap, List<String> levelInherited, BaseObject bobj,
574    List<String> levelsToMatch, boolean direct, XWikiContext context)
575    {
576  0 List<String> users =
577    ListClass.getListFromString(bobj.getStringValue(RIGHTSFIELD_USERS), RIGHTSLISTFIELD_SEP, false);
578  0 List<String> groups =
579    ListClass.getListFromString(bobj.getStringValue(RIGHTSFIELD_GROUPS), RIGHTSLISTFIELD_SEP, false);
580  0 List<String> levels =
581    ListClass.getListFromString(bobj.getStringValue(RIGHTSFIELD_LEVELS), RIGHTSLISTFIELD_SEP, false);
582  0 boolean allow = (bobj.getIntValue(RIGHTSFIELD_ALLOW) == 1);
583   
584  0 for (String levelName : levels) {
585  0 if (levelsToMatch == null || levelsToMatch.contains(levelName)) {
586  0 LevelTree level;
587  0 if (!rightsMap.containsKey(levelName)) {
588  0 level = new LevelTree();
589  0 rightsMap.put(levelName, level);
590    } else {
591  0 level = rightsMap.get(levelName);
592    }
593   
594  0 AllowDeny allowdeny;
595  0 if (direct) {
596  0 if (levelInherited != null) {
597  0 levelInherited.add(levelName);
598    }
599   
600  0 if (level.direct == null) {
601  0 level.direct = new AllowDeny();
602    }
603  0 allowdeny = level.direct;
604    } else {
605  0 if (level.inherited == null) {
606  0 level.inherited = new AllowDeny();
607    }
608  0 allowdeny = level.inherited;
609    }
610   
611  0 UsersGroups usersgroups = allow ? allowdeny.allow : allowdeny.deny;
612   
613  0 usersgroups.users.addAll(users);
614  0 usersgroups.groups.addAll(groups);
615    }
616    }
617    }
618   
619    /**
620    * Fill the {@link LevelTree} {@link Map} inherited part.
621    *
622    * @param rightsMap the {@link LevelTree} {@link Map} to fill.
623    * @param levelInheritedIn the levels names for which to find inheritance.
624    * @param preferences the document containing rights preferences.
625    * @param levelsToMatch the levels names to check ("view", "edit", etc.).
626    * @param global indicate it is global rights (wiki or space) or document rights.
627    * @param context the XWiki context.
628    * @throws XWikiException error when browsing rights preferences.
629    */
 
630  0 toggle private void fillLevelTreeMapInherited(Map<String, LevelTree> rightsMap, List<String> levelInheritedIn,
631    XWikiDocument preferences, List<String> levelsToMatch, boolean global, XWikiContext context)
632    throws XWikiException
633    {
634  0 List<String> levelInherited = levelInheritedIn;
635   
636    // Get document containing inherited rights
637  0 XWikiDocument parentPreferences = getParentPreference(preferences, global, context);
638   
639  0 if (parentPreferences != null) {
640    // Fill levels where to find inheritance
641  0 if (levelInherited == null) {
642  0 levelInherited = new ArrayList<String>();
643    }
644   
645  0 for (String levelName : levelsToMatch) {
646  0 if (!rightsMap.containsKey(levelName) || (rightsMap.get(levelName)).inherited == null) {
647  0 levelInherited.add(levelName);
648    }
649    }
650   
651    // Find inheritance if needed
652  0 if (!levelInherited.isEmpty()) {
653  0 fillLevelTreeMap(rightsMap, parentPreferences, levelInherited, true, false, context);
654    }
655    }
656    }
657   
658    /**
659    * Fill the {@link LevelTree} {@link Map}.
660    *
661    * @param rightsMap the {@link LevelTree} {@link Map} to fill.
662    * @param preferences the document containing rights preferences.
663    * @param levelsToMatch the levels names to check ("view", "edit", etc.).
664    * @param global indicate it is global rights (wiki or space) or document rights.
665    * @param direct if true fill the {@link LevelTree#direct} field, otherwise fill the {@link LevelTree#inherited}.
666    * @param context the XWiki context.
667    * @throws XWikiException error when browsing rights preferences.
668    */
 
669  0 toggle private void fillLevelTreeMap(Map<String, LevelTree> rightsMap, XWikiDocument preferences,
670    List<String> levelsToMatch, boolean global, boolean direct, XWikiContext context) throws XWikiException
671    {
672  0 List<String> levelInherited = null;
673  0 if (levelsToMatch == null) {
674  0 levelInherited = new ArrayList<String>();
675    }
676   
677  0 if (!preferences.isNew()) {
678  0 EntityReference rightClassReference =
679  0 global ? XWikiRightServiceImpl.GLOBALRIGHTCLASS_REFERENCE
680    : XWikiRightServiceImpl.RIGHTCLASS_REFERENCE;
681  0 List<BaseObject> rightObjects = preferences.getXObjects(rightClassReference);
682  0 if (rightObjects != null) {
683  0 for (BaseObject bobj : rightObjects) {
684  0 fillLevelTreeMap(rightsMap, levelInherited, bobj, levelsToMatch, direct, context);
685    }
686    }
687    }
688   
689  0 fillLevelTreeMapInherited(rightsMap, levelInherited, preferences, levelsToMatch, global, context);
690    }
691   
692    /**
693    * Get the document containing inherited rights of provided document.
694    *
695    * @param currentPreference the document for which to find parent preferences document.
696    * @param currentGlobal indicate if current preferences document is global.
697    * @param context the XWiki context.
698    * @return the document containing inherited rights of provided document.
699    * @throws XWikiException error when browsing rights preferences.
700    */
 
701  0 toggle public XWikiDocument getParentPreference(XWikiDocument currentPreference, boolean currentGlobal,
702    XWikiContext context) throws XWikiException
703    {
704  0 XWikiDocument parentPreferences = null;
705   
706  0 if (currentGlobal) {
707  0 if (currentPreference.getFullName().equals(WIKI_PREFERENCES)) {
708  0 if (!context.isMainWiki()) {
709  0 parentPreferences =
710    context.getWiki().getDocument(context.getMainXWiki() + WIKIFULLNAME_SEP + WIKI_PREFERENCES,
711    context);
712    }
713  0 } else if (currentPreference.getName().equals(SPACE_PREFERENCES)) {
714  0 String parentspace = currentPreference.getStringValue(WIKI_PREFERENCES, "parent");
715  0 if (parentspace.trim().length() > 0) {
716  0 parentPreferences =
717    context.getWiki().getDocument(parentspace + SPACEPAGENAME_SEP + SPACE_PREFERENCES, context);
718    } else {
719  0 parentPreferences = context.getWiki().getDocument(WIKI_PREFERENCES, context);
720    }
721   
722  0 if (parentPreferences == currentPreference) {
723  0 parentPreferences = null;
724    }
725    }
726    } else {
727  0 parentPreferences =
728    context.getWiki().getDocument(currentPreference.getSpace() + SPACEPAGENAME_SEP + SPACE_PREFERENCES,
729    context);
730    }
731   
732  0 return parentPreferences;
733    }
734   
735    /**
736    * Get the document containing inherited rights of provided document.
737    *
738    * @param spaceOrPage the space of page where to get XWikiRights. If null get wiki rights.
739    * @param context the XWiki context.
740    * @return the document containing inherited rights of provided document.
741    * @throws XWikiException error when browsing rights preferences.
742    */
 
743  0 toggle public XWikiDocument getParentPreference(String spaceOrPage, XWikiContext context) throws XWikiException
744    {
745  0 XWikiDocument preferences = getXWikiPreferencesDoc(spaceOrPage, context);
746   
747  0 boolean global = isGlobal(preferences, spaceOrPage);
748   
749  0 return getParentPreference(preferences, global, context);
750    }
751   
752    /**
753    * Get level right tree.
754    *
755    * @param doc the document containing rights preferences.
756    * @param levelName the level right name ("view", "delete"...).
757    * @param global indicate it is global rights (wiki or space) or document rights.
758    * @param context the XWiki context.
759    * @return the {@link LevelTree}.
760    * @throws XWikiException error when browsing rights preferences.
761    */
 
762  0 toggle private LevelTree getLevel(XWikiDocument doc, String levelName, boolean global, XWikiContext context)
763    throws XWikiException
764    {
765  0 if (doc.isNew()) {
766  0 return null;
767    }
768   
769  0 List<String> rights = new ArrayList<String>();
770  0 rights.add(levelName);
771   
772  0 Map<String, LevelTree> rightsMap = getLevelTreeMap(doc, rights, global, context);
773   
774  0 return rightsMap.get(levelName);
775    }
776   
777    /**
778    * Get document containing rights preferences for provided wiki, space or document.
779    *
780    * @param spaceOrPage the space of page where to get XWikiRights. If null get wiki rights.
781    * @param context the XWiki context.
782    * @return the document containing rights preferences.
783    * @throws XWikiException error when getting document from database.
784    */
 
785  0 toggle private XWikiDocument getXWikiPreferencesDoc(String spaceOrPage, XWikiContext context) throws XWikiException
786    {
787  0 XWikiDocument xwikidoc = null;
788   
789  0 if (spaceOrPage != null) {
790  0 xwikidoc = context.getWiki().getDocument(spaceOrPage, context);
791   
792  0 if (xwikidoc.isNew()) {
793  0 xwikidoc = context.getWiki().getDocument(spaceOrPage + SPACEPAGENAME_SEP + SPACE_PREFERENCES, context);
794    }
795    } else {
796  0 xwikidoc = context.getWiki().getDocument(WIKI_PREFERENCES, context);
797    }
798   
799  0 return xwikidoc;
800    }
801   
802    /**
803    * Indicate if provided document contains global or document rights.
804    *
805    * @param preferences the document containing rights preferences.
806    * @param spaceOrPage the space of page where to get XWikiRights. If null get wiki rights.
807    * @return true if provided document contains global rights, false otherwise.
808    */
 
809  0 toggle private boolean isGlobal(XWikiDocument preferences, String spaceOrPage)
810    {
811  0 return !preferences.getFullName().equals(spaceOrPage);
812    }
813   
814    /**
815    * Get level right tree.
816    *
817    * @param spaceOrPage the space of page where to get XWikiRights. If null get wiki rights.
818    * @param levelName the level right name ("view", "delete"...).
819    * @param context the XWiki context.
820    * @return the {@link LevelTree}.
821    * @throws XWikiException error when browsing rights.
822    */
 
823  0 toggle public LevelTree getTreeLevel(String spaceOrPage, String levelName, XWikiContext context) throws XWikiException
824    {
825  0 XWikiDocument preferences = getXWikiPreferencesDoc(spaceOrPage, context);
826   
827  0 return getLevel(preferences, levelName, isGlobal(preferences, spaceOrPage), context);
828    }
829   
830    /**
831    * Remove a user or group from rights preferences document for provided level.
832    *
833    * @param spaceOrPage the space of page where to get XWikiRights. If null get wiki rights.
834    * @param userOrGroup the name of the user or group.
835    * @param user indicate if it is a user or group.
836    * @param levelName the name of the right level.
837    * @param allow indicate if user is removed from allow right or deny right.
838    * @param comment the comment to use when saving preferences document.
839    * @param context the XWiki context.
840    * @throws XWikiException error when browsing rights.
841    */
 
842  0 toggle public void removeUserOrGroupFromLevel(String spaceOrPage, String userOrGroup, boolean user, String levelName,
843    boolean allow, String comment, XWikiContext context) throws XWikiException
844    {
845  0 XWikiDocument preferences = getXWikiPreferencesDoc(spaceOrPage, context);
846   
847  0 boolean global = isGlobal(preferences, spaceOrPage);
848   
849  0 EntityReference rightClassReference =
850  0 global ? XWikiRightServiceImpl.GLOBALRIGHTCLASS_REFERENCE : XWikiRightServiceImpl.RIGHTCLASS_REFERENCE;
851   
852  0 boolean needUpdate = false;
853   
854  0 List<BaseObject> rightObjects = preferences.getXObjects(rightClassReference);
855  0 if (rightObjects != null) {
856  0 for (BaseObject bobj : rightObjects) {
857  0 List<String> levels =
858    ListClass.getListFromString(bobj.getStringValue(RIGHTSFIELD_LEVELS), RIGHTSLISTFIELD_SEP, false);
859   
860  0 if (levels.contains(levelName)) {
861  0 needUpdate |= removeUserOrGroupFromRight(bobj, null, null, userOrGroup, user, context);
862    }
863    }
864   
865  0 if (needUpdate) {
866  0 context.getWiki().saveDocument(preferences, comment, context);
867    }
868    }
869    }
870   
871    /**
872    * Remove all references to provided user or group from provided right object.
873    *
874    * @param right the object containing the right preferences.
875    * @param userOrGroupWiki the name of the wiki of the use or group.
876    * @param userOrGroupSpace the name of the space of the use or group.
877    * @param userOrGroupName the name of the use or group.
878    * @param user indicate if it is a user or a group.
879    * @param context the XWiki context.
880    * @return true if user or group has been found and removed.
881    */
 
882  0 toggle public boolean removeUserOrGroupFromRight(BaseObject right, String userOrGroupWiki, String userOrGroupSpace,
883    String userOrGroupName, boolean user, XWikiContext context)
884    {
885  0 boolean needUpdate = false;
886   
887  0 String userOrGroupField = user ? RIGHTSFIELD_USERS : RIGHTSFIELD_GROUPS;
888   
889  0 List<String> usersOrGroups =
890    ListClass.getListFromString(right.getStringValue(userOrGroupField), RIGHTSLISTFIELD_SEP, false);
891   
892  0 if (userOrGroupWiki != null) {
893  0 needUpdate |= usersOrGroups.remove(userOrGroupWiki + WIKIFULLNAME_SEP + userOrGroupName);
894    }
895   
896  0 if (context.getWikiId() == null || context.getWikiId().equalsIgnoreCase(userOrGroupWiki)) {
897  0 needUpdate |= usersOrGroups.remove(userOrGroupName);
898   
899  0 if (userOrGroupSpace == null || userOrGroupSpace.equals(DEFAULT_USERORGROUP_SPACE)) {
900  0 needUpdate |= usersOrGroups.remove(userOrGroupSpace + SPACEPAGENAME_SEP + userOrGroupName);
901    }
902    }
903   
904  0 if (needUpdate) {
905  0 right.setStringValue(userOrGroupField, StringUtils.join(usersOrGroups.toArray(), RIGHTSLISTFIELD_JOIN));
906    }
907   
908  0 return needUpdate;
909    }
910   
911    /**
912    * Remove all references to provided user or group from provided rights document.
913    *
914    * @param rightsDocument the document containing the rights preferences.
915    * @param userOrGroupWiki the name of the wiki of the use or group.
916    * @param userOrGroupSpace the name of the space of the use or group.
917    * @param userOrGroupName the name of the use or group.
918    * @param user indicate if it is a user or a group.
919    * @param global indicate if user or group is removed from global or document rights.
920    * @param context the XWiki context.
921    * @return true if user or group has been found and removed.
922    */
 
923  0 toggle public boolean removeUserOrGroupFromRights(XWikiDocument rightsDocument, String userOrGroupWiki,
924    String userOrGroupSpace, String userOrGroupName, boolean user, boolean global, XWikiContext context)
925    {
926  0 boolean needUpdate = false;
927   
928  0 EntityReference rightClassReference =
929  0 global ? XWikiRightServiceImpl.GLOBALRIGHTCLASS_REFERENCE : XWikiRightServiceImpl.RIGHTCLASS_REFERENCE;
930   
931  0 List<BaseObject> rightObjects = rightsDocument.getXObjects(rightClassReference);
932  0 if (rightObjects != null) {
933  0 for (BaseObject bobj : rightObjects) {
934  0 if (bobj == null) {
935  0 continue;
936    }
937  0 needUpdate |=
938    removeUserOrGroupFromRight(bobj, userOrGroupWiki, userOrGroupSpace, userOrGroupName, user, context);
939   
940  0 if (needUpdate && bobj.getStringValue(RIGHTSFIELD_USERS).trim().length() == 0
941    && bobj.getStringValue(RIGHTSFIELD_GROUPS).trim().length() == 0) {
942  0 rightsDocument.removeXObject(bobj);
943    }
944    }
945    }
946   
947  0 return needUpdate;
948    }
949   
950    /**
951    * Remove all references to provided user or group from provided rights document.
952    *
953    * @param rightsDocument the document containing the rights preferences.
954    * @param userOrGroupWiki the name of the wiki of the use or group.
955    * @param userOrGroupSpace the name of the space of the use or group.
956    * @param userOrGroupName the name of the use or group.
957    * @param user indicate if it is a user or a group.
958    * @param context the XWiki context.
959    * @return true if user or group has been found and removed.
960    */
 
961  0 toggle public boolean removeUserOrGroupFromAllRights(XWikiDocument rightsDocument, String userOrGroupWiki,
962    String userOrGroupSpace, String userOrGroupName, boolean user, XWikiContext context)
963    {
964  0 return removeUserOrGroupFromRights(rightsDocument, userOrGroupWiki, userOrGroupSpace, userOrGroupName, user,
965    true, context)
966    || removeUserOrGroupFromRights(rightsDocument, userOrGroupWiki, userOrGroupSpace, userOrGroupName, user,
967    false, context);
968    }
969   
970    /**
971    * Remove all references to provided user or group from all rights documents.
972    *
973    * @param userOrGroupWiki the name of the wiki of the use or group.
974    * @param userOrGroupSpace the name of the space of the use or group.
975    * @param userOrGroupName the name of the use or group.
976    * @param user indicate if it is a user or a group.
977    * @param context the XWiki context.
978    * @throws XWikiException error when browsing rights.
979    */
 
980  0 toggle public void removeUserOrGroupFromAllRights(String userOrGroupWiki, String userOrGroupSpace, String userOrGroupName,
981    boolean user, XWikiContext context) throws XWikiException
982    {
983  0 List<String> parameterValues = new ArrayList<String>();
984   
985  0 String fieldName;
986  0 if (user) {
987  0 fieldName = RIGHTSFIELD_USERS;
988    } else {
989  0 fieldName = RIGHTSFIELD_GROUPS;
990    }
991   
992  0 BaseClass rightClass = context.getWiki().getRightsClass(context);
993  0 BaseClass globalRightClass = context.getWiki().getGlobalRightsClass(context);
994   
995  0 String fieldTypeName = ((PropertyClass) rightClass.get(fieldName)).newProperty().getClass().getSimpleName();
996   
997  0 StringBuilder where =
998    new StringBuilder(", BaseObject as obj" + ", " + fieldTypeName + " as prop where doc.fullName=obj.name"
999    + " and (obj.className=? or obj.className=?)");
1000  0 parameterValues.add(rightClass.getName());
1001  0 parameterValues.add(globalRightClass.getName());
1002   
1003  0 where.append(" and obj.id=prop.id.id");
1004   
1005  0 where.append(" and prop.name=?");
1006  0 parameterValues.add(fieldName);
1007   
1008  0 where.append(" and prop.value like ?");
1009   
1010  0 if (context.getWikiId() == null || context.getWikiId().equalsIgnoreCase(userOrGroupWiki)) {
1011  0 if (userOrGroupSpace == null || userOrGroupSpace.equals(DEFAULT_USERORGROUP_SPACE)) {
1012  0 parameterValues.add(HQLLIKE_ALL_SYMBOL + userOrGroupName + HQLLIKE_ALL_SYMBOL);
1013    } else {
1014  0 parameterValues.add(HQLLIKE_ALL_SYMBOL + userOrGroupSpace + SPACEPAGENAME_SEP + userOrGroupName
1015    + HQLLIKE_ALL_SYMBOL);
1016    }
1017    } else {
1018  0 parameterValues.add(HQLLIKE_ALL_SYMBOL + userOrGroupWiki + WIKIFULLNAME_SEP + userOrGroupName
1019    + HQLLIKE_ALL_SYMBOL);
1020    }
1021   
1022  0 List<XWikiDocument> documentList =
1023    context.getWiki().getStore().searchDocuments(where.toString(), parameterValues, context);
1024   
1025  0 for (XWikiDocument groupDocument : documentList) {
1026  0 if (removeUserOrGroupFromAllRights(groupDocument, userOrGroupWiki, userOrGroupSpace, userOrGroupName, user,
1027    context)) {
1028  0 context.getWiki().saveDocument(groupDocument, context);
1029    }
1030    }
1031    }
1032   
1033    /**
1034    * Remove "direct" rights for wiki, space or document. This means that after that inherited right will be used.
1035    *
1036    * @param spaceOrPage the space of page where to get XWikiRights. If null get wiki rights.
1037    * @param levelNames the levels names to check ("view", "edit", etc.).
1038    * @param comment the comment to use when saving preferences document.
1039    * @param context the XWiki context.
1040    * @throws XWikiException error when browsing rights.
1041    */
 
1042  0 toggle public void removeDirectRights(String spaceOrPage, List<String> levelNames, String comment, XWikiContext context)
1043    throws XWikiException
1044    {
1045  0 XWikiDocument preferences = getXWikiPreferencesDoc(spaceOrPage, context);
1046   
1047  0 boolean global = isGlobal(preferences, spaceOrPage);
1048   
1049  0 EntityReference rightClassReference =
1050  0 global ? XWikiRightServiceImpl.GLOBALRIGHTCLASS_REFERENCE : XWikiRightServiceImpl.RIGHTCLASS_REFERENCE;
1051   
1052  0 List<BaseObject> rightObjects = preferences.getXObjects(rightClassReference);
1053  0 if (rightObjects != null && !rightObjects.isEmpty()) {
1054  0 preferences.removeXObjects(rightClassReference);
1055  0 context.getWiki().saveDocument(preferences, comment, context);
1056    }
1057    }
1058   
1059    /**
1060    * Browse a group and groups it contains to find provided member (user or group).
1061    *
1062    * @param groupName the group name where to search for member.
1063    * @param memberName the name of the member to find.
1064    * @param groupCacheIn a map containing a set a group and its corresponding members already retrieved.
1065    * @param context the XWiki context.
1066    * @return true if the member has been found, false otherwise.
1067    * @throws XWikiException error when browsing groups.
1068    */
 
1069  0 toggle public boolean groupContainsMember(String groupName, String memberName,
1070    Map<String, Collection<String>> groupCacheIn, XWikiContext context) throws XWikiException
1071    {
1072  0 boolean found = false;
1073   
1074  0 Map<String, Collection<String>> groupCache = groupCacheIn;
1075  0 if (groupCache == null) {
1076  0 groupCache = new HashMap<String, Collection<String>>();
1077    }
1078   
1079  0 Collection<String> memberList = groupCache.get(groupName);
1080   
1081  0 if (memberList == null) {
1082  0 memberList =
1083    context.getWiki().getGroupService(context).getAllMembersNamesForGroup(groupName, 0, 0, context);
1084  0 groupCache.put(groupName, memberList);
1085    }
1086   
1087  0 if (memberList.contains(memberName)
1088    || memberList.contains(context.getWikiId() + WIKIFULLNAME_SEP + memberName)) {
1089  0 found = true;
1090    } else {
1091  0 for (String groupMemberName : memberList) {
1092  0 if (groupContainsMember(groupMemberName, memberName, groupCache, context)) {
1093  0 found = true;
1094  0 break;
1095    }
1096    }
1097    }
1098   
1099  0 return found;
1100    }
1101   
1102    /**
1103    * Resolve passed user or group into users references list.
1104    *
1105    * @param userOrGroup the user or group
1106    * @param context the XWikiContext the XWiki context
1107    * @return the list of users references
1108    * @throws XWikiException error when getting documents
1109    */
 
1110  9 toggle public Collection<DocumentReference> resolveUsers(DocumentReference userOrGroup, XWikiContext context)
1111    throws XWikiException
1112    {
1113  9 Collection<DocumentReference> userReferences = new LinkedHashSet<>();
1114  9 Iterator<DocumentReference> iterator =
1115    new ReferenceUserIterator(userOrGroup, this.explicitDocumentReferenceResolver, context);
1116  17 while (iterator.hasNext()) {
1117  8 userReferences.add(iterator.next());
1118    }
1119  9 return userReferences;
1120    }
1121   
1122    /**
1123    * Resolve passed user or group into users references list.
1124    *
1125    * @param userOrGroup the user or group
1126    * @param context the XWikiContext the XWiki context
1127    * @return the list of users references
1128    * @throws XWikiException error when getting documents
1129    */
 
1130  9 toggle public Collection<DocumentReference> resolveUsers(String userOrGroup, XWikiContext context) throws XWikiException
1131    {
1132  9 return resolveUsers(this.currentDocumentReferenceResolver.resolve(userOrGroup), context);
1133    }
1134   
1135    /**
1136    * Resolve passed users and groups into users references list.
1137    *
1138    * @param referenceList the list of users and groups
1139    * @param context the XWikiContext the XWiki context
1140    * @return the list of users references
1141    * @throws XWikiException error when getting documents
1142    */
 
1143  7 toggle public Collection<DocumentReference> resolveUsers(List<String> referenceList, XWikiContext context)
1144    throws XWikiException
1145    {
1146  7 Collection<DocumentReference> users = new LinkedHashSet<>();
1147   
1148  7 for (String reference : referenceList) {
1149  9 users.addAll(resolveUsers(reference, context));
1150    }
1151   
1152  7 return users;
1153    }
1154    }