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.genericattributes.service.entrytype;
35  
36  import java.awt.image.BufferedImage;
37  import java.io.ByteArrayInputStream;
38  import java.io.ByteArrayOutputStream;
39  import java.io.IOException;
40  import java.text.SimpleDateFormat;
41  import java.util.Calendar;
42  import java.util.List;
43  import java.util.Locale;
44  import java.util.Optional;
45  
46  import javax.imageio.ImageIO;
47  import javax.servlet.http.HttpServletRequest;
48  
49  import org.apache.commons.lang3.StringUtils;
50  
51  import fr.paris.lutece.plugins.genericattributes.business.Entry;
52  import fr.paris.lutece.plugins.genericattributes.business.Field;
53  import fr.paris.lutece.plugins.genericattributes.business.GenericAttributeError;
54  import fr.paris.lutece.plugins.genericattributes.business.MandatoryError;
55  import fr.paris.lutece.plugins.genericattributes.business.Response;
56  import fr.paris.lutece.plugins.genericattributes.util.FileAttributesUtils;
57  import fr.paris.lutece.plugins.genericattributes.util.GenericAttributesUtils;
58  import fr.paris.lutece.portal.business.file.File;
59  import fr.paris.lutece.portal.business.physicalfile.PhysicalFile;
60  import fr.paris.lutece.portal.service.i18n.I18nService;
61  import fr.paris.lutece.portal.service.message.AdminMessage;
62  import fr.paris.lutece.portal.service.message.AdminMessageService;
63  import fr.paris.lutece.portal.service.util.AppLogService;
64  import fr.paris.lutece.portal.service.util.AppPropertiesService;
65  import fr.paris.lutece.portal.web.upload.MultipartHttpServletRequest;
66  import fr.paris.lutece.util.filesystem.FileSystemUtil;
67  
68  /**
69   *
70   * AbstractEntryTypeCamera
71   *
72   */
73  public abstract class AbstractEntryTypeCamera extends AbstractEntryTypeImage
74  {
75      private static final String PROPERTY_IMAGE_TITLE = AppPropertiesService.getProperty( "genericattributes.image.prefix.title", "default" );
76      private static final String PROPERTY_IMAGE_TITLE_DATE_FORMAT = AppPropertiesService.getProperty( "genericattributes.image.date.format.title",
77              "YYYY-MM-DD hh:mm:ss" );
78  
79      /**
80       * {@inheritDoc}
81       */
82      @Override
83      public String getRequestData( Entry entry, HttpServletRequest request, Locale locale )
84      {
85          initCommonRequestData( entry, request );
86          String strCode = request.getParameter( PARAMETER_ENTRY_CODE );
87          String strTitle = request.getParameter( PARAMETER_TITLE );
88          String strHelpMessage = ( request.getParameter( PARAMETER_HELP_MESSAGE ) != null ) ? request.getParameter( PARAMETER_HELP_MESSAGE ).trim( ) : null;
89          String strComment = request.getParameter( PARAMETER_COMMENT );
90          String strMaxImageSize = request.getParameter( PARAMETER_MAX_IMAGE_SIZE );
91          String strMandatory = request.getParameter( PARAMETER_MANDATORY );
92          String strWidth = request.getParameter( PARAMETER_WIDTH );
93          String strHeight = request.getParameter( PARAMETER_HEIGHT );
94          String strUnique = request.getParameter( PARAMETER_UNIQUE );
95          String strCSSClass = request.getParameter( PARAMETER_CSS_CLASS );
96          String strOnlyDisplayInBack = request.getParameter( PARAMETER_ONLY_DISPLAY_IN_BACK );
97          String strErrorMessage = request.getParameter( PARAMETER_ERROR_MESSAGE );
98  
99          String strTypeImage = request.getParameter( PARAMETER_IMAGE_TYPE );
100 
101         int nWidth = -1;
102         int nheight = -1;
103         int nMaxImageSize = -1;
104 
105         String strFieldError = StringUtils.EMPTY;
106 
107         if ( StringUtils.isBlank( strTitle ) )
108         {
109             strFieldError = ERROR_FIELD_TITLE;
110         }
111 
112         else
113             if ( StringUtils.isBlank( strWidth ) )
114             {
115                 strFieldError = ERROR_FIELD_WIDTH;
116             }
117 
118         if ( StringUtils.isNotBlank( strFieldError ) )
119         {
120             Object [ ] tabRequiredFields = {
121                     I18nService.getLocalizedString( strFieldError, locale )
122             };
123 
124             return AdminMessageService.getMessageUrl( request, MESSAGE_MANDATORY_FIELD, tabRequiredFields, AdminMessage.TYPE_STOP );
125         }
126 
127         try
128         {
129             nWidth = Integer.parseInt( strWidth );
130         }
131         catch( NumberFormatException ne )
132         {
133             strFieldError = ERROR_FIELD_WIDTH;
134         }
135 
136         try
137         {
138             if ( StringUtils.isNotBlank( strHeight ) )
139             {
140                 nheight = Integer.parseInt( strHeight );
141             }
142         }
143         catch( NumberFormatException ne )
144         {
145             strFieldError = ERROR_FIELD_HEIGHT;
146         }
147 
148         try
149         {
150             if ( StringUtils.isNotBlank( strMaxImageSize ) )
151             {
152                 nMaxImageSize = Integer.parseInt( strMaxImageSize );
153             }
154         }
155         catch( NumberFormatException ne )
156         {
157             strFieldError = ERROR_FIELD_HEIGHT;
158         }
159 
160         if ( StringUtils.isNotBlank( strFieldError ) )
161         {
162             Object [ ] tabRequiredFields = {
163                     I18nService.getLocalizedString( strFieldError, locale )
164             };
165 
166             return AdminMessageService.getMessageUrl( request, MESSAGE_NUMERIC_FIELD, tabRequiredFields, AdminMessage.TYPE_STOP );
167         }
168 
169         entry.setTitle( strTitle );
170         entry.setHelpMessage( strHelpMessage );
171         entry.setComment( strComment );
172         entry.setCSSClass( strCSSClass );
173         entry.setErrorMessage( strErrorMessage );
174         entry.setCode( strCode );
175 
176         GenericAttributesUtils.createOrUpdateField( entry, FIELD_IMAGE_TYPE, null, strTypeImage );
177         GenericAttributesUtils.createOrUpdateField( entry, FIELD_WIDTH, null, String.valueOf( nWidth ) );
178         GenericAttributesUtils.createOrUpdateField( entry, FIELD_HEIGHT, null, String.valueOf( nheight ) );
179         GenericAttributesUtils.createOrUpdateField( entry, FIELD_MAX_SIZE, null, String.valueOf( nMaxImageSize ) );
180 
181         entry.setMandatory( strMandatory != null );
182         entry.setOnlyDisplayInBack( strOnlyDisplayInBack != null );
183         entry.setUnique( strUnique != null );
184         return null;
185     }
186 
187     /**
188      * {@inheritDoc}
189      */
190     @Override
191     public GenericAttributeError getResponseData( Entry entry, HttpServletRequest request, List<Response> listResponse, Locale locale )
192     {
193         if ( !( request instanceof MultipartHttpServletRequest ) )
194         {
195             return entry.isMandatory( ) ? new MandatoryError( entry, locale ) : null;
196         }
197 
198         GenericAttributeError genAttError = null;
199         String sourceBase = request.getParameter( ( IEntryTypeService.PREFIX_ATTRIBUTE + entry.getIdEntry( ) ) );
200 
201         if ( sourceBase != null )
202         {
203             genAttError = doCheckforImages( sourceBase, entry, request.getLocale( ) );
204 
205             if ( genAttError != null )
206             {
207                 return genAttError;
208             }
209 
210             listResponse.add( getResponseFromImage( request, sourceBase, entry, true ) );
211 
212             if ( !entry.isMandatory( ) )
213             {
214                 return genAttError;
215             }
216 
217             if ( entry.isMandatory( ) && ( StringUtils.isBlank( sourceBase ) || StringUtils.isEmpty( sourceBase ) ) )
218             {
219                 if ( StringUtils.isNotEmpty( entry.getErrorMessage( ) ) )
220                 {
221                     GenericAttributeErrortributes/business/GenericAttributeError.html#GenericAttributeError">GenericAttributeError error = new GenericAttributeError( );
222                     error.setMandatoryError( true );
223                     error.setErrorMessage( entry.getErrorMessage( ) );
224 
225                     return error;
226                 }
227 
228                 return new MandatoryError( entry, locale );
229             }
230         }
231 
232         return genAttError;
233     }
234 
235     /**
236      * Get a generic attributes response from a request
237      * 
238      * @param request
239      * @param imageSource
240      *            the image in base64 form
241      * @param entry
242      *            The entry
243      * @param bCreatePhysicalFile
244      *            True to create the physical file associated with the file of the response, false otherwise. Note that the physical file will never be saved in
245      *            the database by this method, like any other created object.
246      * @return The created response
247      */
248     protected Response getResponseFromImage( HttpServletRequest request, String imageSource, Entry entry, boolean bCreatePhysicalFile )
249     {
250         Response/genericattributes/business/Response.html#Response">Response response = new Response( );
251         response.setEntry( entry );
252         String fileName = null;
253         SimpleDateFormat dt = new SimpleDateFormat( PROPERTY_IMAGE_TITLE_DATE_FORMAT );
254 
255         Field imageTypeField = entry.getFieldByCode( FIELD_IMAGE_TYPE );
256         String imageType = Optional.ofNullable( imageTypeField ).map( i -> "." + i.getValue( ) ).orElse( "" );
257 
258         Calendar c = Calendar.getInstance( );
259         String [ ] imageTitle = PROPERTY_IMAGE_TITLE.trim( ).split( "," );
260         if ( imageTitle != null )
261         {
262             fileName = "";
263             for ( String imgTitle : imageTitle )
264             {
265                 if ( request.getParameter( imgTitle ) != null && StringUtils.isNotBlank( request.getParameter( imgTitle ) ) )
266                 {
267 
268                     fileName = fileName.concat( request.getParameter( imgTitle ) ).concat( "-" );
269                 }
270             }
271         }
272 
273         if ( StringUtils.isNotBlank( imageSource ) && StringUtils.isNotEmpty( imageSource ) )
274         {
275             File file = new File( );
276 
277             if ( fileName != null )
278             {
279                 file.setTitle( fileName + dt.format( c.getTime( ) ) + imageType );
280             }
281             else
282             {
283                 file.setTitle( entry.getTitle( ) + dt.format( c.getTime( ) ) + imageType );
284             }
285             file.setExtension( imageType );
286             if ( bCreatePhysicalFile )
287             {
288                 file.setMimeType( FileSystemUtil.getMIMEType( file.getTitle( ) ) );
289 
290                 PhysicalFile physicalFile = new PhysicalFile( );
291                 String base64Image = imageSource.split( "," ) [1];
292                 byte [ ] imageBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary( base64Image );
293                 physicalFile.setValue( imageBytes );
294                 file.setPhysicalFile( physicalFile );
295                 file.setSize( imageBytes.length );
296             }
297 
298             response.setFile( file );
299             response.setIsImage( true );
300             response.setToStringValueResponse( imageSource );
301         }
302         else
303         {
304             response.setToStringValueResponse( StringUtils.EMPTY );
305         }
306 
307         response.setIterationNumber( getResponseIterationValue( request ) );
308 
309         return response;
310     }
311 
312     @Override
313     public String getResponseValueForRecap( Entry entry, HttpServletRequest request, Response response, Locale locale )
314     {
315         if ( ( response.getFile( ) != null ) && StringUtils.isNotBlank( response.getToStringValueResponse( ) ) )
316         {
317             return response.getToStringValueResponse( );
318         }
319 
320         return StringUtils.EMPTY;
321     }
322 
323     /**
324      * Do check that an uploaded source is an image
325      * 
326      * @param imageSource
327      *            The file imageSource
328      * @param entry
329      *            the entry
330      * @param locale
331      *            The locale
332      * @return The error if any, or null if the file is a valid image
333      */
334     public GenericAttributeError doCheckforImages( String imageSource, Entry entry, Locale locale )
335     {
336         BufferedImage image = null;
337         GenericAttributeErrores/business/GenericAttributeError.html#GenericAttributeError">GenericAttributeError genAttError = new GenericAttributeError( );
338         genAttError.setMandatoryError( false );
339 
340         Object [ ] args = {
341                 entry.getTitle( )
342         };
343         genAttError.setErrorMessage( I18nService.getLocalizedString( MESSAGE_ERROR_NOT_AN_IMAGE, args, locale ) );
344         genAttError.setTitleQuestion( entry.getTitle( ) );
345 
346         if ( ( imageSource != null ) && ( imageSource.split( "," ).length > 1 ) )
347         {
348             String base64Image = imageSource.split( "," ) [1];
349             byte [ ] imageBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary( base64Image );
350             ByteArrayInputStream bis = new ByteArrayInputStream( imageBytes );
351 
352             try
353             {
354                 image = ImageIO.read( bis );
355                 bis.close( );
356             }
357             catch( IOException e )
358             {
359                 return genAttError;
360             }
361         }
362 
363         if ( ( image == null ) && StringUtils.isNotBlank( imageSource ) )
364         {
365             return genAttError;
366         }
367 
368         return doCheckSize( image, entry, locale );
369     }
370 
371     /**
372      * Do check the size of image
373      * 
374      * @param image
375      * @param entry
376      * @param locale
377      *            The locale
378      * @return The error if any, or null if not erroe
379      */
380     public GenericAttributeError doCheckSize( BufferedImage image, Entry entry, Locale locale )
381     {
382         int nMaxSize = Integer.parseInt( entry.getFieldByCode( FIELD_MAX_SIZE ).getValue( ) );
383 
384         Field imageTypeField = entry.getFieldByCode( FIELD_IMAGE_TYPE );
385         String imageType = imageTypeField != null ? imageTypeField.getValue( ) : "png";
386 
387         // If no max size defined in the db, then fetch the default max size from the
388         // properties file
389         if ( nMaxSize == GenericAttributesUtils.CONSTANT_ID_NULL )
390         {
391             nMaxSize = AppPropertiesService.getPropertyInt( FileAttributesUtils.PROPERTY_UPLOAD_FILE_DEFAULT_MAX_SIZE, 5242880 );
392         }
393 
394         // If nMaxSize == -1, then no size limit
395         if ( ( nMaxSize != GenericAttributesUtils.CONSTANT_ID_NULL ) && ( image != null ) )
396         {
397             boolean bHasFileMaxSizeError = false;
398             ByteArrayOutputStream tmp = new ByteArrayOutputStream( );
399 
400             try
401             {
402                 ImageIO.write( image, imageType, tmp );
403                 tmp.close( );
404             }
405             catch( IOException e )
406             {
407                 AppLogService.error( e );
408 
409                 String strMessage = "IOException when reading Image Size";
410                 GenericAttributeErrortributes/business/GenericAttributeError.html#GenericAttributeError">GenericAttributeError error = new GenericAttributeError( );
411                 error.setMandatoryError( false );
412                 error.setTitleQuestion( entry.getTitle( ) );
413                 error.setErrorMessage( strMessage );
414 
415                 return error;
416             }
417 
418             Integer contentLength = tmp.size( );
419 
420             if ( contentLength > nMaxSize )
421             {
422                 bHasFileMaxSizeError = true;
423             }
424 
425             if ( bHasFileMaxSizeError )
426             {
427                 Object [ ] params = {
428                         nMaxSize
429                 };
430                 String strMessage = I18nService.getLocalizedString( FileAttributesUtils.PROPERTY_MESSAGE_ERROR_UPLOADING_FILE_FILE_MAX_SIZE, params, locale );
431                 GenericAttributeErrortributes/business/GenericAttributeError.html#GenericAttributeError">GenericAttributeError error = new GenericAttributeError( );
432                 error.setMandatoryError( false );
433                 error.setTitleQuestion( entry.getTitle( ) );
434                 error.setErrorMessage( strMessage );
435 
436                 return error;
437             }
438         }
439 
440         return null;
441     }
442 }