View Javadoc
1   package fr.paris.lutece.plugins.atelieraba.web;
2   
3   import java.io.IOException;
4   import java.io.StringWriter;
5   import java.io.UnsupportedEncodingException;
6   import java.util.ArrayList;
7   import java.util.Collection;
8   import java.util.HashMap;
9   import java.util.List;
10  import java.util.Map;
11  import java.util.Map.Entry;
12  import java.util.regex.Pattern;
13  import java.util.stream.Collectors;
14  
15  import javax.servlet.http.HttpServletRequest;
16  
17  import org.apache.commons.lang3.BooleanUtils;
18  
19  import au.com.bytecode.opencsv.CSVWriter;
20  import fr.paris.lutece.plugins.atelieraba.business.AtelierHome;
21  import fr.paris.lutece.plugins.atelieraba.business.Cours;
22  import fr.paris.lutece.plugins.atelieraba.business.CoursHome;
23  import fr.paris.lutece.plugins.atelieraba.business.Inscrit;
24  import fr.paris.lutece.plugins.atelieraba.business.InscritHome;
25  import fr.paris.lutece.plugins.atelieraba.utils.constants.AtelierabaConstants;
26  import fr.paris.lutece.plugins.crmclient.util.CRMException;
27  import fr.paris.lutece.plugins.workflowcore.business.state.State;
28  import fr.paris.lutece.portal.service.i18n.I18nService;
29  import fr.paris.lutece.portal.service.util.AppLogService;
30  import fr.paris.lutece.portal.service.util.AppPropertiesService;
31  import fr.paris.lutece.portal.service.workflow.WorkflowService;
32  import fr.paris.lutece.portal.util.mvc.admin.MVCAdminJspBean;
33  import fr.paris.lutece.portal.util.mvc.admin.annotations.Controller;
34  import fr.paris.lutece.portal.util.mvc.commons.annotations.Action;
35  import fr.paris.lutece.portal.util.mvc.commons.annotations.View;
36  import fr.paris.lutece.portal.web.util.LocalizedPaginator;
37  import fr.paris.lutece.util.html.Paginator;
38  import fr.paris.lutece.util.url.UrlItem;
39  
40  /**
41   * This class provides the user interface to manage Candidatures features ( manage )
42   */
43  @Controller( controllerJsp = "ManageCandidatures.jsp", controllerPath = "jsp/admin/plugins/atelieraba/", right = "ATELIERABA_CANDIDATURES_MANAGEMENT" )
44  public class CandidaturesJspBean extends MVCAdminJspBean
45  {
46      private static final long         serialVersionUID                        = 6200158288322626572L;
47  
48      // Constants
49      private static final String[][]   filter_fields                           = { { "search_nom", "LOWER(i.nom) LIKE ?", "STR_PATTERN" }, { "search_prenom", "LOWER(i.prenom) LIKE ?", "STR_PATTERN" },
50              { "search_naissance", "i.naissance = ?", "DATE" }, { "search_arpege", "i.probable_arpege = ?", "BOOL" }, { "search_discipline_un", "t1.discipline = ?", "STR" },
51              { "search_atelier_un", "t1.titre_atelier = ?", "STR" }, { "search_creneau_un", "t1.creneau = ?", "STR" }, { "search_statut_un", "t1.id_state = ?", "INT" },
52              { "search_discipline_deux", "t2.discipline = ?", "STR" }, { "search_atelier_deux", "t2.titre_atelier = ?", "STR" }, { "search_creneau_deux", "t2.creneau = ?", "STR" },
53              { "search_statut_deux", "t2.id_state = ?", "INT" } };
54  
55      // Views
56      private static final String       VIEW_MANAGE_CANDIDATURES                = "manageCandidatures";
57  
58      // Actions
59      private static final String       ACTION_WORKFLOW                         = "workflow";
60  
61      // JSP
62      private static final String       JSP_MANAGE_CANDIDATS                    = "jsp/admin/plugins/atelieraba/ManageCandidatures.jsp";
63  
64      // Templates
65      private static final String       TEMPLATE_MANAGE_CANDIDATURES            = "/admin/plugins/atelieraba/manage_candidatures.html";
66  
67      // Parameters
68      private static final String       PARAMETER_RESET_SEARCH                  = "reset";
69      private static final String       PARAMETER_EXPORT_CSV                    = "export_csv";
70      private static final String       PARAMETER_PAGE_INDEX                    = "page_index";
71      private static final String       MARK_PAGINATOR                          = "paginator";
72      private static final String       MARK_NB_ITEMS_PER_PAGE                  = "nb_items_per_page";
73      private static final String       PARAMETER_ID_ATELIER                    = "id_atelier";
74      private static final String       PARAMETER_ID_ACTION                     = "id_action";
75  
76      // Properties for page titles
77      private static final String       PROPERTY_PAGE_TITLE_MANAGE_CANDIDATURES = "atelieraba.manage_candidatures.pageTitle";
78      private static final String       PROPERTY_DEFAULT_LIST_CANDIDAT_PER_PAGE = "atelieraba.listCandidats.itemsPerPage";
79      private static final int          PROPERTY_ID_WORKFLOW_1                  = AppPropertiesService.getPropertyInt( AtelierabaConstants.PROPERTY_WORKFLOW_ID,
80              AtelierabaConstants.PROPERTY_ID_WORKFLOW_ATELIER_1 );
81      private static final int          PROPERTY_ID_WORKFLOW_2                  = AppPropertiesService.getPropertyInt( AtelierabaConstants.PROPERTY_WORKFLOW_ID,
82              AtelierabaConstants.PROPERTY_ID_WORKFLOW_ATELIER_2 );
83      private static final String       MARK_COURS_TREE                         = "cours_tree";
84      private static final String       MARK_ALL_DISCIPLINES                    = "all_disciplines";
85      private static final String       MARK_ALL_ATELIERS                       = "all_ateliers";
86      private static final String       MARK_ALL_CRENEAUX                       = "all_creneaux";
87      private static final String       MARK_ALL_STATUTS_WF1                    = "all_statuts_wf1";
88      private static final String       MARK_ALL_STATUTS_WF2                    = "all_statuts_wf2";
89      private static final String       MARK_INSCRIT                            = "inscrit";
90      private static final String       MARK_COURS_1                            = "premier_cours";
91      private static final String       MARK_ATELIER_1                          = "premier_atelier";
92      private static final String       MARK_STATUT_1                           = "statut_premier_atelier";
93      private static final String       MARK_ACTIONS_1                          = "actions_premier_atelier";
94      private static final String       MARK_COURS_2                            = "second_cours";
95      private static final String       MARK_ATELIER_2                          = "second_atelier";
96      private static final String       MARK_STATUT_2                           = "statut_second_atelier";
97      private static final String       MARK_ACTIONS_2                          = "actions_second_atelier";
98      private static final String       MARK_CANDIDATS_LIST                     = "candidats_list";
99  
100     // Variables
101     private HashMap<String[], String> _search_parameters;
102     private int                       _nDefaultItemsPerPage;
103     private String                    _strCurrentPageIndex;
104     private int                       _nItemsPerPage;
105 
106     // Export
107     private static final String       CONSTANT_MIME_TYPE_CSV                  = "application/csv";
108     private static final String       CONSTANT_NOM_CSV                        = "candidatures.csv";
109     private static final String[]     EXPECTEDHEADERS                         = { "atelieraba.manage_candidatures.columnNumero", "atelieraba.manage_candidatures.columnDateInscription",
110             "atelieraba.manage_candidatures.columnArpege", "atelieraba.manage_candidatures.columnNom", "atelieraba.manage_candidatures.columnPrenom", "atelieraba.manage_candidatures.columnNaissance",
111             "atelieraba.manage_candidatures.columnAdresse", "atelieraba.manage_candidatures.columnContactNom", "atelieraba.manage_candidatures.columnContactPrenom",
112             "atelieraba.manage_candidatures.columnContactEmail", "atelieraba.manage_candidatures.columnContactTelephone", "atelieraba.manage_candidatures.columnDecouverte",
113             "atelieraba.manage_candidatures.columnMotivation", "atelieraba.manage_candidatures.columnDemarche", "atelieraba.manage_candidatures.columnSource",
114             "atelieraba.manage_candidatures.columnPremierAtelier", "atelieraba.manage_candidatures.columnPremierStatut", "atelieraba.manage_candidatures.columnSecondAtelier",
115     "atelieraba.manage_candidatures.columnSecondStatut" };
116 
117     /**
118      * Build the Manage View for the search and the listing of Candidats
119      *
120      * @param request
121      *            The HTTP request
122      * @return The Manage View for the search and the listing of Candidats
123      */
124     @View( value = VIEW_MANAGE_CANDIDATURES, defaultView = true )
125     public String getManageCandidatures( HttpServletRequest request )
126     {
127         if ( ( _search_parameters == null ) || ( request.getParameter( PARAMETER_RESET_SEARCH ) != null ) )
128         {
129             _search_parameters = new HashMap<>( );
130             if ( request.getParameter( PARAMETER_RESET_SEARCH ) != null )
131             {
132                 return redirectView( request, VIEW_MANAGE_CANDIDATURES );
133             }
134         }
135 
136         for ( String[] fieldDescription : filter_fields )
137         {
138             String field = fieldDescription[0];
139             String fieldValue = request.getParameter( field );
140             if ( ( fieldValue != null ) )
141             {
142                 if ( fieldValue.isEmpty( ) && _search_parameters.containsKey( fieldDescription ) )
143                 {
144                     _search_parameters.remove( fieldDescription );
145                 } else if ( !fieldValue.isEmpty( ) )
146                 {
147                     _search_parameters.put( fieldDescription, fieldValue );
148                 }
149             }
150         }
151 
152         Collection<Cours> coursList = CoursHome.getCourssList( );
153         Map<String, Map<String, List<Cours>>> coursMap = coursList.stream( ).collect( Collectors.groupingBy( c -> c.getDiscipline( ), Collectors.groupingBy( c -> c.getTitreAtelier( ) ) ) );
154 
155         Map<String, Object> model = getModel( );
156         model.put( MARK_COURS_TREE, coursMap );
157         model.put( MARK_ALL_DISCIPLINES, CoursHome.getDisciplinesList( ) );
158         model.put( MARK_ALL_ATELIERS, CoursHome.getAteliersList( ) );
159         model.put( MARK_ALL_CRENEAUX, CoursHome.getCreneauxList( ) );
160         model.put( MARK_ALL_STATUTS_WF1, WorkflowService.getInstance( ).getAllStateByWorkflow( PROPERTY_ID_WORKFLOW_1, getUser( ) ) );
161         model.put( MARK_ALL_STATUTS_WF2, WorkflowService.getInstance( ).getAllStateByWorkflow( PROPERTY_ID_WORKFLOW_2, getUser( ) ) );
162 
163         HashMap<String[], String> validatedFilters = new HashMap<>( );
164 
165         for ( Entry<String[], String> entry : _search_parameters.entrySet( ) )
166         {
167             String[] fieldDescription = entry.getKey( );
168             String field = fieldDescription[0];
169             String fieldValue = entry.getValue( );
170             model.put( field, fieldValue );
171 
172             if ( "STR_PATTERN".equals( fieldDescription[2] ) || "STR".equals( fieldDescription[2] ) )
173             {
174                 validatedFilters.put( fieldDescription, fieldValue );
175             } else if ( "INT".equals( fieldDescription[2] ) )
176             {
177                 try
178                 {
179                     @SuppressWarnings( "unused" )
180                     int checkIfInt = Integer.parseInt( fieldValue );
181                     validatedFilters.put( fieldDescription, fieldValue );
182                 } catch ( NumberFormatException nfe )
183                 {
184                     AppLogService.error( "ATELIERABA error, bad user input: " + nfe.toString( ) );
185                 }
186             } else if ( "DATE".equals( fieldDescription[2] ) && Pattern.matches( Inscrit.PATTERN_NAISSANCE, fieldValue ) )
187             {
188                 validatedFilters.put( fieldDescription, fieldValue );
189             } else if ( "BOOL".equals( fieldDescription[2] ) )
190             {
191                 validatedFilters.put( fieldDescription, "true".equals( fieldValue ) ? "true" : "false" );
192             }
193         }
194 
195         Map<Integer, Object> mapCours = new HashMap<>( );
196         for ( Cours cours : CoursHome.getCourssList( ) )
197         {
198             Map<String, Integer> placesByCours = new HashMap<>( );
199             placesByCours.put( "places_vivantes", 0 );
200             placesByCours.put( "places_disponibles", cours.getPlacesDisponibles( ) );
201             mapCours.put( cours.getId( ), placesByCours );
202         }
203 
204         List<Map<String, Object>> listCandidats = InscritHome.getInscritsListByFilter( validatedFilters );
205         List<Map<String, Object>> listCandidatsDetailed = new ArrayList<>( );
206 
207         for ( Map<String, Object> candidat : listCandidats )
208         {
209             Map<String, Object> candidatDetailed = new HashMap<>( );
210 
211             Inscrit inscrit = ( Inscrit ) candidat.get( MARK_INSCRIT );
212             Cours cours1 = CoursHome.findByPrimaryKey( ( int ) candidat.get( MARK_COURS_1 ) );
213             State statut1 = WorkflowService.getInstance( ).getState( ( int ) candidat.get( MARK_ATELIER_1 ), AtelierabaConstants.WORKFLOW_RESOURCE_TYPE, PROPERTY_ID_WORKFLOW_1, -1 );
214             Collection<fr.paris.lutece.plugins.workflowcore.business.action.Action> actions1 = WorkflowService.getInstance( ).getActions( ( int ) candidat.get( MARK_ATELIER_1 ),
215                     AtelierabaConstants.WORKFLOW_RESOURCE_TYPE, PROPERTY_ID_WORKFLOW_1, getUser( ) );
216 
217             Map<String, Integer> cours = ( Map<String, Integer> ) mapCours.get( cours1.getId( ) );
218 
219             if ( statut1.getId( ) == 1 ) // Demande reçue (X)
220             {
221                 if ( ( validatedFilters.isEmpty( ) && ( cours.get( "places_vivantes" ) < cours.get( "places_disponibles" ) ) )
222                         || ( !validatedFilters.isEmpty( ) && CoursHome.accesPlacesDisponibles( inscrit.getDateInscription( ), cours1.getId( ) ) ) )
223                 {
224                     actions1.removeIf( action -> action.getId( ) == 18 );
225                 } else
226                 {
227                     List<fr.paris.lutece.plugins.workflowcore.business.action.Action> actionsList = new ArrayList<>( actions1 );
228                     actionsList.removeIf( action -> action.getId( ) == 1 );
229                     actionsList.add( 0, actionsList.remove( actionsList.size( ) - 1 ) );
230                     actions1 = new ArrayList<>( actionsList );
231                 }
232             }
233 
234             if ( ( validatedFilters.isEmpty( ) && ( statut1.getId( ) < 4 ) ) ) // Demande reçue (X) ou confirmée (C) ou en attente (A)
235             {
236                 cours.put( "places_vivantes", cours.get( "places_vivantes" ) + 1 );
237             }
238 
239             candidatDetailed.put( MARK_INSCRIT, inscrit );
240             candidatDetailed.put( MARK_COURS_1, cours1 );
241             candidatDetailed.put( MARK_STATUT_1, statut1 );
242             candidatDetailed.put( MARK_ACTIONS_1, actions1 );
243             candidatDetailed.put( MARK_ATELIER_1, ( int ) candidat.get( MARK_ATELIER_1 ) );
244 
245             Cours cours2 = CoursHome.findByPrimaryKey( ( int ) candidat.get( MARK_COURS_2 ) );
246             if ( cours2 != null )
247             {
248                 State statut2 = WorkflowService.getInstance( ).getState( ( int ) candidat.get( MARK_ATELIER_2 ), AtelierabaConstants.WORKFLOW_RESOURCE_TYPE, PROPERTY_ID_WORKFLOW_2, -1 );
249                 Collection<fr.paris.lutece.plugins.workflowcore.business.action.Action> actions2 = WorkflowService.getInstance( ).getActions( ( int ) candidat.get( MARK_ATELIER_2 ),
250                         AtelierabaConstants.WORKFLOW_RESOURCE_TYPE, PROPERTY_ID_WORKFLOW_2, getUser( ) );
251 
252                 candidatDetailed.put( MARK_COURS_2, cours2 );
253                 candidatDetailed.put( MARK_STATUT_2, statut2 );
254                 candidatDetailed.put( MARK_ACTIONS_2, actions2 );
255                 candidatDetailed.put( MARK_ATELIER_2, ( int ) candidat.get( MARK_ATELIER_2 ) );
256             }
257 
258             listCandidatsDetailed.add( candidatDetailed );
259         }
260 
261         if ( request.getParameter( PARAMETER_EXPORT_CSV ) != null )
262         {
263             downloadCSV( doExport( listCandidatsDetailed ) );
264         }
265 
266         _strCurrentPageIndex = Paginator.getPageIndex( request, Paginator.PARAMETER_PAGE_INDEX, _strCurrentPageIndex );
267         _nDefaultItemsPerPage = AppPropertiesService.getPropertyInt( PROPERTY_DEFAULT_LIST_CANDIDAT_PER_PAGE, 50 );
268         _nItemsPerPage = Paginator.getItemsPerPage( request, Paginator.PARAMETER_ITEMS_PER_PAGE, _nItemsPerPage, _nDefaultItemsPerPage );
269 
270         UrlItem url = new UrlItem( JSP_MANAGE_CANDIDATS );
271         LocalizedPaginator<Map<String, Object>> paginator = new LocalizedPaginator<>( listCandidatsDetailed, _nItemsPerPage, url.getUrl( ), PARAMETER_PAGE_INDEX, _strCurrentPageIndex, getLocale( ) );
272 
273         model.put( MARK_NB_ITEMS_PER_PAGE, "" + _nItemsPerPage );
274         model.put( MARK_PAGINATOR, paginator );
275         model.put( MARK_CANDIDATS_LIST, paginator.getPageItems( ) );
276 
277         return getPage( PROPERTY_PAGE_TITLE_MANAGE_CANDIDATURES, TEMPLATE_MANAGE_CANDIDATURES, model );
278     }
279 
280     /**
281      * Process the action of the workflow
282      *
283      * @param request
284      *            The Http request
285      * @return The Jsp URL of the process result
286      * @throws CRMException
287      */
288     @Action( ACTION_WORKFLOW )
289     public String doWorkflow( HttpServletRequest request )
290     {
291         String strIdAtelier = request.getParameter( PARAMETER_ID_ATELIER );
292         String strIdAction = request.getParameter( PARAMETER_ID_ACTION );
293 
294         if ( ( strIdAtelier != null ) && ( strIdAction != null ) )
295         {
296             int nIdAtelier;
297             int nIdAction;
298 
299             try
300             {
301                 nIdAtelier = Integer.parseInt( strIdAtelier );
302                 nIdAction = Integer.parseInt( strIdAction );
303             } catch ( NumberFormatException nfe )
304             {
305                 return redirectView( request, VIEW_MANAGE_CANDIDATURES );
306             }
307 
308             int idWorkflow = AtelierHome.findByPrimaryKey( nIdAtelier ).getNumeroAtelier( );
309             WorkflowService.getInstance( ).doProcessAction( nIdAtelier, AtelierabaConstants.WORKFLOW_RESOURCE_TYPE, nIdAction, -1, request, getLocale( ), false );
310             WorkflowService.getInstance( ).executeActionAutomatic( nIdAtelier, AtelierabaConstants.WORKFLOW_RESOURCE_TYPE, idWorkflow, -1 );
311         }
312 
313         return redirectView( request, VIEW_MANAGE_CANDIDATURES );
314     }
315 
316     /**
317      * adds a download of the exported list
318      *
319      * @param list
320      *            The list to export
321      * @return the string of the cvs exported file
322      */
323     private String doExport( List<Map<String, Object>> listCandidats )
324     {
325         StringWriter stringwriter = new StringWriter( );
326         String[] localizedHeaders = new String[EXPECTEDHEADERS.length];
327 
328         for ( int i = 0; i < localizedHeaders.length; i++ )
329         {
330             localizedHeaders[i] = I18nService.getLocalizedString( EXPECTEDHEADERS[i], getLocale( ) );
331         }
332 
333         CSVWriter writer = new CSVWriter( stringwriter, ';' );
334         writer.writeNext( localizedHeaders );
335 
336         for ( Map<String, Object> candidat : listCandidats )
337         {
338             String[] entries = new String[EXPECTEDHEADERS.length];
339             Inscrit inscrit = ( Inscrit ) candidat.get( MARK_INSCRIT );
340             Cours premierAtelier = ( Cours ) candidat.get( MARK_COURS_1 );
341             State premierStatut = ( State ) candidat.get( MARK_STATUT_1 );
342             Cours secondAtelier = ( Cours ) candidat.get( MARK_COURS_2 );
343             State secondStatut = ( State ) candidat.get( MARK_STATUT_2 );
344 
345             entries[0] = Integer.toString( inscrit.getId( ) );
346             entries[1] = inscrit.getDateInscription( ).toString( );
347             entries[2] = BooleanUtils.toString( inscrit.getProbableArpege( ), "Oui", "" );
348             entries[3] = inscrit.getNom( );
349             entries[4] = inscrit.getPrenom( );
350             entries[5] = inscrit.getNaissance( ).toString( );
351             entries[6] = inscrit.getAdresseDomicile( );
352             entries[7] = inscrit.getContactNom( );
353             entries[8] = inscrit.getContactPrenom( );
354             entries[9] = inscrit.getContactEmail( );
355             entries[10] = inscrit.getContactTelephone( );
356             entries[11] = inscrit.getDecouverte( );
357             entries[12] = inscrit.getMotivation( );
358             entries[13] = inscrit.getDemarche( );
359             entries[14] = inscrit.getSource( );
360             entries[15] = premierAtelier.getTitreAtelier( ) + " : " + premierAtelier.getCreneau( );
361             entries[16] = premierStatut.getName( );
362             if ( secondAtelier != null )
363             {
364                 entries[17] = secondAtelier.getTitreAtelier( ) + " : " + secondAtelier.getCreneau( );
365                 entries[18] = secondStatut.getName( );
366             } else
367             {
368                 entries[17] = "";
369                 entries[18] = "";
370             }
371 
372             writer.writeNext( entries );
373         }
374 
375         try
376         {
377             writer.close( );
378         } catch ( IOException e )
379         {
380             AppLogService.error( "ATELIERABA: candidats csv export error " + e );
381         }
382 
383         return stringwriter.toString( );
384     }
385 
386     /**
387      * downloadCSV in UTF-8 with BOM for excel
388      *
389      * @param strExport
390      *            the contents of the file
391      */
392     private void downloadCSV( String strExport )
393     {
394         try
395         {
396             byte[] bytesExport;
397             bytesExport = strExport.getBytes( "UTF-8" );
398 
399             byte[] downloadData = new byte[AtelierabaConstants.UTF8_BOM.length + bytesExport.length];
400             System.arraycopy( AtelierabaConstants.UTF8_BOM, 0, downloadData, 0, AtelierabaConstants.UTF8_BOM.length );
401             System.arraycopy( bytesExport, 0, downloadData, AtelierabaConstants.UTF8_BOM.length, bytesExport.length );
402             download( downloadData, CONSTANT_NOM_CSV, CONSTANT_MIME_TYPE_CSV );
403         } catch ( UnsupportedEncodingException e )
404         {
405             AppLogService.error( "Atelieraba error: candidats export csv, error encoding to UTF-8" + e );
406             download( strExport, CONSTANT_NOM_CSV, CONSTANT_MIME_TYPE_CSV );
407         }
408     }
409 
410 }