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.portal.service.admin;
35  
36  import fr.paris.lutece.portal.business.user.AdminUser;
37  import fr.paris.lutece.portal.business.user.AdminUserHome;
38  import fr.paris.lutece.portal.business.user.attribute.AdminUserField;
39  import fr.paris.lutece.portal.business.user.attribute.AdminUserFieldFilter;
40  import fr.paris.lutece.portal.business.user.attribute.AdminUserFieldHome;
41  import fr.paris.lutece.portal.business.user.attribute.IAttribute;
42  import fr.paris.lutece.portal.business.user.attribute.ISimpleValuesAttributes;
43  import fr.paris.lutece.portal.business.user.authentication.LuteceDefaultAdminUser;
44  import fr.paris.lutece.portal.business.workgroup.AdminWorkgroupHome;
45  import fr.paris.lutece.portal.service.csv.CSVMessageDescriptor;
46  import fr.paris.lutece.portal.service.csv.CSVMessageLevel;
47  import fr.paris.lutece.portal.service.csv.CSVReaderService;
48  import fr.paris.lutece.portal.service.i18n.I18nService;
49  import fr.paris.lutece.portal.service.plugin.Plugin;
50  import fr.paris.lutece.portal.service.plugin.PluginService;
51  import fr.paris.lutece.portal.service.spring.SpringContextService;
52  import fr.paris.lutece.portal.service.user.attribute.AdminUserFieldListenerService;
53  import fr.paris.lutece.portal.service.user.attribute.AttributeService;
54  import fr.paris.lutece.portal.service.util.AppLogService;
55  import fr.paris.lutece.portal.service.util.AppPathService;
56  import fr.paris.lutece.portal.service.util.AppPropertiesService;
57  
58  import org.apache.commons.lang.StringUtils;
59  
60  import java.sql.Timestamp;
61  
62  import java.text.DateFormat;
63  import java.text.ParseException;
64  import java.text.SimpleDateFormat;
65  
66  import java.util.ArrayList;
67  import java.util.Date;
68  import java.util.HashMap;
69  import java.util.List;
70  import java.util.Locale;
71  import java.util.Map;
72  
73  
74  /**
75   * Class to import Admin Users from CSV files.
76   */
77  public class ImportAdminUserService extends CSVReaderService
78  {
79      private static final String MESSAGE_NO_LEVEL = "portal.users.import_users_from_file.importNoLevel";
80      private static final String MESSAGE_NO_STATUS = "portal.users.import_users_from_file.importNoStatus";
81      private static final String MESSAGE_ACCESS_CODE_ALREADY_USED = "portal.users.message.user.accessCodeAlreadyUsed";
82      private static final String MESSAGE_EMAIL_ALREADY_USED = "portal.users.message.user.accessEmailUsed";
83      private static final String MESSAGE_USERS_IMPORTED = "portal.users.import_users_from_file.usersImported";
84      private static final String MESSAGE_ERROR_MIN_NUMBER_COLUMNS = "portal.users.import_users_from_file.messageErrorMinColumnNumber";
85      private static final String MESSAGE_ERROR_IMPORTING_ATTRIBUTES = "portal.users.import_users_from_file.errorImportingAttributes";
86      private static final String PROPERTY_IMPORT_EXPORT_USER_SEPARATOR = "lutece.importExportUser.defaultSeparator";
87      private static final String PROPERTY_MESSAGE_EMAIL_SUBJECT_NOTIFY_USER = "portal.users.notify_user.email.subject";
88      private static final String TEMPLATE_NOTIFY_USER = "admin/user/notify_user_account_created.html";
89      private static final String CONSTANT_DEFAULT_IMPORT_EXPORT_USER_SEPARATOR = ":";
90      private static final String CONSTANT_RIGHT = "right";
91      private static final String CONSTANT_ROLE = "role";
92      private static final String CONSTANT_WORKGROUP = "workgroup";
93      private static final int CONSTANT_MINIMUM_COLUMNS_PER_LINE = 12;
94      private static final AttributeService _attributeService = AttributeService.getInstance(  );
95      private Character _strAttributesSeparator;
96      private boolean _bUpdateExistingUsers;
97  
98      /**
99       * {@inheritDoc}
100      */
101     @Override
102     protected List<CSVMessageDescriptor> readLineOfCSVFile( String[] strLineDataArray, int nLineNumber, Locale locale,
103         String strBaseUrl )
104     {
105         List<CSVMessageDescriptor> listMessages = new ArrayList<CSVMessageDescriptor>(  );
106         int nIndex = 0;
107 
108         String strAccessCode = strLineDataArray[nIndex++];
109         String strLastName = strLineDataArray[nIndex++];
110         String strFirstName = strLineDataArray[nIndex++];
111         String strEmail = strLineDataArray[nIndex++];
112 
113         boolean bUpdateUser = getUpdateExistingUsers(  );
114         int nUserId = 0;
115 
116         if ( bUpdateUser )
117         {
118             int nAccessCodeUserId = AdminUserHome.checkAccessCodeAlreadyInUse( strAccessCode );
119             int nEmailUserId = AdminUserHome.checkEmailAlreadyInUse( strEmail );
120 
121             if ( nAccessCodeUserId > 0 )
122             {
123                 nUserId = nAccessCodeUserId;
124             }
125             else if ( nEmailUserId > 0 )
126             {
127                 nUserId = nEmailUserId;
128             }
129 
130             bUpdateUser = nUserId > 0;
131         }
132 
133         String strStatus = strLineDataArray[nIndex++];
134         int nStatus = 0;
135 
136         if ( StringUtils.isNotEmpty( strStatus ) && StringUtils.isNumeric( strStatus ) )
137         {
138             nStatus = Integer.parseInt( strStatus );
139         }
140         else
141         {
142             Object[] args = { strLastName, strFirstName, nStatus };
143             String strMessage = I18nService.getLocalizedString( MESSAGE_NO_STATUS, args, locale );
144             CSVMessageDescriptor message = new CSVMessageDescriptor( CSVMessageLevel.INFO, nLineNumber, strMessage );
145             listMessages.add( message );
146         }
147 
148         String strLocale = strLineDataArray[nIndex++];
149         String strLevelUser = strLineDataArray[nIndex++];
150         int nLevelUser = 3;
151 
152         if ( StringUtils.isNotEmpty( strLevelUser ) && StringUtils.isNumeric( strLevelUser ) )
153         {
154             nLevelUser = Integer.parseInt( strLevelUser );
155         }
156         else
157         {
158             Object[] args = { strLastName, strFirstName, nLevelUser };
159             String strMessage = I18nService.getLocalizedString( MESSAGE_NO_LEVEL, args, locale );
160             CSVMessageDescriptor message = new CSVMessageDescriptor( CSVMessageLevel.INFO, nLineNumber, strMessage );
161             listMessages.add( message );
162         }
163 
164         // We ignore the reset password attribute because we set it to true anyway.
165         // String strResetPassword = strLineDataArray[nIndex++];
166         nIndex++;
167 
168         boolean bResetPassword = true;
169         String strAccessibilityMode = strLineDataArray[nIndex++];
170         boolean bAccessibilityMode = Boolean.parseBoolean( strAccessibilityMode );
171         // We ignore the password max valid date attribute because we changed the password.
172         // String strPasswordMaxValidDate = strLineDataArray[nIndex++];
173         nIndex++;
174 
175         Timestamp passwordMaxValidDate = null;
176         // We ignore the account max valid date attribute
177         // String strAccountMaxValidDate = strLineDataArray[nIndex++];
178         nIndex++;
179 
180         Timestamp accountMaxValidDate = AdminUserService.getAccountMaxValidDate(  );
181         String strDateLastLogin = strLineDataArray[nIndex++];
182         Timestamp dateLastLogin = new Timestamp( AdminUser.DEFAULT_DATE_LAST_LOGIN.getTime(  ) );
183 
184         if ( StringUtils.isNotBlank( strDateLastLogin ) )
185         {
186             DateFormat dateFormat = new SimpleDateFormat(  );
187             Date dateParsed;
188 
189             try
190             {
191                 dateParsed = dateFormat.parse( strDateLastLogin );
192             }
193             catch ( ParseException e )
194             {
195                 AppLogService.error( e.getMessage(  ), e );
196                 dateParsed = null;
197             }
198 
199             if ( dateParsed != null )
200             {
201                 dateLastLogin = new Timestamp( dateParsed.getTime(  ) );
202             }
203         }
204 
205         AdminUser user = null;
206 
207         if ( bUpdateUser )
208         {
209             user = AdminUserHome.findByPrimaryKey( nUserId );
210         }
211         else
212         {
213             user = new LuteceDefaultAdminUser(  );
214         }
215 
216         user.setAccessCode( strAccessCode );
217         user.setLastName( strLastName );
218         user.setFirstName( strFirstName );
219         user.setEmail( strEmail );
220         user.setStatus( nStatus );
221         user.setUserLevel( nLevelUser );
222         user.setLocale( new Locale( strLocale ) );
223         user.setAccessibilityMode( bAccessibilityMode );
224 
225         if ( bUpdateUser )
226         {
227             user.setUserId( nUserId );
228             // We update the user
229             AdminUserHome.update( user );
230         }
231         else
232         {
233             // We create the user
234             user.setPasswordReset( bResetPassword );
235             user.setPasswordMaxValidDate( passwordMaxValidDate );
236             user.setAccountMaxValidDate( accountMaxValidDate );
237             user.setDateLastLogin( dateLastLogin );
238 
239             if ( AdminAuthenticationService.getInstance(  ).isDefaultModuleUsed(  ) )
240             {
241                 LuteceDefaultAdminUser defaultAdminUser = (LuteceDefaultAdminUser) user;
242                 String strPassword = AdminUserService.makePassword(  );
243                 defaultAdminUser.setPassword( AdminUserService.encryptPassword( strPassword ) );
244                 AdminUserHome.create( defaultAdminUser );
245                 AdminUserService.notifyUser( AppPathService.getProdUrl( strBaseUrl ), user,
246                         strPassword, PROPERTY_MESSAGE_EMAIL_SUBJECT_NOTIFY_USER, TEMPLATE_NOTIFY_USER );
247             }
248             else
249             {
250                 AdminUserHome.create( user );
251             }
252         }
253 
254         // We remove any previous right, roles, workgroup and attributes of the user
255         AdminUserHome.removeAllRightsForUser( user.getUserId(  ) );
256         AdminUserHome.removeAllRolesForUser( user.getUserId(  ) );
257 
258         AdminUserFieldFilter auFieldFilter = new AdminUserFieldFilter(  );
259         auFieldFilter.setIdUser( user.getUserId(  ) );
260         AdminUserFieldHome.removeByFilter( auFieldFilter );
261 
262         // We get every attribute, role, right and workgroup of the user
263         Map<Integer, List<String>> mapAttributesValues = new HashMap<Integer, List<String>>(  );
264         List<String> listAdminRights = new ArrayList<String>(  );
265         List<String> listAdminRoles = new ArrayList<String>(  );
266         List<String> listAdminWorkgroups = new ArrayList<String>(  );
267 
268         while ( nIndex < strLineDataArray.length )
269         {
270             String strValue = strLineDataArray[nIndex];
271 
272             if ( StringUtils.isNotBlank( strValue ) && ( strValue.indexOf( getAttributesSeparator(  ) ) > 0 ) )
273             {
274                 int nSeparatorIndex = strValue.indexOf( getAttributesSeparator(  ) );
275                 String strLineId = strValue.substring( 0, nSeparatorIndex );
276 
277                 if ( StringUtils.isNotBlank( strLineId ) )
278                 {
279                     if ( StringUtils.equalsIgnoreCase( strLineId, CONSTANT_RIGHT ) )
280                     {
281                         listAdminRights.add( strValue.substring( nSeparatorIndex + 1 ) );
282                     }
283                     else if ( StringUtils.equalsIgnoreCase( strLineId, CONSTANT_ROLE ) )
284                     {
285                         listAdminRoles.add( strValue.substring( nSeparatorIndex + 1 ) );
286                     }
287                     else if ( StringUtils.equalsIgnoreCase( strLineId, CONSTANT_WORKGROUP ) )
288                     {
289                         listAdminWorkgroups.add( strValue.substring( nSeparatorIndex + 1 ) );
290                     }
291                     else
292                     {
293                         int nAttributeId = Integer.parseInt( strLineId );
294 
295                         String strAttributeValue = strValue.substring( nSeparatorIndex + 1 );
296                         List<String> listValues = mapAttributesValues.get( nAttributeId );
297 
298                         if ( listValues == null )
299                         {
300                             listValues = new ArrayList<String>(  );
301                         }
302 
303                         listValues.add( strAttributeValue );
304                         mapAttributesValues.put( nAttributeId, listValues );
305                     }
306                 }
307             }
308 
309             nIndex++;
310         }
311 
312         // We create rights
313         for ( String strRight : listAdminRights )
314         {
315             AdminUserHome.createRightForUser( user.getUserId(  ), strRight );
316         }
317 
318         // We create roles
319         for ( String strRole : listAdminRoles )
320         {
321             AdminUserHome.createRoleForUser( user.getUserId(  ), strRole );
322         }
323 
324         // We create workgroups
325         for ( String strWorkgoup : listAdminWorkgroups )
326         {
327             AdminWorkgroupHome.addUserForWorkgroup( user, strWorkgoup );
328         }
329 
330         List<IAttribute> listAttributes = _attributeService.getAllAttributesWithoutFields( locale );
331         Plugin pluginCore = PluginService.getCore(  );
332 
333         // We save the attributes found
334         for ( IAttribute attribute : listAttributes )
335         {
336             if ( attribute instanceof ISimpleValuesAttributes )
337             {
338                 List<String> listValues = mapAttributesValues.get( attribute.getIdAttribute(  ) );
339 
340                 if ( ( listValues != null ) && ( listValues.size(  ) > 0 ) )
341                 {
342                     int nIdField = 0;
343                     boolean bCoreAttribute = ( attribute.getPlugin(  ) == null ) ||
344                         StringUtils.equals( pluginCore.getName(  ), attribute.getPlugin(  ).getName(  ) );
345 
346                     for ( String strValue : listValues )
347                     {
348                         int nSeparatorIndex = strValue.indexOf( getAttributesSeparator(  ) );
349 
350                         if ( nSeparatorIndex >= 0 )
351                         {
352                             nIdField = 0;
353 
354                             try
355                             {
356                                 nIdField = Integer.parseInt( strValue.substring( 0, nSeparatorIndex ) );
357                             }
358                             catch ( NumberFormatException e )
359                             {
360                                 nIdField = 0;
361                             }
362 
363                             strValue = strValue.substring( nSeparatorIndex + 1 );
364                         }
365                         else
366                         {
367                             nIdField = 0;
368                         }
369 
370                         String[] strValues = { strValue };
371 
372                         try
373                         {
374                             List<AdminUserField> listUserFields = ( (ISimpleValuesAttributes) attribute ).getUserFieldsData( strValues,
375                                     user );
376 
377                             for ( AdminUserField userField : listUserFields )
378                             {
379                                 if ( userField != null )
380                                 {
381                                     userField.getAttributeField(  ).setIdField( nIdField );
382                                     AdminUserFieldHome.create( userField );
383                                 }
384                             }
385 
386                             if ( !bCoreAttribute )
387                             {
388                                 for ( AdminUserFieldListenerService adminUserFieldListenerService : SpringContextService.getBeansOfType( 
389                                         AdminUserFieldListenerService.class ) )
390                                 {
391                                     adminUserFieldListenerService.doCreateUserFields( user, listUserFields, locale );
392                                 }
393                             }
394                         }
395                         catch ( Exception e )
396                         {
397                             AppLogService.error( e.getMessage(  ), e );
398 
399                             String strErrorMessage = I18nService.getLocalizedString( MESSAGE_ERROR_IMPORTING_ATTRIBUTES,
400                                     locale );
401                             CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber,
402                                     strErrorMessage );
403                             listMessages.add( error );
404                         }
405                     }
406                 }
407             }
408         }
409 
410         return listMessages;
411     }
412 
413     /**
414      * {@inheritDoc}
415      */
416     @Override
417     protected List<CSVMessageDescriptor> checkLineOfCSVFile( String[] strLineDataArray, int nLineNumber, Locale locale )
418     {
419         int nMinColumnNumber = CONSTANT_MINIMUM_COLUMNS_PER_LINE;
420         List<CSVMessageDescriptor> listMessages = new ArrayList<CSVMessageDescriptor>(  );
421 
422         if ( ( strLineDataArray == null ) || ( strLineDataArray.length < nMinColumnNumber ) )
423         {
424             int nNbCol;
425 
426             if ( strLineDataArray == null )
427             {
428                 nNbCol = 0;
429             }
430             else
431             {
432                 nNbCol = strLineDataArray.length;
433             }
434 
435             Object[] args = { nNbCol, nMinColumnNumber };
436             String strErrorMessage = I18nService.getLocalizedString( MESSAGE_ERROR_MIN_NUMBER_COLUMNS, args, locale );
437             CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber, strErrorMessage );
438             listMessages.add( error );
439 
440             return listMessages;
441         }
442 
443         if ( !getUpdateExistingUsers(  ) )
444         {
445             String strAccessCode = strLineDataArray[0];
446             String strEmail = strLineDataArray[3];
447 
448             if ( AdminUserHome.checkAccessCodeAlreadyInUse( strAccessCode ) > 0 )
449             {
450                 String strMessage = I18nService.getLocalizedString( MESSAGE_ACCESS_CODE_ALREADY_USED, locale );
451                 CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber, strMessage );
452                 listMessages.add( error );
453             }
454             else
455             {
456                 if ( AdminUserHome.checkEmailAlreadyInUse( strEmail ) > 0 )
457                 {
458                     String strMessage = I18nService.getLocalizedString( MESSAGE_EMAIL_ALREADY_USED, locale );
459                     CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber,
460                             strMessage );
461                     listMessages.add( error );
462                 }
463             }
464         }
465 
466         return listMessages;
467     }
468 
469     /**
470      * {@inheritDoc}
471      */
472     @Override
473     protected List<CSVMessageDescriptor> getEndOfProcessMessages( int nNbLineParses, int nNbLinesWithoutErrors,
474         Locale locale )
475     {
476         List<CSVMessageDescriptor> listMessages = new ArrayList<CSVMessageDescriptor>(  );
477         Object[] args = { nNbLineParses, nNbLinesWithoutErrors };
478         String strMessageContent = I18nService.getLocalizedString( MESSAGE_USERS_IMPORTED, args, locale );
479         CSVMessageDescriptor message = new CSVMessageDescriptor( CSVMessageLevel.INFO, 0, strMessageContent );
480         listMessages.add( message );
481 
482         return listMessages;
483     }
484 
485     /**
486      * Get the separator used for attributes of admin users.
487      * @return The separator
488      */
489     public Character getAttributesSeparator(  )
490     {
491         if ( _strAttributesSeparator == null )
492         {
493             _strAttributesSeparator = AppPropertiesService.getProperty( PROPERTY_IMPORT_EXPORT_USER_SEPARATOR,
494                     CONSTANT_DEFAULT_IMPORT_EXPORT_USER_SEPARATOR ).charAt( 0 );
495         }
496 
497         return _strAttributesSeparator;
498     }
499 
500     /**
501      * Get the update users flag
502      * @return True if existing users should be updated, false if they should be
503      *         ignored.
504      */
505     public boolean getUpdateExistingUsers(  )
506     {
507         return _bUpdateExistingUsers;
508     }
509 
510     /**
511      * Set the update users flag
512      * @param bUpdateExistingUsers True if existing users should be updated,
513      *            false if they should be ignored.
514      */
515     public void setUpdateExistingUsers( boolean bUpdateExistingUsers )
516     {
517         _bUpdateExistingUsers = bUpdateExistingUsers;
518     }
519 }