View Javadoc

1   /*
2    * Copyright (c) 2002-2014, Mairie de 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.formengine.web;
35  
36  import fr.paris.lutece.plugins.formengine.service.FormsRegistrationService;
37  import fr.paris.lutece.plugins.formengine.util.JSONUtils;
38  import fr.paris.lutece.portal.service.i18n.I18nService;
39  import fr.paris.lutece.portal.service.message.SiteMessageException;
40  import fr.paris.lutece.portal.service.plugin.Plugin;
41  import fr.paris.lutece.portal.service.security.UserNotSignedException;
42  import fr.paris.lutece.portal.service.template.AppTemplateService;
43  import fr.paris.lutece.portal.service.util.AppHTTPSService;
44  import fr.paris.lutece.portal.service.util.AppPathService;
45  import fr.paris.lutece.portal.service.util.AppPropertiesService;
46  import fr.paris.lutece.portal.web.PortalJspBean;
47  import fr.paris.lutece.portal.web.xpages.XPage;
48  import fr.paris.lutece.portal.web.xpages.XPageApplication;
49  import fr.paris.lutece.util.html.HtmlTemplate;
50  
51  import net.sf.json.JSON;
52  import net.sf.json.JSONArray;
53  import net.sf.json.JSONObject;
54  import net.sf.json.JSONSerializer;
55  
56  import org.apache.commons.lang.ArrayUtils;
57  import org.apache.commons.lang.StringUtils;
58  
59  import java.util.Arrays;
60  import java.util.Enumeration;
61  
62  import javax.servlet.http.HttpServletRequest;
63  import javax.servlet.http.HttpSession;
64  
65  
66  /**
67   * Form Engine XPage Application
68   *
69   */
70  public class FormEngineApp implements XPageApplication
71  {
72      // CONSTANTS
73      private static final String SLASH = "/";
74  
75      // PARAMETERS
76      private static final String PARAMETER_PAGE = "page";
77      private static final String PARAMETER_FORM_NAME = "form";
78      private static final String PARAMETER_SUBFORM_NAME = "subform";
79      private static final String PARAMETER_ACTION_NAME = "action";
80      private static final String PARAMETER_PORTAL_URI = "portalURI";
81      private static final String PARAMETER_FIELD_NAME = "field_name";
82      private static final String PARAMETER_FIELD_INDEX = "field_index";
83  
84      // PROPERTY
85      private static final String PROPERTY_MESSAGE_SESSION_LOST = "formengine.session.lost";
86      private static final String PROPERTY_MESSAGE_ERROR_REMOVING_FILE = "formengine.message.error.removingFile";
87  
88      // TEMPLATES
89      private static final String TEMPLATE_ACCESS_ERROR = "/skin/plugins/formengine/access_error.html";
90  
91      /**
92       * Get the xpage that display the form contents
93       * @param request the http request
94       * @param nMode The mode
95       * @param plugin The plugin
96       * @return the xpage for the forms
97       * @throws UserNotSignedException If an authentication is required and the user is not signed
98       * @throws SiteMessageException If an error occurs
99       */
100     public XPage getPage( HttpServletRequest request, int nMode, Plugin plugin )
101         throws UserNotSignedException, SiteMessageException
102     {
103         XPage page = new XPage(  );
104 
105         // Set the upload filter site next url
106         PortalJspBean.setUploadFilterSiteNextUrl( request );
107 
108         // retrieve the parameters
109         String strFormName = request.getParameter( PARAMETER_FORM_NAME );
110         String strSubFormName = request.getParameter( PARAMETER_SUBFORM_NAME );
111 
112         // get the form from its name
113         Form form = FormsRegistrationService.getForm( strFormName );
114 
115         if ( ( form == null ) || form.isClosed( request.getLocale(  ) ) )
116         {
117             // if the form is not found, display an error message
118             page.setContent( this.getAccessErrorMessage(  ) );
119 
120             return page;
121         }
122 
123         SubForm subForm = getSubForm( request, form, strSubFormName );
124 
125         if ( form.preprocessRequest( request ) )
126         {
127             return page;
128         }
129 
130         if ( subForm == null )
131         {
132             // if no subform was found, display an error
133             page.setContent( this.getAccessErrorMessage(  ) );
134 
135             return page;
136         }
137 
138         // don't forget to allow access to the first subform
139         if ( subForm.getPreviousSubForm(  ) == null )
140         {
141             // grant access to the first subform
142             subForm.setIsSubFormAllowed( request, true );
143         }
144 
145         // display result
146         page.setContent( subForm.display( request ) );
147         page.setTitle( form.getTitle(  ) );
148         page.setPathLabel( form.getTitle(  ) + " - " + subForm.getTitle(  ) );
149 
150         // reset errors
151         form.resetErrors( request );
152 
153         // if we are at the last subform, clean the session
154         if ( subForm.getNextSubForm(  ) == null )
155         {
156             form.validateDraft( request, form );
157             form.flushSession( request );
158         }
159 
160         return page;
161     }
162 
163     /**
164      * Set the display URL of a form depending on the given subform name
165      * @param request the http request - gives the plugin name and the form name
166      * @param strSubFormName the name of the subform to display
167      * @return the url to display the given subform
168      */
169     public static String setUrl( HttpServletRequest request, String strSubFormName )
170     {
171         String strUrl = null;
172         String strPluginName = SharedConstants.PLUGIN_NAME;
173         String strFormName = request.getParameter( PARAMETER_FORM_NAME );
174         String strFormPortalUrl = request.getParameter( PARAMETER_PORTAL_URI );
175 
176         // get the form from the name in request
177         Form form = FormsRegistrationService.getForm( strFormName );
178 
179         if ( form != null )
180         {
181             strFormPortalUrl = strFormPortalUrl.replaceFirst( request.getContextPath(  ) + SLASH, "" );
182 
183             String strBaseURL;
184 
185             if ( AppHTTPSService.isHTTPSSupportEnabled(  ) )
186             {
187                 HttpSession session = request.getSession(  );
188 
189                 if ( session != null )
190                 {
191                     session.setAttribute( AppPathService.SESSION_BASE_URL, AppPathService.getBaseUrl( request ) );
192                 }
193 
194                 strBaseURL = AppHTTPSService.getHTTPSUrl( request );
195             }
196             else
197             {
198                 strBaseURL = AppPathService.getBaseUrl( request );
199             }
200 
201             strUrl = strBaseURL + strFormPortalUrl + "?" + PARAMETER_PAGE + "=" + strPluginName + "&" +
202                 PARAMETER_FORM_NAME + "=" + strFormName;
203 
204             // if session is not lost
205             if ( request.isRequestedSessionIdValid(  ) )
206             {
207                 strUrl = strUrl + "&" + PARAMETER_SUBFORM_NAME + "=" + strSubFormName;
208             }
209         }
210 
211         return strUrl;
212     }
213 
214     public String getUploadedFiles( HttpServletRequest request )
215     {
216         String strFormName = request.getParameter( PARAMETER_FORM_NAME );
217         String strSubFormName = request.getParameter( PARAMETER_SUBFORM_NAME );
218         String strFieldName = request.getParameter( PARAMETER_FIELD_NAME );
219 
220         if ( StringUtils.isBlank( strFormName ) || StringUtils.isBlank( strFieldName ) )
221         {
222             return buildJsonErrorRemovingFile( request ).toString(  );
223         }
224 
225         // find the subform
226         Form form = FormsRegistrationService.getForm( strFormName );
227 
228         if ( form == null )
229         {
230             return buildJsonErrorRemovingFile( request ).toString(  );
231         }
232 
233         SubForm subForm = null;
234 
235         if ( StringUtils.isNotBlank( strSubFormName ) )
236         {
237             subForm = form.getSubForm( strSubFormName );
238         }
239 
240         if ( subForm == null )
241         {
242             // if upload is in first subform, no subform parameter available
243             subForm = form.getFirstSubForm(  );
244         }
245 
246         // merge asynchronous uploaded file with already uploaded files before deleting
247         FormErrorsList listErrors = new FormErrorsList(  );
248         subForm.mergeAsynchronousUploadedFiles( request, strFieldName, listErrors );
249 
250         JSONObject json = JSONUtils.getUploadedFileJSON( subForm.getFileItems( request, strFieldName ) );
251 
252         // Add errors
253         for ( String strMessage : listErrors )
254         {
255             json.accumulate( JSONUtils.JSON_KEY_ERROR_MESSAGES, strMessage );
256         }
257 
258         // we have to clear error list to prevent user from refreshing page
259         form.resetErrors( request );
260 
261         // add field name
262         json.element( JSONUtils.JSON_KEY_FIELD, strFieldName );
263 
264         return json.toString(  );
265     }
266 
267     /**
268      * Remove an asynchronous uploaded file.
269      * @param request the request
270      * @return
271      */
272     public String doRemoveAsynchronousUploadedFile( HttpServletRequest request )
273     {
274         // get the request parameters
275         String strFormName = request.getParameter( PARAMETER_FORM_NAME );
276         String strSubFormName = request.getParameter( PARAMETER_SUBFORM_NAME );
277         String strFieldName = request.getParameter( PARAMETER_FIELD_NAME );
278         String strFieldIndex = request.getParameter( PARAMETER_FIELD_INDEX );
279 
280         if ( StringUtils.isBlank( strFormName ) || StringUtils.isBlank( strFieldName ) ||
281                 StringUtils.isBlank( strFieldIndex ) )
282         {
283             return buildJsonErrorRemovingFile( request ).toString(  );
284         }
285 
286         // find the subform
287         Form form = FormsRegistrationService.getForm( strFormName );
288 
289         if ( form == null )
290         {
291             return buildJsonErrorRemovingFile( request ).toString(  );
292         }
293 
294         SubForm subForm = null;
295 
296         if ( StringUtils.isNotBlank( strSubFormName ) )
297         {
298             subForm = form.getSubForm( strSubFormName );
299         }
300 
301         if ( subForm == null )
302         {
303             // if upload is in first subform, no subform parameter available
304             subForm = form.getFirstSubForm(  );
305         }
306 
307         // parse json
308         JSON jsonFieldIndexes = JSONSerializer.toJSON( strFieldIndex );
309 
310         if ( !jsonFieldIndexes.isArray(  ) )
311         {
312             return buildJsonErrorRemovingFile( request ).toString(  );
313         }
314 
315         JSONArray jsonArrayFieldIndexers = (JSONArray) jsonFieldIndexes;
316 
317         int[] tabFieldIndex = new int[jsonArrayFieldIndexers.size(  )];
318 
319         for ( int nIndex = 0; nIndex < jsonArrayFieldIndexers.size(  ); nIndex++ )
320         {
321             try
322             {
323                 tabFieldIndex[nIndex] = Integer.parseInt( jsonArrayFieldIndexers.getString( nIndex ) );
324             }
325             catch ( NumberFormatException nfe )
326             {
327                 return buildJsonErrorRemovingFile( request ).toString(  );
328             }
329         }
330 
331         // merge asynchronous uploaded file with already uploaded files before deleting
332         subForm.mergeAsynchronousUploadedFiles( request, strFieldName );
333 
334         // inverse order (removing using index - remove greater first to keep order)
335         Arrays.sort( tabFieldIndex );
336         ArrayUtils.reverse( tabFieldIndex );
337 
338         JSONObject json = new JSONObject(  );
339 
340         for ( int nFieldIndex : tabFieldIndex )
341         {
342             subForm.removeUploadedFileItem( request, strFieldName, nFieldIndex );
343         }
344 
345         // add field name
346         json.element( JSONUtils.JSON_KEY_FIELD, strFieldName );
347         // operation successful
348         json.element( JSONUtils.JSON_KEY_SUCCESS, JSONUtils.JSON_KEY_SUCCESS );
349         json.accumulateAll( JSONUtils.getUploadedFileJSON( subForm.getFileItems( request, strFieldName ) ) );
350 
351         return json.toString(  );
352     }
353 
354     /**
355      * Builds a json object with the error message.
356      * @param request the request
357      * @return the json object.
358      */
359     private JSONObject buildJsonErrorRemovingFile( HttpServletRequest request )
360     {
361         JSONObject json = new JSONObject(  );
362 
363         json.element( JSONUtils.JSON_KEY_ERROR,
364             I18nService.getLocalizedString( PROPERTY_MESSAGE_ERROR_REMOVING_FILE, request.getLocale(  ) ) );
365 
366         return json;
367     }
368 
369     /**
370      * Perform an action on a given subform
371      * @param request the http request - gives the form, subform and action name
372      * @return the name of the subform to display after having performed the requested action
373      */
374     public String doAction( HttpServletRequest request )
375     {
376         // get the request parameters
377         String strFormName = request.getParameter( PARAMETER_FORM_NAME );
378         String strSubFormName = request.getParameter( PARAMETER_SUBFORM_NAME );
379         String strActionName = request.getParameter( PARAMETER_ACTION_NAME );
380 
381         // default next subform (in case of error) is current subform
382         String strNextSubForm = strSubFormName;
383 
384         // get the form from its name
385         Form form = FormsRegistrationService.getForm( strFormName );
386 
387         // If session is lost
388         if ( !request.isRequestedSessionIdValid(  ) )
389         {
390             form.addErrorMessage( request, AppPropertiesService.getProperty( PROPERTY_MESSAGE_SESSION_LOST ) );
391 
392             return strSubFormName;
393         }
394 
395         // Special case for upload fields : if no action is specified, a submit
396         // button associated with an upload might have been pressed :
397         if ( strActionName == null )
398         {
399             String strUploadAction = getUploadAction( request );
400 
401             if ( strUploadAction != null )
402             {
403                 return form.getSubForm( strSubFormName ).doUploadAction( request, strUploadAction );
404             }
405         }
406 
407         SubForm subForm = null;
408 
409         if ( form != null ) // if we have a form corresponding to the name
410         {
411             // get the subform from its name
412             subForm = form.getSubForm( strSubFormName );
413 
414             if ( subForm != null ) // if we have a subform corresponding to the name
415             {
416                 if ( subForm.getIsSubFormAllowed( request ) )
417                 {
418                     // perform the action
419                     strNextSubForm = subForm.doAction( strActionName, request );
420                     // save draft
421                     form.saveDraft( request );
422                 }
423             }
424         }
425 
426         return strNextSubForm;
427     }
428 
429     /**
430      * Get the error message from its template
431      * @return the html code for an error
432      */
433     private String getAccessErrorMessage(  )
434     {
435         HtmlTemplate templateNotFound = AppTemplateService.getTemplate( TEMPLATE_ACCESS_ERROR );
436 
437         return templateNotFound.getHtml(  );
438     }
439 
440     /**
441      * Checks the request parameters to see if an upload submit has been
442      * called.
443      *
444      * @param request the HTTP request
445      * @return the name of the upload action, if any. Null otherwise.
446      */
447     private static String getUploadAction( HttpServletRequest request )
448     {
449         Enumeration enumParamNames = request.getParameterNames(  );
450 
451         while ( enumParamNames.hasMoreElements(  ) )
452         {
453             String paramName = (String) enumParamNames.nextElement(  );
454 
455             if ( paramName.startsWith( SharedConstants.UPLOAD_SUBMIT_PREFIX ) ||
456                     paramName.startsWith( SharedConstants.UPLOAD_DELETE_PREFIX ) )
457             {
458                 return paramName;
459             }
460         }
461 
462         return null;
463     }
464 
465     /**
466      * Get the subform corresponding to the request
467      * @param request The HTTP request
468      * @param form The form
469      * @param strSubFormName The subform name
470      * @return The subform
471      */
472     private SubForm getSubForm( HttpServletRequest request, Form form, String strSubFormName )
473     {
474         SubForm subForm = null;
475 
476         if ( ( strSubFormName == null ) || ( strSubFormName.trim(  ).equals( "" ) ) )
477         {
478             // if no subform name was stated, choose the first subform
479             subForm = form.getFirstSubForm(  );
480             form.flushSession( request );
481         }
482         else
483         {
484             // else retrieve the subform from its name
485             subForm = form.getSubForm( strSubFormName );
486         }
487 
488         return subForm;
489     }
490 }