AbstractEntryTypeUpload.java
/*
* Copyright (c) 2002-2022, 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.genericattributes.service.entrytype;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import fr.paris.lutece.plugins.asynchronousupload.service.IAsyncUploadHandler;
import fr.paris.lutece.plugins.genericattributes.business.Entry;
import fr.paris.lutece.plugins.genericattributes.business.Field;
import fr.paris.lutece.plugins.genericattributes.business.FieldHome;
import fr.paris.lutece.plugins.genericattributes.business.GenericAttributeError;
import fr.paris.lutece.plugins.genericattributes.business.Response;
import fr.paris.lutece.plugins.genericattributes.service.file.GenericAttributeFileService;
import fr.paris.lutece.plugins.genericattributes.util.FileAttributesUtils;
import fr.paris.lutece.portal.business.file.File;
import fr.paris.lutece.portal.business.regularexpression.RegularExpression;
import fr.paris.lutece.portal.service.fileupload.FileUploadService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.plugin.Plugin;
import fr.paris.lutece.portal.service.regularexpression.RegularExpressionService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPathService;
import fr.paris.lutece.util.ReferenceList;
import fr.paris.lutece.util.url.UrlItem;
/**
* Abstract entry type for uploads
*/
public abstract class AbstractEntryTypeUpload extends EntryTypeService
{
// PARAMETERS
protected static final String PARAMETER_ID_RESPONSE = "id_response";
protected static final String PARAMETER_MAX_FILES = "max_files";
protected static final String PARAMETER_FILE_MAX_SIZE = "file_max_size";
protected static final String PARAMETER_EXPORT_BINARY = "export_binary";
protected static final String PARAMETER_FILE_TYPE = "file_type";
// CONSTANTS
protected static final String ALL = "*";
protected static final String COMMA = ",";
// Private parameters
protected static final String PARAMETER_RESOURCE_TYPE = "resource_type";
protected static final String PARAMETER_ID = "id";
protected static final String URL_IMAGE_SERVLET = "image";
// MESSAGES
protected static final String MESSAGE_ERROR_NOT_AN_IMAGE = "genericattributes.message.notAnImage";
/**
* Get the asynchronous upload handler to use for entries of this type
*
* @return The asynchronous upload handler to use for entries of this type
*/
public abstract IAsyncUploadHandler getAsynchronousUploadHandler( );
/**
* Get the URL to download the file of a response
*
* @param nResponseId
* The id of the response to download the file of
* @param strBaseUrl
* The base URL
* @return The URL to redirect the user to download the file
*/
public abstract String getUrlDownloadFile( int nResponseId, String strBaseUrl );
/**
* Check whether this entry type allows only images or every file type
*
* @return True if this entry type allows only images, false if it allow every file type
*/
protected abstract boolean checkForImages( );
/**
* Get the URL to download a file of a response throw the image servlet.
*
* @param nResponseId
* The id of the response
* @param strBaseUrl
* The base URL
* @return The URL of to download the image
*/
protected String getUrlDownloadImage( int nResponseId, String strBaseUrl )
{
UrlItem url = new UrlItem( strBaseUrl + URL_IMAGE_SERVLET );
url.addParameter( PARAMETER_RESOURCE_TYPE, Response.RESOURCE_TYPE );
url.addParameter( PARAMETER_ID, nResponseId );
return url.getUrl( );
}
/**
* {@inheritDoc}
*/
@Override
public GenericAttributeError canUploadFiles( Entry entry, List<FileItem> listUploadedFileItems, List<FileItem> listFileItemsToUpload, Locale locale )
{
/** 1) Check max files */
GenericAttributeError error = FileAttributesUtils.checkNumberFiles( entry, listUploadedFileItems, listFileItemsToUpload, locale );
if ( error != null )
{
return error;
}
/** 2) Check files size */
error = FileAttributesUtils.checkFileSize( entry, listUploadedFileItems, listFileItemsToUpload, locale );
if ( error != null )
{
return error;
}
if ( listFileItemsToUpload != null )
{
for ( FileItem fileItem : listFileItemsToUpload )
{
if ( checkForImages( ) )
{
error = doCheckforImages( fileItem, entry, locale );
if ( error != null )
{
return error;
}
}
}
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public String getResponseValueForExport( Entry entry, HttpServletRequest request, Response response, Locale locale )
{
// Check whether the binaries must be exported or just displaying an URL to download the file
if ( entry.getFields( ) == null )
{
entry.setFields( FieldHome.getFieldListByIdEntry( entry.getIdEntry( ) ) );
}
Field field = entry.getFieldByCode( FIELD_FILE_BINARY );
if ( ( field != null ) && StringUtils.isNotBlank( field.getValue( ) ) && Boolean.TRUE.equals( Boolean.valueOf( field.getValue( ) ) ) )
{
if ( response.getFile( ) != null )
{
File file = GenericAttributeFileService.getInstance( ).load( response.getFile( ).getFileKey( ), response.getFile( ).getOrigin( ) );
if ( ( file != null ) && ( file.getPhysicalFile( ) != null ) && ( file.getPhysicalFile( ).getValue( ) != null ) )
{
String strPhysicalFile = Arrays.toString( file.getPhysicalFile( ).getValue( ) );
if ( StringUtils.isNotBlank( strPhysicalFile ) )
{
// Removing the square brackets ("[]") that "Arrays.toString" added
return strPhysicalFile.substring( 1, strPhysicalFile.length( ) - 1 );
}
}
}
return StringUtils.EMPTY;
}
String strBaseUrl = AppPathService.getBaseUrl( request );
return getUrlDownloadFile( response.getIdResponse( ), strBaseUrl );
}
// CHECKS
/**
* Check the record field data
*
* @param entry
* The entry
* @param listFilesSource
* the list of source files to upload
* @param locale
* the locale
* @param request
* the HTTP request
* @return The error if there is any
*/
protected GenericAttributeError checkResponseData( Entry entry, List<FileItem> listFilesSource, Locale locale, HttpServletRequest request )
{
// Check if the user can upload the file. The File is already uploaded in the asynchronous uploaded files map
// Thus the list of files to upload is in the list of uploaded files
GenericAttributeError error = canUploadFiles( entry, listFilesSource, new ArrayList<FileItem>( ), locale );
if ( error != null )
{
return error;
}
return FileAttributesUtils.checkResponseData( entry, listFilesSource, locale );
}
// FINDERS
/**
* Get the file source from the session
*
* @param request
* the HttpServletRequest
* @param strAttributeName
* the attribute name
* @return the file item
*/
protected List<FileItem> getFileSources( HttpServletRequest request, String strAttributeName )
{
if ( request != null )
{
// Files are only removed if a given flag is in the request
getAsynchronousUploadHandler( ).doRemoveFile( request, strAttributeName );
// Files are only added if a given flag is in the request
getAsynchronousUploadHandler( ).addFilesUploadedSynchronously( request, strAttributeName );
return getAsynchronousUploadHandler( ).getListUploadedFiles( strAttributeName, request.getSession( ) );
}
return new ArrayList<>( );
}
/**
* Gives the attribute name
*
* @param entry
* the entry
* @param request
* the request
* @return the attribute name
*/
protected String getAttributeName( Entry entry, HttpServletRequest request )
{
String strAttributePrefix = IEntryTypeService.PREFIX_ATTRIBUTE + Integer.toString( entry.getIdEntry( ) );
int nIterationNumber = getResponseIterationValue( request );
if ( nIterationNumber != NumberUtils.INTEGER_MINUS_ONE )
{
strAttributePrefix = IEntryTypeService.PREFIX_ITERATION_ATTRIBUTE + nIterationNumber + "_" + strAttributePrefix;
}
return strAttributePrefix;
}
// PRIVATE METHODS
/**
* {@inheritDoc}
*/
@Override
public String getRequestData( Entry entry, HttpServletRequest request, Locale locale )
{
initCommonRequestData( entry, request );
String strTitle = request.getParameter( PARAMETER_TITLE );
String strHelpMessage = ( request.getParameter( PARAMETER_HELP_MESSAGE ) != null ) ? request.getParameter( PARAMETER_HELP_MESSAGE ).trim( ) : null;
String strComment = request.getParameter( PARAMETER_COMMENT );
String strMandatory = request.getParameter( PARAMETER_MANDATORY );
String strCSSClass = request.getParameter( PARAMETER_CSS_CLASS );
String strCode = request.getParameter( PARAMETER_ENTRY_CODE );
String strOnlyDisplayInBack = request.getParameter( PARAMETER_ONLY_DISPLAY_IN_BACK );
String strIndexed = request.getParameter( PARAMETER_INDEXED );
String strError = FileAttributesUtils.checkEntryData( request, locale );
if ( StringUtils.isNotBlank( strError ) )
{
return strError;
}
entry.setTitle( strTitle );
entry.setCode( strCode );
entry.setHelpMessage( strHelpMessage );
entry.setComment( strComment );
entry.setCSSClass( strCSSClass );
entry.setIndexed( strIndexed != null );
FileAttributesUtils.createOrUpdateFileFields( entry, request );
entry.setMandatory( strMandatory != null );
entry.setOnlyDisplayInBack( strOnlyDisplayInBack != null );
return null;
}
/**
* {@inheritDoc}
*/
@Override
public ReferenceList getReferenceListRegularExpression( Entry entry, Plugin plugin )
{
ReferenceList refListRegularExpression = null;
if ( RegularExpressionService.getInstance( ).isAvailable( ) )
{
refListRegularExpression = new ReferenceList( );
List<RegularExpression> listRegularExpression = RegularExpressionService.getInstance( ).getAllRegularExpression( );
for ( RegularExpression regularExpression : listRegularExpression )
{
if ( !entry.getFields( ).get( 0 ).getRegularExpressionList( ).contains( regularExpression ) )
{
refListRegularExpression.addItem( regularExpression.getIdExpression( ), regularExpression.getTitle( ) );
}
}
}
return refListRegularExpression;
}
/**
* toStringValue should stay <code>null</code>.
*
* @param entry
* The entry
* @param response
* The response
* @param locale
* the locale - will use a default one if not specified
*/
@Override
public void setResponseToStringValue( Entry entry, Response response, Locale locale )
{
// nothing - null is default
}
/**
* {@inheritDoc}
*/
@Override
public String getResponseValueForRecap( Entry entry, HttpServletRequest request, Response response, Locale locale )
{
if ( ( response.getFile( ) != null ) && StringUtils.isNotBlank( response.getFile( ).getTitle( ) ) )
{
return response.getFile( ).getTitle( );
}
return StringUtils.EMPTY;
}
/**
* Do check that an uploaded file is an image
*
* @param fileItem
* The file item
* @param entry
* the entry
* @param locale
* The locale
* @return The error if any, or null if the file is a valid image
*/
public GenericAttributeError doCheckforImages( FileItem fileItem, Entry entry, Locale locale )
{
String strFilename = FileUploadService.getFileNameOnly( fileItem );
BufferedImage image = null;
try
{
if ( fileItem.get( ) != null )
{
image = ImageIO.read( new ByteArrayInputStream( fileItem.get( ) ) );
}
}
catch( IOException e )
{
AppLogService.error( e );
}
if ( ( image == null ) && StringUtils.isNotBlank( strFilename ) )
{
GenericAttributeError genAttError = new GenericAttributeError( );
genAttError.setMandatoryError( false );
Object [ ] args = {
fileItem.getName( )
};
genAttError.setErrorMessage( I18nService.getLocalizedString( MESSAGE_ERROR_NOT_AN_IMAGE, args, locale ) );
genAttError.setTitleQuestion( entry.getTitle( ) );
return genAttError;
}
return null;
}
}