View Javadoc
1   /*
2    * Copyright (c) 2002-2023, 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.document.service.spaces;
35  
36  import fr.paris.lutece.plugins.document.business.DocumentType;
37  import fr.paris.lutece.plugins.document.business.DocumentTypeHome;
38  import fr.paris.lutece.plugins.document.business.spaces.DocumentSpace;
39  import fr.paris.lutece.plugins.document.business.spaces.DocumentSpaceHome;
40  import fr.paris.lutece.plugins.document.service.DocumentTypeResourceIdService;
41  import fr.paris.lutece.plugins.document.utils.IntegerUtils;
42  import fr.paris.lutece.portal.business.user.AdminUser;
43  import fr.paris.lutece.portal.service.rbac.RBACService;
44  import fr.paris.lutece.portal.service.template.AppTemplateService;
45  import fr.paris.lutece.portal.service.util.AppPathService;
46  import fr.paris.lutece.portal.service.workgroup.AdminWorkgroupService;
47  import fr.paris.lutece.util.html.HtmlTemplate;
48  import fr.paris.lutece.util.xml.XmlUtil;
49  
50  import org.apache.commons.lang3.StringEscapeUtils;
51  import org.apache.commons.lang3.StringUtils;
52  
53  import java.io.FileInputStream;
54  
55  import java.util.ArrayList;
56  import java.util.Collection;
57  import java.util.HashMap;
58  import java.util.List;
59  import java.util.Locale;
60  import java.util.Map;
61  
62  import javax.servlet.http.HttpServletRequest;
63  
64  import javax.xml.transform.Source;
65  import javax.xml.transform.stream.StreamSource;
66  
67  
68  /**
69   * Document Spaces management Service.
70   */
71  public class DocumentSpacesService
72  {
73      public static final String PARAMETER_BROWSER_SELECTED_SPACE_ID = "browser_selected_space_id";
74      private static final String REGEX_ID = "^[\\d]+$";
75      private static final String TAG_SPACES = "spaces";
76      private static final String TAG_SPACE = "space";
77      private static final String TAG_SPACE_ID = "space-id";
78      private static final String TAG_SPACE_IS_VALID = "space-is-valid";
79      private static final String TAG_SPACE_NAME = "name";
80      private static final String TAG_SPACE_DESCRIPTION = "description";
81      private static final String TAG_SPACE_CHILDS = "child-spaces";
82      private static final String TAG_SPACE_ICON_URL = "space-icon-url";
83  
84      //browser
85      private static final String TEMPLATE_BROWSE_SPACES = "/admin/plugins/document/spaces/browse_spaces.html";
86      private static final String TEMPLATE_BROWSE_SPACES_FOR_FILE_SELECTION = "/admin/plugins/document/spaces/browse_spaces_for_file_selection.html";
87      private static final String MARK_SPACE = "space";
88      private static final String PARAMETER_BROWSER_SPACE_ID = "browser_id_space";
89      private static final String MARK_ACTION = "action";
90      private static final String MARK_SPACES_LIST = "spaces_list";
91      private static final String MARK_URLS_LIST = "has_childs";
92      private static final String MARK_SELECTED_SPACE = "selected_space";
93      private static final String MARK_GO_UP = "go_up";
94      private static final String PATH_XSL = "/WEB-INF/plugins/document/xsl/";
95      private static final String FILE_TREE_XSL = "document_spaces_tree.xsl";
96      
97      //CONSTANTS
98      private static final String CONSTANT_TRUE = "true";
99      private static DocumentSpacesServicece/spaces/DocumentSpacesService.html#DocumentSpacesService">DocumentSpacesService _singleton = new DocumentSpacesService(  );
100 
101     /** Creates a new instance of DocumentSpacesService */
102     private DocumentSpacesService(  )
103     {
104     }
105 
106     /**
107      * Returns the unique instance of the service
108      * @return the unique instance of the service
109      */
110     public static DocumentSpacesService getInstance(  )
111     {
112         return _singleton;
113     }
114 
115     /**
116      * Gets allowed Spaces for a given user as an XML document
117      * @param user The current user
118      * @return An XML document containing allowed spaces
119      */
120     public String getXmlSpacesList( AdminUser user )
121     {
122         StringBuffer sbXML = new StringBuffer(  );
123         XmlUtil.beginElement( sbXML, TAG_SPACES );
124 
125         for ( DocumentSpace space : getUserSpaces( user ) )
126         {
127             findSpaces( sbXML, space.getId(  ), user );
128         }
129 
130         XmlUtil.endElement( sbXML, TAG_SPACES );
131 
132         return sbXML.toString(  );
133     }
134 
135     /**
136      * Gets allowed Spaces for a given user and a type of document as an XML
137      * document
138      * @param user The current user
139      * @param strCodeType The code for the document type
140      * @return An XML document containing allowed spaces
141      */
142     public String getXmlSpacesList( AdminUser user, String strCodeType )
143     {
144         StringBuffer sbXML = new StringBuffer(  );
145         XmlUtil.beginElement( sbXML, TAG_SPACES );
146 
147         for ( DocumentSpace space : getUserSpaces( user ) )
148         {
149             findSpacesByCodeType( sbXML, space.getId(  ), user, strCodeType );
150         }
151 
152         XmlUtil.endElement( sbXML, TAG_SPACES );
153 
154         return sbXML.toString(  );
155     }
156 
157     /**
158      * Gets user default space
159      * @param user The current user
160      * @return The user default space
161      */
162     public int getUserDefaultSpace( AdminUser user )
163     {
164         int nIdDefaultSpace = -1;
165 
166         for ( DocumentSpace space : getUserSpaces( user ) )
167         {
168             nIdDefaultSpace = space.getId(  );
169         }
170 
171         return nIdDefaultSpace;
172     }
173 
174     private Collection<DocumentSpace> getUserSpaces( AdminUser user )
175     {
176         Collection<DocumentSpace> listSpaces = DocumentSpaceHome.findAll(  );
177         listSpaces = RBACService.getAuthorizedCollection( listSpaces, SpaceResourceIdService.PERMISSION_VIEW, user );
178 
179         return listSpaces;
180     }
181 
182     /**
183      * Gets the XSL to display user spaces tree
184      * @return The XSL to display user spaces tree
185      */
186     public Source getTreeXsl(  )
187     {
188         FileInputStream fis = AppPathService.getResourceAsStream( PATH_XSL, FILE_TREE_XSL );
189         Source xslSource = new StreamSource( fis );
190 
191         return xslSource;
192     }
193 
194     /**
195      * Build recursively the XML document containing the arborescence of spaces
196      *
197      * @param sbXML The buffer in which adding the current space of the
198      *            arborescence
199      * @param nSpaceId The current space of the recursive course
200      * @param user AdminUser
201      */
202     private void findSpaces( StringBuffer sbXML, int nSpaceId, AdminUser user )
203     {
204         DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
205 
206         if ( AdminWorkgroupService.isAuthorized( space, user ) )
207         {
208             XmlUtil.beginElement( sbXML, TAG_SPACE );
209             XmlUtil.addElement( sbXML, TAG_SPACE_ID, space.getId(  ) );
210             XmlUtil.addElement( sbXML, TAG_SPACE_NAME, StringEscapeUtils.escapeXml( space.getName(  ) ) );
211             XmlUtil.addElement( sbXML, TAG_SPACE_DESCRIPTION, space.getDescription(  ) );
212             XmlUtil.addElement( sbXML, TAG_SPACE_ICON_URL, space.getIconUrl(  ) );
213 
214             List<DocumentSpace> listChilds = DocumentSpaceHome.findChilds( nSpaceId );
215 
216             if ( listChilds.size(  ) > 0 )
217             {
218                 XmlUtil.beginElement( sbXML, TAG_SPACE_CHILDS );
219 
220                 for ( DocumentSpace child : listChilds )
221                 {
222                     findSpaces( sbXML, child.getId(  ), user );
223                 }
224 
225                 XmlUtil.endElement( sbXML, TAG_SPACE_CHILDS );
226             }
227 
228             XmlUtil.endElement( sbXML, TAG_SPACE );
229         }
230     }
231 
232     /**
233      * Build recursively the XML document containing the arborescence of spaces
234      *
235      * @param sbXML The buffer in which adding the current space of the
236      *            arborescence
237      * @param nSpaceId The current space of the recursive course
238      * @param user AdminUser
239      * @param strCodeType The code type
240      * @return True if the space is valid, false otherwise
241      */
242     private boolean findSpacesByCodeType( StringBuffer sbXML, int nSpaceId, AdminUser user, String strCodeType )
243     {
244         DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
245         DocumentType documentType = DocumentTypeHome.findByPrimaryKey( strCodeType );
246         boolean bValidSpace = false;
247         boolean bChildValidity = false;
248 
249         if ( AdminWorkgroupService.isAuthorized( space, user ) )
250         {
251             Collection<DocumentSpace> listChilds = DocumentSpaceHome.findChilds( nSpaceId );
252 
253             boolean bContainCodeType = false;
254 
255             for ( String strCodeTypeDocument : space.getAllowedDocumentTypes(  ) )
256             {
257                 if ( strCodeTypeDocument.equals( strCodeType ) )
258                 {
259                     bContainCodeType = true;
260                 }
261             }
262 
263             if ( listChilds.size(  ) > 0 )
264             {
265                 StringBuffer sbChildrenXML = new StringBuffer(  );
266 
267                 for ( DocumentSpace child : listChilds )
268                 {
269                     bChildValidity = findSpacesByCodeType( sbChildrenXML, child.getId(  ), user, strCodeType );
270 
271                     if ( bChildValidity )
272                     {
273                         //if only one child is valid the current space must be displayed
274                         bValidSpace = true;
275                     }
276                 }
277 
278                 if ( bValidSpace )
279                 {
280                     //the space has children which are valid or have valid children
281                     XmlUtil.beginElement( sbXML, TAG_SPACE );
282                     XmlUtil.addElement( sbXML, TAG_SPACE_ID, space.getId(  ) );
283 
284                     if ( bContainCodeType && space.isDocumentCreationAllowed(  ) &&
285                             ( RBACService.isAuthorized( documentType, DocumentTypeResourceIdService.PERMISSION_CREATE,
286                                 user ) ) )
287                     {
288                         //the user can create the selected type of document into the space
289                         XmlUtil.addElement( sbXML, TAG_SPACE_IS_VALID, CONSTANT_TRUE );
290                     }
291 
292                     XmlUtil.addElement( sbXML, TAG_SPACE_NAME, space.getName(  ) );
293                     XmlUtil.addElement( sbXML, TAG_SPACE_DESCRIPTION, space.getDescription(  ) );
294                     XmlUtil.addElement( sbXML, TAG_SPACE_ICON_URL, space.getIconUrl(  ) );
295                     XmlUtil.beginElement( sbXML, TAG_SPACE_CHILDS );
296                     sbXML.append( sbChildrenXML );
297                     XmlUtil.endElement( sbXML, TAG_SPACE_CHILDS );
298                     XmlUtil.endElement( sbXML, TAG_SPACE );
299                 }
300             }
301 
302             //the space has no children
303             else
304             {
305                 if ( ( bContainCodeType ) &&
306                         RBACService.isAuthorized( documentType, DocumentTypeResourceIdService.PERMISSION_CREATE, user ) )
307                 {
308                     //the space can contain the type of document
309                     XmlUtil.beginElement( sbXML, TAG_SPACE );
310                     XmlUtil.addElement( sbXML, TAG_SPACE_ID, space.getId(  ) );
311                     XmlUtil.addElement( sbXML, TAG_SPACE_IS_VALID, CONSTANT_TRUE );
312                     XmlUtil.addElement( sbXML, TAG_SPACE_NAME, space.getName(  ) );
313                     XmlUtil.addElement( sbXML, TAG_SPACE_DESCRIPTION, space.getDescription(  ) );
314                     XmlUtil.addElement( sbXML, TAG_SPACE_ICON_URL, space.getIconUrl(  ) );
315                     XmlUtil.endElement( sbXML, TAG_SPACE );
316                     bValidSpace = true;
317                 }
318                 else
319                 {
320                     //the space can not contain the type of document or the user is not authorized
321                     bValidSpace = false;
322                 }
323             }
324         }
325 
326         return bValidSpace;
327     }
328 
329     /**
330      * Check if the user can view a space according its role
331      * @param nIdSpace The Space Id
332      * @param user The current user
333      * @return True if the user has the permission to view document Space.
334      */
335     public boolean isAuthorizedViewByRole( int nIdSpace, AdminUser user )
336     {
337         DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nIdSpace );
338         boolean bAuthorized;
339 
340         while ( space != null )
341         {
342             bAuthorized = RBACService.isAuthorized( space, SpaceResourceIdService.PERMISSION_VIEW, user );
343 
344             if ( bAuthorized )
345             {
346                 return true;
347             }
348 
349             space = DocumentSpaceHome.findByPrimaryKey( space.getIdParent(  ) );
350         }
351 
352         return false;
353     }
354 
355     /**
356      * Check if a space should be visible to the user according its workgroup
357      * @param nIdSpace the id of the space to check
358      * @param user The current user
359      * @return true if authorized, otherwise false
360      */
361     public boolean isAuthorizedViewByWorkgroup( int nIdSpace, AdminUser user )
362     {
363         if ( nIdSpace != -1 )
364         {
365             DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nIdSpace );
366 
367             if ( ( space != null ) && AdminWorkgroupService.isAuthorized( space, user ) )
368             {
369                 return isAuthorizedViewByWorkgroup( space.getIdParent(  ), user );
370             }
371 
372             return false;
373         }
374 
375         return true;
376     }
377 
378     /**
379      * Get the list of spaces allowed for a given user
380      * @param user The admin user
381      * @return The list of spaces allowed for the given user
382      */
383     public List<DocumentSpace> getUserAllowedSpaces( AdminUser user )
384     {
385         List<DocumentSpace> listSpaces = new ArrayList<DocumentSpace>(  );
386         List<DocumentSpace> listSpacesAllowed = new ArrayList<DocumentSpace>(  );
387 
388         for ( DocumentSpace space : getUserSpaces( user ) )
389         {
390             addChildSpaces( space, listSpaces );
391         }
392 
393         //verify authorization workgroup
394         for ( DocumentSpace spaceAllowed : listSpaces )
395         {
396             if ( isAuthorizedViewByWorkgroup( spaceAllowed.getId(  ), user ) )
397             {
398                 listSpacesAllowed.add( spaceAllowed );
399             }
400         }
401 
402         return listSpacesAllowed;
403     }
404 
405         /**
406      * get the HTML code to display a space browser.
407      *
408      * @param request The HTTP request
409      * @param user The current user
410      * @param bFilterViewRollUser true if the list of childs space must be
411      *            filter by RBAC view permission
412      * @param bFilterWorkspaceUser true if the list of childs space must be
413      *            filter by workgroup
414      * @param locale The Locale
415      * @return The HTML form
416      */
417     public String getSpacesBrowser( HttpServletRequest request, AdminUser user, Locale locale,
418         boolean bFilterViewRollUser, boolean bFilterWorkspaceUser )
419     {
420         return getSpacesBrowser( request, user, locale, bFilterViewRollUser, bFilterWorkspaceUser, false );
421     }
422     
423     /**
424      * get the HTML code to display a space browser.
425      *
426      * @param request The HTTP request
427      * @param user The current user
428      * @param bFilterViewRollUser true if the list of childs space must be
429      *            filter by RBAC view permission
430      * @param bFilterWorkspaceUser true if the list of childs space must be
431      *            filter by workgroup
432      * @param bSelectFilesMode true if the list spaces is used to select files only
433      * @param locale The Locale
434      * @return The HTML form
435      */
436     public String getSpacesBrowser( HttpServletRequest request, AdminUser user, Locale locale,
437         boolean bFilterViewRollUser, boolean bFilterWorkspaceUser, boolean bSelectFilesMode )
438     {
439         String strIdSpaceFilter = request.getParameter( PARAMETER_BROWSER_SELECTED_SPACE_ID );
440         String strIdSpace = request.getParameter( PARAMETER_BROWSER_SPACE_ID );
441         Map<String, Object> model = new HashMap<String, Object>(  );
442         DocumentSpace selectedSpace = null;
443         DocumentSpace space;
444         Collection<DocumentSpace> spacesList;
445         int nIdSpace = -1;
446         int i = 0;
447         boolean bIsAuthorized = true;
448         boolean bGoUp = true;
449 
450         // Selected space
451         if ( StringUtils.isNotBlank( strIdSpaceFilter ) && strIdSpaceFilter.matches( REGEX_ID ) )
452         {
453             selectedSpace = DocumentSpaceHome.findByPrimaryKey( IntegerUtils.convert( strIdSpaceFilter ) );
454         }
455 
456         // if current space doesn't exists then set it up
457         if ( IntegerUtils.isNotNumeric( strIdSpace ) )
458         {
459             nIdSpace = DocumentSpacesService.getInstance(  ).getUserDefaultSpace( user );
460         }
461         else
462         {
463             nIdSpace = IntegerUtils.convert( strIdSpace );
464         }
465 
466         // set space list
467         if ( nIdSpace == -1 )
468         {
469             space = new DocumentSpace(  );
470             space.setId( -1 );
471             space.setIdParent( -1 );
472         }
473         else
474         {
475             space = DocumentSpaceHome.findByPrimaryKey( nIdSpace );
476         }
477 
478         spacesList = DocumentSpaceHome.findChilds( space.getId(  ) );
479 
480         if ( bFilterViewRollUser )
481         {
482             bIsAuthorized = isAuthorizedViewByRole( space.getId(  ), user );
483         }
484 
485         if ( bIsAuthorized && bFilterWorkspaceUser )
486         {
487             bIsAuthorized = AdminWorkgroupService.isAuthorized( space, user );
488 
489             if ( bIsAuthorized )
490             {
491                 spacesList = AdminWorkgroupService.getAuthorizedCollection( spacesList, user );
492             }
493         }
494 
495         // set links for childs spaces
496         int[] arrayHasChilds = new int[spacesList.size(  )];
497 
498         for ( DocumentSpace documentSpace : spacesList )
499         {
500             // Check Childs spaces
501             List<DocumentSpace> childsSpaces = DocumentSpaceHome.findChilds( documentSpace.getId(  ) );
502 
503             //If childs spaces list is not empty, then add into array
504             if ( childsSpaces.size(  ) != 0 )
505             {
506                 arrayHasChilds[i] = documentSpace.getId(  );
507             }
508 
509             i++;
510         }
511 
512         if ( !bIsAuthorized )
513         {
514             //display "go up" link
515             bGoUp = false;
516         }
517        
518         model.put( MARK_GO_UP, bGoUp );
519         model.put( MARK_SELECTED_SPACE, selectedSpace );
520         model.put( MARK_SPACE, space );
521         model.put( MARK_SPACES_LIST, spacesList );
522         model.put( MARK_URLS_LIST, arrayHasChilds );
523         model.put( MARK_ACTION, request.getRequestURI(  ) );
524         
525         String _template = TEMPLATE_BROWSE_SPACES ;
526         if ( bSelectFilesMode ) _template = TEMPLATE_BROWSE_SPACES_FOR_FILE_SELECTION ;
527         
528         HtmlTemplate template = AppTemplateService.getTemplate( _template , locale, model );
529 
530         return template.getHtml(  );
531     }
532 
533     private void addChildSpaces( DocumentSpace spaceParent, List<DocumentSpace> listSpaces )
534     {
535         listSpaces.add( spaceParent );
536 
537         List<DocumentSpace> listChilds = DocumentSpaceHome.findChilds( spaceParent.getId(  ) );
538 
539         for ( DocumentSpace space : listChilds )
540         {
541             addChildSpaces( space, listSpaces );
542         }
543     }
544 
545     /**
546      * the list of parents Document space of the document space specified in
547      * parameter
548      * @param documentSpace the document space
549      * @param user the user
550      * @return the list of parents Document space of the document space
551      *         specified in parameter
552      */
553     private List<DocumentSpace> getSpaceParents( DocumentSpace documentSpace, AdminUser user )
554     {
555         List<DocumentSpace> documentSpaceParents = new ArrayList<DocumentSpace>(  );
556         getSpaceParents( documentSpace.getIdParent(  ), documentSpaceParents, user );
557 
558         return documentSpaceParents;
559     }
560 
561     /**
562      * add in the list of document space the list of parents document space
563      * specified in parameter
564      * @param nSpaceId the id of the document space
565      * @param documentSpaceParents the list of document space
566      * @param user the user
567      */
568     private void getSpaceParents( int nSpaceId, List<DocumentSpace> documentSpaceParents, AdminUser user )
569     {
570         DocumentSpace documentSpace = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
571 
572         if ( AdminWorkgroupService.isAuthorized( documentSpace, user ) )
573         {
574             if ( documentSpace.getIdParent(  ) != -1 )
575             {
576                 getSpaceParents( documentSpace.getIdParent(  ), documentSpaceParents, user );
577             }
578 
579             documentSpaceParents.add( documentSpace );
580         }
581     }
582 
583     /**
584      * the path of the document space
585      * @param nIdDocumentSpace the id of the document space
586      * @param user the user
587      * @return the path of the document space
588      */
589     public String getLabelSpacePath( int nIdDocumentSpace, AdminUser user )
590     {
591         DocumentSpace documentSpace = DocumentSpaceHome.findByPrimaryKey( nIdDocumentSpace );
592         StringBuffer sbLabelPath = new StringBuffer(  );
593 
594         if ( documentSpace != null )
595         {
596             if ( documentSpace.getIdParent(  ) != -1 )
597             {
598                 List<DocumentSpace> documentSpaceParents = getSpaceParents( documentSpace, user );
599 
600                 for ( DocumentSpace documentSpaceParent : documentSpaceParents )
601                 {
602                     sbLabelPath.append( documentSpaceParent.getName(  ) );
603                     sbLabelPath.append( "/" );
604                 }
605             }
606 
607             sbLabelPath.append( documentSpace.getName(  ) );
608         }
609 
610         return sbLabelPath.toString(  );
611     }
612 }