DefaultImportAdminUserService.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.portal.service.admin;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import fr.paris.lutece.portal.business.user.AdminUser;
import fr.paris.lutece.portal.business.user.AdminUserHome;
import fr.paris.lutece.portal.business.user.attribute.AdminUserField;
import fr.paris.lutece.portal.business.user.attribute.AdminUserFieldFilter;
import fr.paris.lutece.portal.business.user.attribute.AdminUserFieldHome;
import fr.paris.lutece.portal.business.user.attribute.IAttribute;
import fr.paris.lutece.portal.business.user.attribute.ISimpleValuesAttributes;
import fr.paris.lutece.portal.business.user.authentication.LuteceDefaultAdminUser;
import fr.paris.lutece.portal.business.workgroup.AdminWorkgroupHome;
import fr.paris.lutece.portal.service.csv.CSVMessageDescriptor;
import fr.paris.lutece.portal.service.csv.CSVMessageLevel;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.plugin.Plugin;
import fr.paris.lutece.portal.service.plugin.PluginService;
import fr.paris.lutece.portal.service.spring.SpringContextService;
import fr.paris.lutece.portal.service.user.attribute.AdminUserFieldListenerService;
import fr.paris.lutece.portal.service.user.attribute.AttributeService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPathService;
/**
* Class to import Admin Users from CSV files.
*/
public class DefaultImportAdminUserService extends ImportAdminUserService
{
private static final String CONSTANT_RIGHT = "right";
private static final String CONSTANT_ROLE = "role";
private static final String CONSTANT_WORKGROUP = "workgroup";
private static final String PROPERTY_MESSAGE_EMAIL_SUBJECT_NOTIFY_USER = "portal.users.notify_user.email.subject";
private static final String TEMPLATE_NOTIFY_USER = "admin/user/notify_user_account_created.html";
private static final String MESSAGE_ERROR_IMPORTING_ATTRIBUTES = "portal.users.import_users_from_file.errorImportingAttributes";
private static final String MESSAGE_NO_LEVEL = "portal.users.import_users_from_file.importNoLevel";
private static final String MESSAGE_NO_STATUS = "portal.users.import_users_from_file.importNoStatus";
private static final int CONSTANT_MINIMUM_COLUMNS_PER_LINE = 12;
// Template
private static final String TEMPLATE_DEFAULT_IMPORT_USERS_FROM_FILE = "admin/user/import_users_from_file.html";
private static final AttributeService _attributeService = AttributeService.getInstance( );
/**
* {@inheritDoc}
*/
@Override
protected List<CSVMessageDescriptor> readLineOfCSVFile( String [ ] strLineDataArray, int nLineNumber, Locale locale, String strBaseUrl )
{
List<CSVMessageDescriptor> listMessages = new ArrayList<>( );
int nIndex = 0;
String strAccessCode = strLineDataArray [nIndex++];
String strLastName = strLineDataArray [nIndex++];
String strFirstName = strLineDataArray [nIndex++];
String strEmail = strLineDataArray [nIndex++];
boolean bUpdateUser = getUpdateExistingUsers( );
int nUserId = 0;
if ( bUpdateUser )
{
int nAccessCodeUserId = AdminUserHome.checkAccessCodeAlreadyInUse( strAccessCode );
int nEmailUserId = AdminUserHome.checkEmailAlreadyInUse( strEmail );
if ( nAccessCodeUserId > 0 )
{
nUserId = nAccessCodeUserId;
}
else
if ( nEmailUserId > 0 )
{
nUserId = nEmailUserId;
}
bUpdateUser = nUserId > 0;
}
String strStatus = strLineDataArray [nIndex++];
int nStatus = getStatus( strStatus, strLastName, strFirstName, nLineNumber, listMessages, locale );
String strLocale = strLineDataArray [nIndex++];
String strLevelUser = strLineDataArray [nIndex++];
int nLevelUser = getLevel( strLevelUser, strLastName, strFirstName, nLineNumber, listMessages, locale );
nIndex++;
String strAccessibilityMode = strLineDataArray [nIndex++];
boolean bAccessibilityMode = Boolean.parseBoolean( strAccessibilityMode );
nIndex++;
nIndex++;
AdminUser user = null;
if ( bUpdateUser )
{
user = AdminUserHome.findByPrimaryKey( nUserId );
}
else
{
user = new LuteceDefaultAdminUser( );
}
user.setAccessCode( strAccessCode );
user.setLastName( strLastName );
user.setFirstName( strFirstName );
user.setEmail( strEmail );
user.setStatus( nStatus );
user.setUserLevel( nLevelUser );
user.setLocale( new Locale( strLocale ) );
user.setAccessibilityMode( bAccessibilityMode );
String strDateLastLogin = strLineDataArray [nIndex++];
user = saveOrUpdateUser( user, bUpdateUser, nUserId, strDateLastLogin, strBaseUrl );
// We remove any previous right, roles, workgroup and attributes of the user
AdminUserHome.removeAllRightsForUser( user.getUserId( ) );
AdminUserHome.removeAllRolesForUser( user.getUserId( ) );
AdminUserFieldFilter auFieldFilter = new AdminUserFieldFilter( );
auFieldFilter.setIdUser( user.getUserId( ) );
AdminUserFieldHome.removeByFilter( auFieldFilter );
// We get every attribute, role, right and workgroup of the user
Map<Integer, List<String>> mapAttributesValues = new HashMap<>( );
List<String> listAdminRights = new ArrayList<>( );
List<String> listAdminRoles = new ArrayList<>( );
List<String> listAdminWorkgroups = new ArrayList<>( );
while ( nIndex < strLineDataArray.length )
{
String strValue = strLineDataArray [nIndex];
readAttribute( strValue, listAdminRights, listAdminRoles, listAdminWorkgroups, mapAttributesValues );
nIndex++;
}
// We create rights
for ( String strRight : listAdminRights )
{
AdminUserHome.createRightForUser( user.getUserId( ), strRight );
}
// We create roles
for ( String strRole : listAdminRoles )
{
AdminUserHome.createRoleForUser( user.getUserId( ), strRole );
}
// We create workgroups
for ( String strWorkgoup : listAdminWorkgroups )
{
AdminWorkgroupHome.addUserForWorkgroup( user, strWorkgoup );
}
List<IAttribute> listAttributes = _attributeService.getAllAttributesWithoutFields( locale );
// We save the attributes found
saveAttributes( listAttributes, user, nLineNumber, mapAttributesValues, listMessages, locale );
return listMessages;
}
private int getLevel( String strLevelUser, String strLastName, String strFirstName, int nLineNumber, List<CSVMessageDescriptor> listMessages,
Locale locale )
{
int nLevelUser = 3;
if ( StringUtils.isNotEmpty( strLevelUser ) && StringUtils.isNumeric( strLevelUser ) )
{
nLevelUser = Integer.parseInt( strLevelUser );
}
else
{
Object [ ] args = {
strLastName, strFirstName, nLevelUser
};
String strMessage = I18nService.getLocalizedString( MESSAGE_NO_LEVEL, args, locale );
CSVMessageDescriptor message = new CSVMessageDescriptor( CSVMessageLevel.INFO, nLineNumber, strMessage );
listMessages.add( message );
}
return nLevelUser;
}
private int getStatus( String strStatus, String strLastName, String strFirstName, int nLineNumber, List<CSVMessageDescriptor> listMessages, Locale locale )
{
int nStatus = 0;
if ( StringUtils.isNotEmpty( strStatus ) && StringUtils.isNumeric( strStatus ) )
{
nStatus = Integer.parseInt( strStatus );
}
else
{
Object [ ] args = {
strLastName, strFirstName, nStatus
};
String strMessage = I18nService.getLocalizedString( MESSAGE_NO_STATUS, args, locale );
CSVMessageDescriptor message = new CSVMessageDescriptor( CSVMessageLevel.INFO, nLineNumber, strMessage );
listMessages.add( message );
}
return nStatus;
}
private void readAttribute( String strValue, List<String> listAdminRights, List<String> listAdminRoles, List<String> listAdminWorkgroups,
Map<Integer, List<String>> mapAttributesValues )
{
if ( StringUtils.isBlank( strValue ) )
{
return;
}
int nSeparatorIndex = strValue.indexOf( getAttributesSeparator( ) );
if ( nSeparatorIndex >= 0 )
{
String strLineId = strValue.substring( 0, nSeparatorIndex );
if ( StringUtils.isNotBlank( strLineId ) )
{
if ( StringUtils.equalsIgnoreCase( strLineId, CONSTANT_RIGHT ) )
{
listAdminRights.add( strValue.substring( nSeparatorIndex + 1 ) );
}
else
if ( StringUtils.equalsIgnoreCase( strLineId, CONSTANT_ROLE ) )
{
listAdminRoles.add( strValue.substring( nSeparatorIndex + 1 ) );
}
else
if ( StringUtils.equalsIgnoreCase( strLineId, CONSTANT_WORKGROUP ) )
{
listAdminWorkgroups.add( strValue.substring( nSeparatorIndex + 1 ) );
}
else
{
int nAttributeId = Integer.parseInt( strLineId );
String strAttributeValue = strValue.substring( nSeparatorIndex + 1 );
List<String> listValues = mapAttributesValues.get( nAttributeId );
if ( listValues == null )
{
listValues = new ArrayList<>( );
}
listValues.add( strAttributeValue );
mapAttributesValues.put( nAttributeId, listValues );
}
}
}
}
private void saveAttributes( List<IAttribute> listAttributes, AdminUser user, int nLineNumber, Map<Integer, List<String>> mapAttributesValues,
List<CSVMessageDescriptor> listMessages, Locale locale )
{
listAttributes = listAttributes.stream( ).filter( a -> a instanceof ISimpleValuesAttributes ).collect( Collectors.toList( ) );
for ( IAttribute attribute : listAttributes )
{
List<String> listValues = mapAttributesValues.get( attribute.getIdAttribute( ) );
if ( CollectionUtils.isEmpty( listValues ) )
{
continue;
}
int nIdField = 0;
for ( String strValue : listValues )
{
int nSeparatorIndex = strValue.indexOf( getAttributesSeparator( ) );
if ( nSeparatorIndex >= 0 )
{
nIdField = 0;
try
{
nIdField = Integer.parseInt( strValue.substring( 0, nSeparatorIndex ) );
}
catch( NumberFormatException e )
{
nIdField = 0;
}
strValue = strValue.substring( nSeparatorIndex + 1 );
}
else
{
nIdField = 0;
}
createFields( attribute, user, strValue, nIdField, nLineNumber, listMessages, locale );
}
}
}
private void createFields( IAttribute attribute, AdminUser user, String strValue, int nIdField, int nLineNumber, List<CSVMessageDescriptor> listMessages,
Locale locale )
{
Plugin pluginCore = PluginService.getCore( );
boolean bCoreAttribute = ( attribute.getPlugin( ) == null ) || StringUtils.equals( pluginCore.getName( ), attribute.getPlugin( ).getName( ) );
try
{
List<AdminUserField> listUserFields = ( (ISimpleValuesAttributes) attribute ).getUserFieldsData( new String [ ] {
strValue
}, user );
for ( AdminUserField userField : listUserFields )
{
if ( userField != null )
{
userField.getAttributeField( ).setIdField( nIdField );
AdminUserFieldHome.create( userField );
}
}
if ( !bCoreAttribute )
{
for ( AdminUserFieldListenerService adminUserFieldListenerService : SpringContextService.getBeansOfType( AdminUserFieldListenerService.class ) )
{
adminUserFieldListenerService.doCreateUserFields( user, listUserFields, locale );
}
}
}
catch( Exception e )
{
AppLogService.error( e.getMessage( ), e );
String strErrorMessage = I18nService.getLocalizedString( MESSAGE_ERROR_IMPORTING_ATTRIBUTES, locale );
CSVMessageDescriptor error = new CSVMessageDescriptor( CSVMessageLevel.ERROR, nLineNumber, strErrorMessage );
listMessages.add( error );
}
}
private AdminUser saveOrUpdateUser( AdminUser user, boolean bUpdateUser, int nUserId, String strDateLastLogin, String strBaseUrl )
{
if ( bUpdateUser )
{
user.setUserId( nUserId );
// We update the user
AdminUserHome.update( user );
}
else
{
Timestamp dateLastLogin = getDateLastLogin( strDateLastLogin );
// We create the user
user.setPasswordReset( true );
user.setPasswordMaxValidDate( null );
user.setAccountMaxValidDate( AdminUserService.getAccountMaxValidDate( ) );
user.setDateLastLogin( dateLastLogin );
if ( AdminAuthenticationService.getInstance( ).isDefaultModuleUsed( ) )
{
LuteceDefaultAdminUser defaultAdminUser = (LuteceDefaultAdminUser) user;
String strPassword = AdminUserService.makePassword( );
defaultAdminUser.setPassword( AdminUserService.encryptPassword( strPassword ) );
AdminUserHome.create( defaultAdminUser );
AdminUserService.notifyUser( AppPathService.getProdUrl( strBaseUrl ), user, strPassword, PROPERTY_MESSAGE_EMAIL_SUBJECT_NOTIFY_USER,
TEMPLATE_NOTIFY_USER );
}
else
{
AdminUserHome.create( user );
}
}
return user;
}
private Timestamp getDateLastLogin( String strDateLastLogin )
{
Timestamp dateLastLogin = AdminUser.getDefaultDateLastLogin( );
if ( StringUtils.isNotBlank( strDateLastLogin ) )
{
DateFormat dateFormat = new SimpleDateFormat( );
Date dateParsed;
try
{
dateParsed = dateFormat.parse( strDateLastLogin );
}
catch( ParseException e )
{
AppLogService.error( e.getMessage( ), e );
dateParsed = null;
}
if ( dateParsed != null )
{
dateLastLogin = new Timestamp( dateParsed.getTime( ) );
}
}
return dateLastLogin;
}
/**
* {@inheritDoc}
*/
@Override
public String getImportFromFileTemplate( )
{
return TEMPLATE_DEFAULT_IMPORT_USERS_FROM_FILE;
}
/**
* {@inheritDoc}
*/
@Override
public int getNbMinColumns( )
{
return CONSTANT_MINIMUM_COLUMNS_PER_LINE;
}
/**
* {@inheritDoc}
*/
@Override
public String getAccessCode( String [ ] strLineDataArray )
{
return strLineDataArray [0];
}
/**
* {@inheritDoc}
*/
@Override
public String getEmail( String [ ] strLineDataArray )
{
return strLineDataArray [3];
}
}