DocumentSpacesService.java
/*
* Copyright (c) 2002-2023, City of Paris
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice
* and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* License 1.0
*/
package fr.paris.lutece.plugins.document.service.spaces;
import fr.paris.lutece.plugins.document.business.DocumentType;
import fr.paris.lutece.plugins.document.business.DocumentTypeHome;
import fr.paris.lutece.plugins.document.business.spaces.DocumentSpace;
import fr.paris.lutece.plugins.document.business.spaces.DocumentSpaceHome;
import fr.paris.lutece.plugins.document.service.DocumentTypeResourceIdService;
import fr.paris.lutece.plugins.document.utils.IntegerUtils;
import fr.paris.lutece.portal.business.user.AdminUser;
import fr.paris.lutece.portal.service.rbac.RBACService;
import fr.paris.lutece.portal.service.template.AppTemplateService;
import fr.paris.lutece.portal.service.util.AppPathService;
import fr.paris.lutece.portal.service.workgroup.AdminWorkgroupService;
import fr.paris.lutece.util.html.HtmlTemplate;
import fr.paris.lutece.util.xml.XmlUtil;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
/**
* Document Spaces management Service.
*/
public class DocumentSpacesService
{
public static final String PARAMETER_BROWSER_SELECTED_SPACE_ID = "browser_selected_space_id";
private static final String REGEX_ID = "^[\\d]+$";
private static final String TAG_SPACES = "spaces";
private static final String TAG_SPACE = "space";
private static final String TAG_SPACE_ID = "space-id";
private static final String TAG_SPACE_IS_VALID = "space-is-valid";
private static final String TAG_SPACE_NAME = "name";
private static final String TAG_SPACE_DESCRIPTION = "description";
private static final String TAG_SPACE_CHILDS = "child-spaces";
private static final String TAG_SPACE_ICON_URL = "space-icon-url";
//browser
private static final String TEMPLATE_BROWSE_SPACES = "/admin/plugins/document/spaces/browse_spaces.html";
private static final String TEMPLATE_BROWSE_SPACES_FOR_FILE_SELECTION = "/admin/plugins/document/spaces/browse_spaces_for_file_selection.html";
private static final String MARK_SPACE = "space";
private static final String PARAMETER_BROWSER_SPACE_ID = "browser_id_space";
private static final String MARK_ACTION = "action";
private static final String MARK_SPACES_LIST = "spaces_list";
private static final String MARK_URLS_LIST = "has_childs";
private static final String MARK_SELECTED_SPACE = "selected_space";
private static final String MARK_GO_UP = "go_up";
private static final String PATH_XSL = "/WEB-INF/plugins/document/xsl/";
private static final String FILE_TREE_XSL = "document_spaces_tree.xsl";
//CONSTANTS
private static final String CONSTANT_TRUE = "true";
private static DocumentSpacesService _singleton = new DocumentSpacesService( );
/** Creates a new instance of DocumentSpacesService */
private DocumentSpacesService( )
{
}
/**
* Returns the unique instance of the service
* @return the unique instance of the service
*/
public static DocumentSpacesService getInstance( )
{
return _singleton;
}
/**
* Gets allowed Spaces for a given user as an XML document
* @param user The current user
* @return An XML document containing allowed spaces
*/
public String getXmlSpacesList( AdminUser user )
{
StringBuffer sbXML = new StringBuffer( );
XmlUtil.beginElement( sbXML, TAG_SPACES );
for ( DocumentSpace space : getUserSpaces( user ) )
{
findSpaces( sbXML, space.getId( ), user );
}
XmlUtil.endElement( sbXML, TAG_SPACES );
return sbXML.toString( );
}
/**
* Gets allowed Spaces for a given user and a type of document as an XML
* document
* @param user The current user
* @param strCodeType The code for the document type
* @return An XML document containing allowed spaces
*/
public String getXmlSpacesList( AdminUser user, String strCodeType )
{
StringBuffer sbXML = new StringBuffer( );
XmlUtil.beginElement( sbXML, TAG_SPACES );
for ( DocumentSpace space : getUserSpaces( user ) )
{
findSpacesByCodeType( sbXML, space.getId( ), user, strCodeType );
}
XmlUtil.endElement( sbXML, TAG_SPACES );
return sbXML.toString( );
}
/**
* Gets user default space
* @param user The current user
* @return The user default space
*/
public int getUserDefaultSpace( AdminUser user )
{
int nIdDefaultSpace = -1;
for ( DocumentSpace space : getUserSpaces( user ) )
{
nIdDefaultSpace = space.getId( );
}
return nIdDefaultSpace;
}
private Collection<DocumentSpace> getUserSpaces( AdminUser user )
{
Collection<DocumentSpace> listSpaces = DocumentSpaceHome.findAll( );
listSpaces = RBACService.getAuthorizedCollection( listSpaces, SpaceResourceIdService.PERMISSION_VIEW, user );
return listSpaces;
}
/**
* Gets the XSL to display user spaces tree
* @return The XSL to display user spaces tree
*/
public Source getTreeXsl( )
{
FileInputStream fis = AppPathService.getResourceAsStream( PATH_XSL, FILE_TREE_XSL );
Source xslSource = new StreamSource( fis );
return xslSource;
}
/**
* Build recursively the XML document containing the arborescence of spaces
*
* @param sbXML The buffer in which adding the current space of the
* arborescence
* @param nSpaceId The current space of the recursive course
* @param user AdminUser
*/
private void findSpaces( StringBuffer sbXML, int nSpaceId, AdminUser user )
{
DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
if ( AdminWorkgroupService.isAuthorized( space, user ) )
{
XmlUtil.beginElement( sbXML, TAG_SPACE );
XmlUtil.addElement( sbXML, TAG_SPACE_ID, space.getId( ) );
XmlUtil.addElement( sbXML, TAG_SPACE_NAME, StringEscapeUtils.escapeXml( space.getName( ) ) );
XmlUtil.addElement( sbXML, TAG_SPACE_DESCRIPTION, space.getDescription( ) );
XmlUtil.addElement( sbXML, TAG_SPACE_ICON_URL, space.getIconUrl( ) );
List<DocumentSpace> listChilds = DocumentSpaceHome.findChilds( nSpaceId );
if ( listChilds.size( ) > 0 )
{
XmlUtil.beginElement( sbXML, TAG_SPACE_CHILDS );
for ( DocumentSpace child : listChilds )
{
findSpaces( sbXML, child.getId( ), user );
}
XmlUtil.endElement( sbXML, TAG_SPACE_CHILDS );
}
XmlUtil.endElement( sbXML, TAG_SPACE );
}
}
/**
* Build recursively the XML document containing the arborescence of spaces
*
* @param sbXML The buffer in which adding the current space of the
* arborescence
* @param nSpaceId The current space of the recursive course
* @param user AdminUser
* @param strCodeType The code type
* @return True if the space is valid, false otherwise
*/
private boolean findSpacesByCodeType( StringBuffer sbXML, int nSpaceId, AdminUser user, String strCodeType )
{
DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
DocumentType documentType = DocumentTypeHome.findByPrimaryKey( strCodeType );
boolean bValidSpace = false;
boolean bChildValidity = false;
if ( AdminWorkgroupService.isAuthorized( space, user ) )
{
Collection<DocumentSpace> listChilds = DocumentSpaceHome.findChilds( nSpaceId );
boolean bContainCodeType = false;
for ( String strCodeTypeDocument : space.getAllowedDocumentTypes( ) )
{
if ( strCodeTypeDocument.equals( strCodeType ) )
{
bContainCodeType = true;
}
}
if ( listChilds.size( ) > 0 )
{
StringBuffer sbChildrenXML = new StringBuffer( );
for ( DocumentSpace child : listChilds )
{
bChildValidity = findSpacesByCodeType( sbChildrenXML, child.getId( ), user, strCodeType );
if ( bChildValidity )
{
//if only one child is valid the current space must be displayed
bValidSpace = true;
}
}
if ( bValidSpace )
{
//the space has children which are valid or have valid children
XmlUtil.beginElement( sbXML, TAG_SPACE );
XmlUtil.addElement( sbXML, TAG_SPACE_ID, space.getId( ) );
if ( bContainCodeType && space.isDocumentCreationAllowed( ) &&
( RBACService.isAuthorized( documentType, DocumentTypeResourceIdService.PERMISSION_CREATE,
user ) ) )
{
//the user can create the selected type of document into the space
XmlUtil.addElement( sbXML, TAG_SPACE_IS_VALID, CONSTANT_TRUE );
}
XmlUtil.addElement( sbXML, TAG_SPACE_NAME, space.getName( ) );
XmlUtil.addElement( sbXML, TAG_SPACE_DESCRIPTION, space.getDescription( ) );
XmlUtil.addElement( sbXML, TAG_SPACE_ICON_URL, space.getIconUrl( ) );
XmlUtil.beginElement( sbXML, TAG_SPACE_CHILDS );
sbXML.append( sbChildrenXML );
XmlUtil.endElement( sbXML, TAG_SPACE_CHILDS );
XmlUtil.endElement( sbXML, TAG_SPACE );
}
}
//the space has no children
else
{
if ( ( bContainCodeType ) &&
RBACService.isAuthorized( documentType, DocumentTypeResourceIdService.PERMISSION_CREATE, user ) )
{
//the space can contain the type of document
XmlUtil.beginElement( sbXML, TAG_SPACE );
XmlUtil.addElement( sbXML, TAG_SPACE_ID, space.getId( ) );
XmlUtil.addElement( sbXML, TAG_SPACE_IS_VALID, CONSTANT_TRUE );
XmlUtil.addElement( sbXML, TAG_SPACE_NAME, space.getName( ) );
XmlUtil.addElement( sbXML, TAG_SPACE_DESCRIPTION, space.getDescription( ) );
XmlUtil.addElement( sbXML, TAG_SPACE_ICON_URL, space.getIconUrl( ) );
XmlUtil.endElement( sbXML, TAG_SPACE );
bValidSpace = true;
}
else
{
//the space can not contain the type of document or the user is not authorized
bValidSpace = false;
}
}
}
return bValidSpace;
}
/**
* Check if the user can view a space according its role
* @param nIdSpace The Space Id
* @param user The current user
* @return True if the user has the permission to view document Space.
*/
public boolean isAuthorizedViewByRole( int nIdSpace, AdminUser user )
{
DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nIdSpace );
boolean bAuthorized;
while ( space != null )
{
bAuthorized = RBACService.isAuthorized( space, SpaceResourceIdService.PERMISSION_VIEW, user );
if ( bAuthorized )
{
return true;
}
space = DocumentSpaceHome.findByPrimaryKey( space.getIdParent( ) );
}
return false;
}
/**
* Check if a space should be visible to the user according its workgroup
* @param nIdSpace the id of the space to check
* @param user The current user
* @return true if authorized, otherwise false
*/
public boolean isAuthorizedViewByWorkgroup( int nIdSpace, AdminUser user )
{
if ( nIdSpace != -1 )
{
DocumentSpace space = DocumentSpaceHome.findByPrimaryKey( nIdSpace );
if ( ( space != null ) && AdminWorkgroupService.isAuthorized( space, user ) )
{
return isAuthorizedViewByWorkgroup( space.getIdParent( ), user );
}
return false;
}
return true;
}
/**
* Get the list of spaces allowed for a given user
* @param user The admin user
* @return The list of spaces allowed for the given user
*/
public List<DocumentSpace> getUserAllowedSpaces( AdminUser user )
{
List<DocumentSpace> listSpaces = new ArrayList<DocumentSpace>( );
List<DocumentSpace> listSpacesAllowed = new ArrayList<DocumentSpace>( );
for ( DocumentSpace space : getUserSpaces( user ) )
{
addChildSpaces( space, listSpaces );
}
//verify authorization workgroup
for ( DocumentSpace spaceAllowed : listSpaces )
{
if ( isAuthorizedViewByWorkgroup( spaceAllowed.getId( ), user ) )
{
listSpacesAllowed.add( spaceAllowed );
}
}
return listSpacesAllowed;
}
/**
* get the HTML code to display a space browser.
*
* @param request The HTTP request
* @param user The current user
* @param bFilterViewRollUser true if the list of childs space must be
* filter by RBAC view permission
* @param bFilterWorkspaceUser true if the list of childs space must be
* filter by workgroup
* @param locale The Locale
* @return The HTML form
*/
public String getSpacesBrowser( HttpServletRequest request, AdminUser user, Locale locale,
boolean bFilterViewRollUser, boolean bFilterWorkspaceUser )
{
return getSpacesBrowser( request, user, locale, bFilterViewRollUser, bFilterWorkspaceUser, false );
}
/**
* get the HTML code to display a space browser.
*
* @param request The HTTP request
* @param user The current user
* @param bFilterViewRollUser true if the list of childs space must be
* filter by RBAC view permission
* @param bFilterWorkspaceUser true if the list of childs space must be
* filter by workgroup
* @param bSelectFilesMode true if the list spaces is used to select files only
* @param locale The Locale
* @return The HTML form
*/
public String getSpacesBrowser( HttpServletRequest request, AdminUser user, Locale locale,
boolean bFilterViewRollUser, boolean bFilterWorkspaceUser, boolean bSelectFilesMode )
{
String strIdSpaceFilter = request.getParameter( PARAMETER_BROWSER_SELECTED_SPACE_ID );
String strIdSpace = request.getParameter( PARAMETER_BROWSER_SPACE_ID );
Map<String, Object> model = new HashMap<String, Object>( );
DocumentSpace selectedSpace = null;
DocumentSpace space;
Collection<DocumentSpace> spacesList;
int nIdSpace = -1;
int i = 0;
boolean bIsAuthorized = true;
boolean bGoUp = true;
// Selected space
if ( StringUtils.isNotBlank( strIdSpaceFilter ) && strIdSpaceFilter.matches( REGEX_ID ) )
{
selectedSpace = DocumentSpaceHome.findByPrimaryKey( IntegerUtils.convert( strIdSpaceFilter ) );
}
// if current space doesn't exists then set it up
if ( IntegerUtils.isNotNumeric( strIdSpace ) )
{
nIdSpace = DocumentSpacesService.getInstance( ).getUserDefaultSpace( user );
}
else
{
nIdSpace = IntegerUtils.convert( strIdSpace );
}
// set space list
if ( nIdSpace == -1 )
{
space = new DocumentSpace( );
space.setId( -1 );
space.setIdParent( -1 );
}
else
{
space = DocumentSpaceHome.findByPrimaryKey( nIdSpace );
}
spacesList = DocumentSpaceHome.findChilds( space.getId( ) );
if ( bFilterViewRollUser )
{
bIsAuthorized = isAuthorizedViewByRole( space.getId( ), user );
}
if ( bIsAuthorized && bFilterWorkspaceUser )
{
bIsAuthorized = AdminWorkgroupService.isAuthorized( space, user );
if ( bIsAuthorized )
{
spacesList = AdminWorkgroupService.getAuthorizedCollection( spacesList, user );
}
}
// set links for childs spaces
int[] arrayHasChilds = new int[spacesList.size( )];
for ( DocumentSpace documentSpace : spacesList )
{
// Check Childs spaces
List<DocumentSpace> childsSpaces = DocumentSpaceHome.findChilds( documentSpace.getId( ) );
//If childs spaces list is not empty, then add into array
if ( childsSpaces.size( ) != 0 )
{
arrayHasChilds[i] = documentSpace.getId( );
}
i++;
}
if ( !bIsAuthorized )
{
//display "go up" link
bGoUp = false;
}
model.put( MARK_GO_UP, bGoUp );
model.put( MARK_SELECTED_SPACE, selectedSpace );
model.put( MARK_SPACE, space );
model.put( MARK_SPACES_LIST, spacesList );
model.put( MARK_URLS_LIST, arrayHasChilds );
model.put( MARK_ACTION, request.getRequestURI( ) );
String _template = TEMPLATE_BROWSE_SPACES ;
if ( bSelectFilesMode ) _template = TEMPLATE_BROWSE_SPACES_FOR_FILE_SELECTION ;
HtmlTemplate template = AppTemplateService.getTemplate( _template , locale, model );
return template.getHtml( );
}
private void addChildSpaces( DocumentSpace spaceParent, List<DocumentSpace> listSpaces )
{
listSpaces.add( spaceParent );
List<DocumentSpace> listChilds = DocumentSpaceHome.findChilds( spaceParent.getId( ) );
for ( DocumentSpace space : listChilds )
{
addChildSpaces( space, listSpaces );
}
}
/**
* the list of parents Document space of the document space specified in
* parameter
* @param documentSpace the document space
* @param user the user
* @return the list of parents Document space of the document space
* specified in parameter
*/
private List<DocumentSpace> getSpaceParents( DocumentSpace documentSpace, AdminUser user )
{
List<DocumentSpace> documentSpaceParents = new ArrayList<DocumentSpace>( );
getSpaceParents( documentSpace.getIdParent( ), documentSpaceParents, user );
return documentSpaceParents;
}
/**
* add in the list of document space the list of parents document space
* specified in parameter
* @param nSpaceId the id of the document space
* @param documentSpaceParents the list of document space
* @param user the user
*/
private void getSpaceParents( int nSpaceId, List<DocumentSpace> documentSpaceParents, AdminUser user )
{
DocumentSpace documentSpace = DocumentSpaceHome.findByPrimaryKey( nSpaceId );
if ( AdminWorkgroupService.isAuthorized( documentSpace, user ) )
{
if ( documentSpace.getIdParent( ) != -1 )
{
getSpaceParents( documentSpace.getIdParent( ), documentSpaceParents, user );
}
documentSpaceParents.add( documentSpace );
}
}
/**
* the path of the document space
* @param nIdDocumentSpace the id of the document space
* @param user the user
* @return the path of the document space
*/
public String getLabelSpacePath( int nIdDocumentSpace, AdminUser user )
{
DocumentSpace documentSpace = DocumentSpaceHome.findByPrimaryKey( nIdDocumentSpace );
StringBuffer sbLabelPath = new StringBuffer( );
if ( documentSpace != null )
{
if ( documentSpace.getIdParent( ) != -1 )
{
List<DocumentSpace> documentSpaceParents = getSpaceParents( documentSpace, user );
for ( DocumentSpace documentSpaceParent : documentSpaceParents )
{
sbLabelPath.append( documentSpaceParent.getName( ) );
sbLabelPath.append( "/" );
}
}
sbLabelPath.append( documentSpace.getName( ) );
}
return sbLabelPath.toString( );
}
}