View Javadoc
1   /*
2    * Copyright (c) 2002-2021, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.unittree.service.unit;
35  
36  import fr.paris.lutece.plugins.unittree.business.unit.Unit;
37  import fr.paris.lutece.plugins.unittree.business.unit.UnitHome;
38  import fr.paris.lutece.portal.business.user.AdminUser;
39  import fr.paris.lutece.portal.business.user.AdminUserHome;
40  import fr.paris.lutece.portal.business.workgroup.AdminWorkgroupHome;
41  import fr.paris.lutece.portal.service.util.AppPropertiesService;
42  import fr.paris.lutece.util.ReferenceItem;
43  import fr.paris.lutece.util.ReferenceList;
44  
45  import org.apache.commons.collections.CollectionUtils;
46  import org.springframework.transaction.annotation.Transactional;
47  
48  import java.util.ArrayList;
49  import java.util.List;
50  import java.util.Map;
51  
52  import javax.inject.Inject;
53  
54  import javax.servlet.http.HttpServletRequest;
55  
56  /**
57   *
58   * UnitUserService
59   *
60   */
61  public class UnitUserService implements IUnitUserService
62  {
63      private static final String PROPERTY_MULTI_AFFECTATION_ENABLED = "unittree.users.enableMultiAffectation";
64      private static final boolean DEFAULT_MULTI_AFFECTATION_ENABLED = false;
65      @Inject
66      private IUnitService _unitService;
67  
68      // GET
69  
70      /**
71       * {@inheritDoc}
72       */
73      @Override
74      public AdminUser getUser( int nIdUser )
75      {
76          return AdminUserHome.findByPrimaryKey( nIdUser );
77      }
78  
79      /**
80       * {@inheritDoc}
81       */
82      @Override
83      public List<AdminUser> getUsers( int nIdUnit, Map<String, Unit> mapIdUserUnit, boolean isInDepthSearch )
84      {
85          List<AdminUser> listAdminUsers = new ArrayList<>( );
86  
87          // First add the users from the current unit
88          listAdminUsers.addAll( getUsers( nIdUnit, mapIdUserUnit ) );
89  
90          if ( isInDepthSearch )
91          {
92              // Then add the users from the sub units
93              for ( Unit subUnit : _unitService.getSubUnits( nIdUnit, false ) )
94              {
95                  // Recursive function in order to get all users from all sub units of the unit
96                  listAdminUsers.addAll( getUsers( subUnit.getIdUnit( ), mapIdUserUnit, isInDepthSearch ) );
97              }
98          }
99  
100         return listAdminUsers;
101     }
102 
103     /**
104      * {@inheritDoc}
105      */
106     @Override
107     public List<AdminUser> getAvailableUsers( AdminUser currentUser, int nIdUnit, boolean bMultiAffectationEnabled )
108     {
109         List<AdminUser> listUsers = new ArrayList<>( );
110         Unit unit = _unitService.getUnit( nIdUnit, false );
111 
112         for ( AdminUser user : AdminUserHome.findUserList( ) )
113         {
114             if ( isUserAvailable( currentUser, user, unit, bMultiAffectationEnabled ) )
115             {
116                 listUsers.add( user );
117             }
118         }
119 
120         return listUsers;
121     }
122 
123     /**
124      * {@inheritDoc}
125      */
126     @Override
127     public List<AdminUser> getAvailableUsers( AdminUser currentUser, int nIdUnit )
128     {
129         boolean bMultiAffectationEnabled = isMultiAffectationEnabled( );
130 
131         return getAvailableUsers( currentUser, nIdUnit, bMultiAffectationEnabled );
132     }
133 
134     // PROCESS
135 
136     /**
137      * {@inheritDoc}
138      */
139     @Override
140     public void doProcessAddUser( int nIdUser, AdminUser currentUser, HttpServletRequest request )
141     {
142         for ( IUnitUserAttributeService service : UnitUserAttributeManager.getListUnitUserAttributeService( ) )
143         {
144             service.doAddUser( nIdUser, currentUser, request );
145         }
146     }
147 
148     /**
149      * {@inheritDoc}
150      */
151     @Override
152     public void doProcessModifyUser( int nIdUser, AdminUser currentUser, HttpServletRequest request )
153     {
154         for ( IUnitUserAttributeService service : UnitUserAttributeManager.getListUnitUserAttributeService( ) )
155         {
156             service.doModifyUser( nIdUser, currentUser, request );
157         }
158     }
159 
160     /**
161      * {@inheritDoc}
162      */
163     @Override
164     public void doProcessRemoveUser( int nIdUser, AdminUser currentUser, HttpServletRequest request )
165     {
166         for ( IUnitUserAttributeService service : UnitUserAttributeManager.getListUnitUserAttributeService( ) )
167         {
168             service.doRemoveUser( nIdUser, currentUser, request );
169         }
170     }
171 
172     // CHECKS
173 
174     /**
175      * {@inheritDoc}
176      */
177     @Override
178     public boolean isUserInUnit( int nIdUser, int nIdUnit )
179     {
180         return UnitHome.isUserInUnit( nIdUser, nIdUnit );
181     }
182 
183     // CRUD
184 
185     /**
186      * {@inheritDoc}
187      */
188     @Override
189     @Transactional( "unittree.transactionManager" )
190     public boolean addUserToUnit( int nIdUnit, int nIdUser )
191     {
192         if ( !isUserInUnit( nIdUser, nIdUnit ) )
193         {
194             Unit unit = UnitHome.findByPrimaryKey( nIdUnit );
195             List<Unit> listUnits = _unitService.getUnitsByIdUser( nIdUser, false );
196             boolean bMultiAffectationEnabled = isMultiAffectationEnabled( );
197 
198             if ( !bMultiAffectationEnabled && CollectionUtils.isNotEmpty( listUnits ) )
199             {
200                 return false;
201             }
202 
203             for ( Unit userUnit : listUnits )
204             {
205                 if ( _unitService.isParent( unit, userUnit ) )
206                 {
207                     removeUserFromUnit( nIdUser, userUnit.getIdUnit( ) );
208                 }
209             }
210 
211             UnitHome.addUserToUnit( nIdUnit, nIdUser );
212 
213             return true;
214         }
215 
216         return false;
217     }
218 
219     /**
220      * {@inheritDoc}
221      */
222     @Override
223     @Transactional( "unittree.transactionManager" )
224     public void removeUserFromUnit( int nIdUser, int nIdUnit )
225     {
226         UnitHome.removeUserFromUnit( nIdUser, nIdUnit );
227     }
228 
229     /**
230      * {@inheritDoc}
231      */
232     @Override
233     @Transactional( "unittree.transactionManager" )
234     public void removeUsersFromUnit( int nIdUnit )
235     {
236         UnitHome.removeUsersFromUnit( nIdUnit );
237     }
238 
239     /**
240      * {@inheritDoc}
241      */
242     @Override
243     public boolean isMultiAffectationEnabled( )
244     {
245         return AppPropertiesService.getPropertyBoolean( PROPERTY_MULTI_AFFECTATION_ENABLED, DEFAULT_MULTI_AFFECTATION_ENABLED );
246     }
247 
248     // PRIVATE METHODS
249 
250     /**
251      * Tell if 2 users have groups in common
252      * 
253      * @param user1
254      *            User1
255      * @param user2
256      *            User2
257      * @return true or false
258      */
259     private boolean haveCommonWorkgroups( AdminUser user1, AdminUser user2 )
260     {
261         ReferenceList workgroups = AdminWorkgroupHome.getUserWorkgroups( user1 );
262 
263         if ( CollectionUtils.isEmpty( workgroups ) )
264         {
265             return true;
266         }
267 
268         for ( ReferenceItem item : workgroups )
269         {
270             if ( AdminWorkgroupHome.isUserInWorkgroup( user2, item.getCode( ) ) )
271             {
272                 return true;
273             }
274         }
275 
276         return false;
277     }
278 
279     /**
280      * Check if the user is available
281      * 
282      * @param currentUser
283      *            the current user
284      * @param userToCheck
285      *            the user to check
286      * @param unit
287      *            the unit to check if the user is available for
288      * @param bMultiAffectationEnabled
289      *            Indicates if this method should allow a user to be in several units, or if it should return false if he is already in a unit.
290      * @return true if the user is available, false otherwise
291      */
292     private boolean isUserAvailable( AdminUser currentUser, AdminUser userToCheck, Unit unit, boolean bMultiAffectationEnabled )
293     {
294         List<Unit> listUnits = _unitService.getUnitsByIdUser( userToCheck.getUserId( ), false );
295 
296         if ( !bMultiAffectationEnabled && CollectionUtils.isNotEmpty( listUnits ) )
297         {
298             return false;
299         }
300 
301         for ( Unit userUnit : listUnits )
302         {
303             // If the user is in the unit or in one if its parents
304             if ( ( userUnit.getIdUnit( ) == unit.getIdUnit( ) ) || _unitService.isParent( userUnit, unit ) )
305             {
306                 return false;
307             }
308         }
309 
310         // Check if the current user is admin => visibility to all users
311         if ( currentUser.isAdmin( ) )
312         {
313             return true;
314         }
315 
316         // Check if the current user is parent to the user to check
317         // Then check if they have the same workgroup, or the user to check does not have any workgroup
318         return currentUser.isParent( userToCheck )
319                 && ( haveCommonWorkgroups( currentUser, userToCheck ) || !AdminWorkgroupHome.checkUserHasWorkgroup( userToCheck.getUserId( ) ) );
320     }
321 
322     /**
323      * Get the list of {@link AdminUser} from a given id unit
324      * 
325      * @param nIdUnit
326      *            the id unit
327      * @param mapIdUserUnit
328      *            the map of <idUser, Unit>
329      * @return a list of {@link AdminUser}
330      */
331     private List<AdminUser> getUsers( int nIdUnit, Map<String, Unit> mapIdUserUnit )
332     {
333         Unit unit = _unitService.getUnit( nIdUnit, false );
334         List<AdminUser> listUsers = new ArrayList<>( );
335         List<Integer> listIdUsers = UnitHome.findIdsUser( nIdUnit );
336 
337         if ( CollectionUtils.isNotEmpty( listIdUsers ) )
338         {
339             for ( int nIdUser : listIdUsers )
340             {
341                 AdminUser user = AdminUserHome.findByPrimaryKey( nIdUser );
342 
343                 if ( user != null )
344                 {
345                     listUsers.add( user );
346                     mapIdUserUnit.put( Integer.toString( user.getUserId( ) ), unit );
347                 }
348             }
349         }
350 
351         return listUsers;
352     }
353 }