View Javadoc
1   /*
2    * Copyright (c) 2002-2022, 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 java.io.FileInputStream;
37  import java.util.ArrayList;
38  import java.util.HashSet;
39  import java.util.List;
40  import java.util.Locale;
41  import java.util.Set;
42  
43  import javax.inject.Inject;
44  import javax.servlet.http.HttpServletRequest;
45  import javax.xml.transform.Source;
46  import javax.xml.transform.stream.StreamSource;
47  
48  import org.apache.commons.lang.StringUtils;
49  import org.springframework.beans.factory.annotation.Autowired;
50  import org.springframework.transaction.annotation.Transactional;
51  
52  import fr.paris.lutece.plugins.unittree.business.action.IAction;
53  import fr.paris.lutece.plugins.unittree.business.unit.Sector;
54  import fr.paris.lutece.plugins.unittree.business.unit.Unit;
55  import fr.paris.lutece.plugins.unittree.business.unit.Unit.TypeUnit;
56  import fr.paris.lutece.plugins.unittree.business.unit.UnitFilter;
57  import fr.paris.lutece.plugins.unittree.business.unit.UnitHome;
58  import fr.paris.lutece.plugins.unittree.service.UnitErrorException;
59  import fr.paris.lutece.plugins.unittree.service.action.IActionService;
60  import fr.paris.lutece.portal.business.user.AdminUser;
61  import fr.paris.lutece.portal.service.i18n.I18nService;
62  import fr.paris.lutece.portal.service.rbac.RBACService;
63  import fr.paris.lutece.portal.service.util.AppPathService;
64  import fr.paris.lutece.util.ReferenceList;
65  import fr.paris.lutece.util.xml.XmlUtil;
66  
67  /**
68   *
69   * UnitService
70   *
71   */
72  public class UnitService implements IUnitService
73  {
74      // XML TAGS
75      private static final String TAG_UNITS = "units";
76      private static final String TAG_UNIT = "unit";
77      private static final String TAG_ID_UNIT = "id-unit";
78      private static final String TAG_LABEL = "label";
79      private static final String TAG_DESCRIPTION = "description";
80      private static final String TAG_UNIT_CHILDREN = "unit-children";
81      private static final String CDATA_START = "<![CDATA[";
82      private static final String CDATA_END = "]]>";
83  
84      // PROPERTIES
85      private static final String PROPERTY_LABEL_PARENT_UNIT = "unittree.moveUser.labelParentUnit";
86  
87      // CONSTANTS
88      private static final String ATTRIBUTE_ID_UNIT = "idUnit";
89      private static final String ATTRIBUTE_LABEL = "label";
90  
91      // XSL
92      private static final String PATH_XSL = "/WEB-INF/plugins/unittree/xsl/";
93      private static final String FILE_TREE_XSL = "units_tree.xsl";
94      @Autowired( required = false )
95      private IUnitUserService _unitUserService;
96      @Inject
97      private IActionService _actionService;
98  
99      // GET
100 
101     /**
102      * {@inheritDoc}
103      */
104     @Override
105     public Unit getUnit( int nIdUnit, boolean bGetAdditionalInfos )
106     {
107         Unit unit = UnitHome.findByPrimaryKey( nIdUnit );
108 
109         if ( ( unit != null ) && bGetAdditionalInfos )
110         {
111             UnitAttributeManager.populate( unit );
112         }
113 
114         return unit;
115     }
116 
117     /**
118      * {@inheritDoc}
119      */
120     @Override
121     public Unit getRootUnit( boolean bGetAdditionalInfos )
122     {
123         return getUnit( Unit.ID_ROOT, bGetAdditionalInfos );
124     }
125 
126     /**
127      * {@inheritDoc}
128      */
129     @Override
130     public List<Unit> getUnitsByIdUser( int nIdUser, boolean bGetAdditionalInfos )
131     {
132         List<Unit> listUnit = UnitHome.findByIdUser( nIdUser );
133 
134         for ( Unit unit : listUnit )
135         {
136             if ( bGetAdditionalInfos && ( unit != null ) )
137             {
138                 UnitAttributeManager.populate( unit );
139             }
140         }
141 
142         return listUnit;
143     }
144 
145     @Override
146     public Unit getUnitUserByType( AdminUser user, TypeUnit type )
147     {
148         List<Unit> units = getUnitsByIdUser( user.getUserId( ), true );
149         for ( Unit unit : units )
150         {
151             if ( type.equals( unit.getTypeunit( ) ) )
152             {
153                 return unit;
154             }
155         }
156 
157         return null;
158     }
159 
160     /**
161      * {@inheritDoc}
162      */
163     @Override
164     public List<Unit> getAllUnits( boolean bGetAdditionalInfos )
165     {
166         List<Unit> listUnits = UnitHome.findAll( );
167 
168         if ( bGetAdditionalInfos )
169         {
170             for ( Unit unit : listUnits )
171             {
172                 if ( unit != null )
173                 {
174                     UnitAttributeManager.populate( unit );
175                 }
176             }
177         }
178 
179         return listUnits;
180     }
181 
182     /**
183      * {@inheritDoc}
184      */
185     @Override
186     public List<Unit> getUnitsFirstLevel( boolean bGetAdditionalInfos )
187     {
188         return getSubUnits( Unit.ID_ROOT, bGetAdditionalInfos );
189     }
190 
191     /**
192      * {@inheritDoc}
193      */
194     @Override
195     public List<Unit> getSubUnits( int nIdUnit, boolean bGetAdditionalInfos )
196     {
197         // If the ID unit == -1, then only return the root unit
198         if ( nIdUnit == Unit.ID_NULL )
199         {
200             List<Unit> listUnits = new ArrayList<Unit>( );
201             listUnits.add( getRootUnit( bGetAdditionalInfos ) );
202 
203             return listUnits;
204         }
205 
206         UnitFilterunittree/business/unit/UnitFilter.html#UnitFilter">UnitFilter uFilter = new UnitFilter( );
207         uFilter.setIdParent( nIdUnit );
208 
209         List<Unit> listUnits = UnitHome.findByFilter( uFilter );
210 
211         if ( bGetAdditionalInfos )
212         {
213             for ( Unit unit : listUnits )
214             {
215                 if ( unit != null )
216                 {
217                     UnitAttributeManager.populate( unit );
218                 }
219             }
220         }
221 
222         return listUnits;
223     }
224 
225     /**
226      * {@inheritDoc}
227      */
228     @Override
229     public List<IAction> getListActions( String strActionType, Locale locale, Unit unit, AdminUser user )
230     {
231         // If the user is admin, then no need to filter by permission
232         if ( user.isAdmin( ) && ( unit != null ) )
233         {
234             // If the unit has sectors and does not have sub units, then remove
235             // 'CREATE' action
236             if ( !canCreateSubUnit( unit.getIdUnit( ) ) )
237             {
238                 return _actionService.getListActions( strActionType, locale, user, UnitResourceIdService.PERMISSION_CREATE );
239             }
240 
241             return _actionService.getListActions( strActionType, locale, user );
242         }
243 
244         List<Unit> listUnits = getUnitsByIdUser( user.getUserId( ), false );
245 
246         List<IAction> listActions = new ArrayList<IAction>( );
247 
248         if ( ( unit != null ) && ( listUnits.size( ) > 0 ) )
249         {
250             // If the unit has sectors and does not have sub units, then remove
251             // 'CREATE' action
252             if ( !canCreateSubUnit( unit.getIdUnit( ) ) )
253             {
254                 listActions = _actionService.getListActions( strActionType, locale, unit, user, UnitResourceIdService.PERMISSION_CREATE );
255             }
256             else
257             {
258                 listActions = _actionService.getListActions( strActionType, locale, unit, user );
259             }
260         }
261 
262         for ( Unit unitUser : listUnits )
263         {
264             if ( ( unitUser != null ) && ( unit != null ) )
265             {
266                 // If the user is in a parent unit of the current unit, then add
267                 // the list of actions of the parent unit to the list
268                 if ( isParent( unitUser, unit ) )
269                 {
270                     List<IAction> listParentUnitActions = _actionService.getListActions( strActionType, locale, unitUser, user );
271 
272                     for ( IAction parentUnitAction : listParentUnitActions )
273                     {
274                         if ( !listActions.contains( parentUnitAction ) )
275                         {
276                             listActions.add( parentUnitAction );
277                         }
278                     }
279                 }
280             }
281         }
282 
283         return listActions;
284     }
285 
286     /**
287      * {@inheritDoc}
288      */
289     @Override
290     public ReferenceList getSubUnitsAsReferenceList( int nIdUnit, Locale locale )
291     {
292         // If parent id == -1, then its sub units is the root unit
293         if ( nIdUnit == Unit.ID_NULL )
294         {
295             ReferenceList listSubUnits = new ReferenceList( );
296             listSubUnits.addItem( Unit.ID_ROOT, getRootUnit( false ).getLabel( ) );
297 
298             return listSubUnits;
299         }
300 
301         // Otherwise, build the reference list
302         Unit unit = getUnit( nIdUnit, false );
303 
304         if ( unit != null )
305         {
306             String strLabelParentUnit = I18nService.getLocalizedString( PROPERTY_LABEL_PARENT_UNIT, locale );
307             ReferenceList listSubUnits = new ReferenceList( );
308             listSubUnits.addItem( unit.getIdParent( ), strLabelParentUnit );
309             listSubUnits.addAll( ReferenceList.convert( getSubUnits( nIdUnit, false ), ATTRIBUTE_ID_UNIT, ATTRIBUTE_LABEL, true ) );
310 
311             return listSubUnits;
312         }
313 
314         return new ReferenceList( );
315     }
316 
317     /**
318      * {@inheritDoc}
319      */
320     @Override
321     public String getXMLUnits( )
322     {
323         StringBuffer sbXML = new StringBuffer( );
324         XmlUtil.beginElement( sbXML, TAG_UNITS );
325 
326         getXMLUnit( sbXML, getRootUnit( false ) );
327 
328         XmlUtil.endElement( sbXML, TAG_UNITS );
329 
330         return sbXML.toString( );
331     }
332 
333     /**
334      * {@inheritDoc}
335      */
336     @Override
337     public Source getTreeXsl( )
338     {
339         FileInputStream fis = AppPathService.getResourceAsStream( PATH_XSL, FILE_TREE_XSL );
340 
341         return new StreamSource( fis );
342     }
343 
344     @Override
345     public List<Sector> findAllSectors( )
346     {
347         return UnitHome.findAllSectorId( );
348     }
349 
350     /**
351      * Find by sector id
352      *
353      * @param nIdSector
354      *            id sector
355      * @return list of Unit found
356      */
357     @Override
358     public List<Unit> findBySectorId( int nIdSector )
359     {
360         return UnitHome.findBySectorId( nIdSector );
361     }
362 
363     @Override
364     public Unit findBySectorIdWithoutChildren( int nIdSector )
365     {
366         return UnitHome.findBySectorIdWithoutChildren( nIdSector );
367     }
368 
369     /**
370      * Return all the Unit with no children (level 0)
371      *
372      * @return all the Unit with no children (level 0)
373      */
374     @Override
375     public List<Unit> getUnitWithNoChildren( )
376     {
377         return UnitHome.getUnitWithNoChildren( );
378     }
379 
380     // CHECKS
381 
382     /**
383      * {@inheritDoc}
384      */
385     @Override
386     public boolean hasSubUnits( int nIdUnit )
387     {
388         return UnitHome.hasSubUnits( nIdUnit );
389     }
390 
391     /**
392      * {@inheritDoc}
393      */
394     @Override
395     public boolean isParent( Unit../../../../../../../fr/paris/lutece/plugins/unittree/business/unit/Unit.html#Unit">Unit unitParent, Unit unitRef )
396     {
397         if ( ( unitParent != null ) && ( unitRef != null ) )
398         {
399             if ( unitParent.getIdUnit( ) == unitRef.getIdParent( ) )
400             {
401                 return true;
402             }
403 
404             Unit nextUnitParent = getUnit( unitRef.getIdParent( ), false );
405 
406             while ( ( nextUnitParent != null ) && ( nextUnitParent.getIdUnit( ) != Unit.ID_NULL ) )
407             {
408                 if ( unitParent.getIdUnit( ) == nextUnitParent.getIdUnit( ) )
409                 {
410                     return true;
411                 }
412 
413                 nextUnitParent = getUnit( nextUnitParent.getIdParent( ), false );
414             }
415         }
416 
417         return false;
418     }
419 
420     /**
421      * {@inheritDoc}
422      */
423     @Override
424     public boolean canCreateSubUnit( int nIdUnit )
425     {
426         return hasSubUnits( nIdUnit ) || UnitAttributeManager.canCreateSubUnit( nIdUnit );
427     }
428 
429     /**
430      * {@inheritDoc}
431      */
432     @Override
433     public boolean isAuthorized( Unit unit, String strPermission, AdminUser user )
434     {
435         // 1) The given user is admin
436         if ( user.isAdmin( ) )
437         {
438             return true;
439         }
440 
441         // 2) unitUser == null : The given user does not belong to any unit
442         List<Unit> listUnits = getUnitsByIdUser( user.getUserId( ), false );
443 
444         if ( unit != null )
445         {
446             Unit targetUnit = null;
447 
448             for ( Unit unitUser : listUnits )
449             {
450                 // 3) The given user belongs to the given unit
451                 if ( unitUser.getIdUnit( ) == unit.getIdUnit( ) )
452                 {
453                     targetUnit = unit;
454                 }
455 
456                 // 4) The given user belongs to a parent unit of the given unit
457                 else
458                     if ( isParent( unitUser, unit ) )
459                     {
460                         targetUnit = unitUser;
461                     }
462 
463                 // 5) targetUnit == null : The given user belongs to an unit who
464                 // is not a parent unit of the given unit
465                 if ( targetUnit != null )
466                 {
467                     if ( RBACService.isAuthorized( targetUnit, strPermission, user ) )
468                     {
469                         return true;
470                     }
471 
472                     targetUnit = null;
473                 }
474             }
475         }
476 
477         return false;
478     }
479 
480     /**
481      * {@inheritDoc}
482      */
483     @Override
484     public boolean isAuthorized( String strIdUnit, String strPermission, AdminUser user )
485     {
486         if ( StringUtils.isNotBlank( strIdUnit ) && StringUtils.isNumeric( strIdUnit ) )
487         {
488             int nIdUnit = Integer.parseInt( strIdUnit );
489             Unit unit = getUnit( nIdUnit, false );
490 
491             return isAuthorized( unit, strPermission, user );
492         }
493 
494         return false;
495     }
496 
497     // CRUD OPERATIONS
498 
499     /**
500      * {@inheritDoc}
501      */
502     @Override
503     @Transactional( "unittree.transactionManager" )
504     public int createUnit( Unit unit, HttpServletRequest request ) throws UnitErrorException
505     {
506         int nIdUnit = Unit.ID_NULL;
507 
508         if ( unit != null )
509         {
510             nIdUnit = UnitHome.create( unit );
511             UnitAttributeManager.doCreateUnit( unit, request );
512 
513             return nIdUnit;
514         }
515 
516         return Unit.ID_NULL;
517     }
518 
519     /**
520      * {@inheritDoc}
521      */
522     @Override
523     @Transactional( "unittree.transactionManager" )
524     public void removeUnit( int nIdUnit, HttpServletRequest request )
525     {
526         if ( ( nIdUnit != Unit.ID_ROOT ) && !hasSubUnits( nIdUnit ) )
527         {
528             UnitAttributeManager.doRemoveUnit( nIdUnit, request );
529 
530             // Remove users
531             _unitUserService.removeUsersFromUnit( nIdUnit );
532 
533             UnitHome.remove( nIdUnit );
534         }
535     }
536 
537     /**
538      * {@inheritDoc}
539      */
540     @Override
541     @Transactional( "unittree.transactionManager" )
542     public void updateUnit( Unit unit, HttpServletRequest request ) throws UnitErrorException
543     {
544         if ( unit != null )
545         {
546             UnitAttributeManager.doModifyUnit( unit, request );
547 
548             // Update unit information
549             UnitHome.update( unit );
550         }
551     }
552 
553     /**
554      * {@inheritDoc}
555      */
556     @Override
557     @Transactional( "unittree.transactionManager" )
558     public boolean moveSubTree( Unit../../../../../../../fr/paris/lutece/plugins/unittree/business/unit/Unit.html#Unit">Unit unitToMove, Unit newUnitParent )
559     {
560         if ( ( unitToMove != null ) && ( newUnitParent != null ) && ( unitToMove.getIdUnit( ) != newUnitParent.getIdUnit( ) )
561                 && !isParent( unitToMove, newUnitParent ) )
562         {
563             UnitAttributeManager.moveSubTree( unitToMove, newUnitParent );
564             unitToMove.setIdParent( newUnitParent.getIdUnit( ) );
565             UnitHome.updateParent( unitToMove.getIdUnit( ), newUnitParent.getIdUnit( ) );
566 
567             return true;
568         }
569 
570         return false;
571     }
572 
573     // PRIVATE METHODS
574 
575     /**
576      * Get the XML for an unit
577      *
578      * @param sbXML
579      *            the XML
580      * @param unit
581      *            the unit
582      */
583     private void getXMLUnit( StringBuffer sbXML, Unit unit )
584     {
585         XmlUtil.beginElement( sbXML, TAG_UNIT );
586         XmlUtil.addElement( sbXML, TAG_ID_UNIT, unit.getIdUnit( ) );
587         XmlUtil.addElement( sbXML, TAG_LABEL, CDATA_START + unit.getLabel( ) + CDATA_END );
588         XmlUtil.addElement( sbXML, TAG_DESCRIPTION, CDATA_START + unit.getDescription( ) + CDATA_END );
589 
590         List<Unit> listChildren = getSubUnits( unit.getIdUnit( ), false );
591 
592         if ( ( listChildren != null ) && !listChildren.isEmpty( ) )
593         {
594             XmlUtil.beginElement( sbXML, TAG_UNIT_CHILDREN );
595 
596             for ( Unit child : listChildren )
597             {
598                 getXMLUnit( sbXML, child );
599             }
600 
601             XmlUtil.endElement( sbXML, TAG_UNIT_CHILDREN );
602         }
603 
604         XmlUtil.endElement( sbXML, TAG_UNIT );
605     }
606 
607     @Override
608     public boolean hasUserSameSubdivisionBySector( int userId, int sectorId )
609     {
610         return hasUserSameParentBySector( userId, sectorId, "SUB" );
611     }
612 
613     @Override
614     public boolean hasUserSameSectionBySector( int userId, int sectorId )
615     {
616         return hasUserSameParentBySector( userId, sectorId, "STV" );
617     }
618 
619     private boolean isSameParentType( Unit unit, String type )
620     {
621         return unit.getLabel( ).startsWith( type );
622     }
623 
624     private Unit../../../../../fr/paris/lutece/plugins/unittree/business/unit/Unit.html#Unit">Unit findParentByType( Unit unit, String type )
625     {
626         if ( unit != null )
627         {
628             if ( isSameParentType( unit, type ) )
629             {
630                 return unit;
631             }
632             else
633             {
634                 return findParentByType( getUnit( unit.getIdParent( ), false ), type );
635             }
636         }
637         else
638         {
639             return null;
640         }
641     }
642 
643     private boolean hasUserSameParentBySector( int userId, int sectorId, String type )
644     {
645         String sectorParent = null;
646         List<Unit> unitsSector = findBySectorId( sectorId );
647         for ( Unit unit : unitsSector )
648         {
649             if ( isSameParentType( unit, type ) )
650             {
651                 sectorParent = unit.getLabel( );
652             }
653         }
654         Set<String> userParent = new HashSet<String>( );
655         List<Unit> unitsUser = getUnitsByIdUser( userId, false );
656         for ( Unit unit : unitsUser )
657         {
658             if ( TypeUnit.VILLE.equals( unit.getTypeunit( ) ) )
659             {
660                 Unit parent = findParentByType( unit, type );
661                 if ( parent != null )
662                 {
663                     userParent.add( parent.getLabel( ) );
664                 }
665                 else
666                 {
667 
668                     userParent.add( sectorParent );
669                 }
670             }
671         }
672         return userParent.contains( sectorParent );
673     }
674 
675     @Override
676     public List<String> findAllSectorsGeo( )
677     {
678         return UnitHome.findAllSectorsGeo( );
679     }
680 
681     @Override
682     public List<Integer> getAllUnitsIdByUnit( Unit unitParent )
683     {
684         List<Unit> subUnits = new ArrayList<Unit>( );
685         List<Integer> allUnitsId = new ArrayList<Integer>( );
686         if ( unitParent != null )
687         {
688             List<Unit> allUnits = getSubUnits( unitParent.getIdUnit( ), false );
689             allUnitsId.add( unitParent.getIdUnit( ) );
690             if ( UnitHome.hasSubUnits( unitParent.getIdUnit( ) ) )
691             {
692                 while ( ( subUnits.size( ) > 0 ) || ( allUnitsId.size( ) == 1 ) )
693                 {
694                     for ( Unit subUnit : subUnits )
695                     {
696                         allUnits.add( subUnit );
697                     }
698                     subUnits = new ArrayList<Unit>( );
699                     for ( Unit unit : allUnits )
700                     {
701                         if ( !unit.getDescription( ).equals( "UNIT_TRAITEE" ) )
702                         {
703                             allUnitsId.add( unit.getIdUnit( ) );
704                             unit.setDescription( "UNIT_TRAITEE" );
705                             if ( UnitHome.hasSubUnits( unit.getIdUnit( ) ) )
706                             {
707                                 subUnits.addAll( getSubUnits( unit.getIdUnit( ), false ) );
708                             }
709                         }
710                     }
711                 }
712             }
713         }
714         return allUnitsId;
715     }
716 
717     @Override
718     public List<Unit> getUnitsByLabel( String unitLabel )
719     {
720         UnitFilterunittree/business/unit/UnitFilter.html#UnitFilter">UnitFilter uFilter = new UnitFilter( );
721         uFilter.setLabel( unitLabel );
722         List<Unit> listUnits = UnitHome.findByFilter( uFilter );
723         return listUnits;
724     }
725 }