AlertService.java
/*
* Copyright (c) 2002-2021, 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.plugins.workflow.modules.alertforms.service;
import fr.paris.lutece.plugins.forms.business.FormHome;
import fr.paris.lutece.plugins.forms.business.FormQuestionResponse;
import fr.paris.lutece.plugins.forms.business.FormQuestionResponseHome;
import fr.paris.lutece.plugins.forms.business.FormResponse;
import fr.paris.lutece.plugins.forms.business.FormResponseHome;
import fr.paris.lutece.plugins.forms.business.Question;
import fr.paris.lutece.plugins.forms.business.QuestionHome;
import fr.paris.lutece.plugins.forms.util.FormsConstants;
import fr.paris.lutece.plugins.workflow.modules.alertforms.business.Alert;
import fr.paris.lutece.plugins.workflow.modules.alertforms.business.IAlertDAO;
import fr.paris.lutece.plugins.workflow.modules.alertforms.business.TaskAlertConfig;
import fr.paris.lutece.plugins.workflow.modules.alertforms.util.constants.AlertConstants;
import fr.paris.lutece.plugins.workflow.utils.WorkflowUtils;
import fr.paris.lutece.plugins.workflowcore.business.action.Action;
import fr.paris.lutece.plugins.workflowcore.business.resource.ResourceHistory;
import fr.paris.lutece.plugins.workflowcore.business.resource.ResourceWorkflow;
import fr.paris.lutece.plugins.workflowcore.business.state.State;
import fr.paris.lutece.plugins.workflowcore.business.state.StateFilter;
import fr.paris.lutece.plugins.workflowcore.service.action.IActionService;
import fr.paris.lutece.plugins.workflowcore.service.config.ITaskConfigService;
import fr.paris.lutece.plugins.workflowcore.service.resource.IResourceHistoryService;
import fr.paris.lutece.plugins.workflowcore.service.resource.IResourceWorkflowService;
import fr.paris.lutece.plugins.workflowcore.service.state.IStateService;
import fr.paris.lutece.plugins.workflowcore.service.task.ITask;
import fr.paris.lutece.plugins.workflowcore.service.task.ITaskService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.plugin.PluginService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.portal.service.workflow.WorkflowService;
import fr.paris.lutece.util.ReferenceList;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Named;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
/**
*
* AlertService
*
*/
public final class AlertService implements IAlertService
{
public static final String BEAN_SERVICE = "workflow-alertforms.alertService";
private List<Integer> _listAcceptedEntryTypesDate;
@Inject
private ITaskService _taskService;
@Inject
private IStateService _stateService;
@Inject
private IResourceWorkflowService _resourceWorkflowService;
@Inject
private IResourceHistoryService _resourceHistoryService;
@Inject
private IActionService _actionService;
@Inject
@Named( AlertConstants.BEAN_ALERT_CONFIG_SERVICE )
private ITaskConfigService _taskAlertConfigService;
@Inject
private IAlertDAO _alertDAO;
/**
* Private constructor
*/
private AlertService( )
{
// Init list accepted entry types for date
_listAcceptedEntryTypesDate = fillListEntryTypes( AlertConstants.PROPERTY_ACCEPTED_FORM_ENTRY_TYPES_DATE );
}
// CRUD
/**
* {@inheritDoc}
*/
@Override
@Transactional( AlertPlugin.BEAN_TRANSACTION_MANAGER )
public void create( Alert alert )
{
if ( alert != null )
{
_alertDAO.insert( alert, PluginService.getPlugin( AlertPlugin.PLUGIN_NAME ) );
}
}
/**
* {@inheritDoc}
*/
@Override
@Transactional( AlertPlugin.BEAN_TRANSACTION_MANAGER )
public void desactivateByHistory( int nIdResourceHistory, int nIdTask, boolean executed )
{
_alertDAO.desactivateByHistory( nIdResourceHistory, nIdTask, executed, PluginService.getPlugin( AlertPlugin.PLUGIN_NAME ) );
}
/**
* {@inheritDoc}
*/
@Override
@Transactional( AlertPlugin.BEAN_TRANSACTION_MANAGER )
public void desactivateByTask( int nIdTask )
{
_alertDAO.desactivateByTask( nIdTask, PluginService.getPlugin( AlertPlugin.PLUGIN_NAME ) );
}
/**
* {@inheritDoc}
*/
@Override
public Alert find( int nIdResourceHistory, int nIdTask )
{
return _alertDAO.load( nIdResourceHistory, nIdTask, PluginService.getPlugin( AlertPlugin.PLUGIN_NAME ) );
}
/**
* {@inheritDoc}
*/
@Override
public List<Alert> findAllActive( )
{
return _alertDAO.selectAllActive( PluginService.getPlugin( AlertPlugin.PLUGIN_NAME ) );
}
// CHECKS
/**
* {@inheritDoc}
*/
@Override
public boolean isEntryTypeDateAccepted( int nIdEntryType )
{
boolean bIsAccepted = false;
if ( ( _listAcceptedEntryTypesDate != null ) && !_listAcceptedEntryTypesDate.isEmpty( ) )
{
bIsAccepted = _listAcceptedEntryTypesDate.contains( nIdEntryType );
}
return bIsAccepted;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isFormResponseStateValid( TaskAlertConfig config, FormResponse formResponse, Locale locale )
{
boolean bIsValid = false;
ITask task = _taskService.findByPrimaryKey( config.getIdTask( ), locale );
if ( task != null )
{
Action action = _actionService.findByPrimaryKey( task.getAction( ).getId( ) );
if ( ( action != null ) && ( action.getStateAfter( ) != null ) )
{
ResourceWorkflow resourceWorkflow = _resourceWorkflowService.findByPrimaryKey( formResponse.getId( ), FormResponse.RESOURCE_TYPE,
action.getWorkflow( ).getId( ) );
if ( ( resourceWorkflow != null ) && ( resourceWorkflow.getState( ) != null )
&& ( resourceWorkflow.getState( ).getId( ) == action.getStateAfter( ).getId( ) ) )
{
bIsValid = true;
}
}
}
return bIsValid;
}
// GET
/**
* {@inheritDoc}
*/
@Override
public List<Question> getListQuestions( int nIdTask )
{
TaskAlertConfig config = _taskAlertConfigService.findByPrimaryKey( nIdTask );
List<Question> listQuestions = new ArrayList<>( );
if ( config != null )
{
listQuestions = QuestionHome.getListQuestionByIdForm( config.getIdForm( ) );
}
return listQuestions;
}
/**
* {@inheritDoc}
*/
@Override
public ReferenceList getListQuestionsDate( int nIdTask, Locale locale )
{
ReferenceList refenreceListEntries = new ReferenceList( );
refenreceListEntries.addItem( FormsConstants.DEFAULT_ID_VALUE, StringUtils.EMPTY );
for ( Question question : getListQuestions( nIdTask ) )
{
int nIdEntryType = question.getEntry( ).getEntryType( ).getIdType( );
/*
* LUT-27425 If the date is set as optional in a form, then do not display this field when configuring an automatic alert task
* */
if ( isEntryTypeDateAccepted( nIdEntryType ) && question.getEntry().isMandatory() )
{
refenreceListEntries.addItem( question.getId( ), buildReferenceEntryToString( question ) );
}
}
return refenreceListEntries;
}
/**
* {@inheritDoc}
*/
@Override
public ReferenceList getListForms( )
{
ReferenceList listForms = FormHome.getFormsReferenceList( );
ReferenceList refenreceListForms = new ReferenceList( );
refenreceListForms.addItem( FormsConstants.DEFAULT_ID_VALUE, StringUtils.EMPTY );
if ( listForms != null )
{
refenreceListForms.addAll( listForms );
}
return refenreceListForms;
}
/**
* {@inheritDoc}
*/
@Override
public ReferenceList getListStates( int nIdAction )
{
ReferenceList referenceListStates = new ReferenceList( );
Action action = _actionService.findByPrimaryKey( nIdAction );
if ( ( action != null ) && ( action.getWorkflow( ) != null ) )
{
StateFilter stateFilter = new StateFilter( );
stateFilter.setIdWorkflow( action.getWorkflow( ).getId( ) );
List<State> listStates = _stateService.getListStateByFilter( stateFilter );
referenceListStates.addItem( FormsConstants.DEFAULT_ID_VALUE, StringUtils.EMPTY );
referenceListStates.addAll( ReferenceList.convert( listStates, AlertConstants.ID, AlertConstants.NAME, true ) );
}
return referenceListStates;
}
/**
* {@inheritDoc}
*/
@Override
public FormResponse getFormResponse( Alert alert )
{
FormResponse formresponse = null;
if ( alert != null )
{
ResourceHistory resourceHistory = _resourceHistoryService.findByPrimaryKey( alert.getIdResourceHistory( ) );
if ( ( resourceHistory != null ) && FormResponse.RESOURCE_TYPE.equals( resourceHistory.getResourceType( ) ) )
{
formresponse = FormResponseHome.findByPrimaryKey( resourceHistory.getIdResource( ) );
}
}
return formresponse;
}
/**
* {@inheritDoc}
*/
@Override
public long getDate( TaskAlertConfig config, int nIdFormResponse, int nIdForm )
{
long lDate = 0;
if ( config != null )
{
List<FormQuestionResponse> listFormQuestionResponses = FormQuestionResponseHome.findFormQuestionResponseByResponseQuestion( nIdFormResponse,
config.getIdQuestionDate( ) );
if ( CollectionUtils.isNotEmpty( listFormQuestionResponses ) )
{
FormQuestionResponse formQuestionResponse = listFormQuestionResponses.get( 0 );
String strDate = formQuestionResponse.getEntryResponse( ).get( 0 ).getResponseValue( );
try
{
Date dDate = new Date(Long.parseLong(strDate));
return dDate.getTime( );
}
catch( Exception e )
{
AppLogService.error( "Unable to parse given date", e );
}
}
}
return lDate;
}
// ACTIONS
/**
* {@inheritDoc}
*/
@Override
public void doChangeFormResponseState( TaskAlertConfig config, int nIdFormResponse, Alert alert )
{
// The locale is not important. It is just used to fetch the task action id
Locale locale = I18nService.getDefaultLocale( );
ITask task = _taskService.findByPrimaryKey( config.getIdTask( ), locale );
if ( task != null )
{
State state = _stateService.findByPrimaryKey( config.getIdStateAfterDeadline( ) );
Action action = _actionService.findByPrimaryKey( task.getAction( ).getId( ) );
if ( ( state != null ) && ( action != null ) )
{
// Create Resource History
ResourceHistory resourceHistory = new ResourceHistory( );
resourceHistory.setIdResource( nIdFormResponse );
resourceHistory.setResourceType( FormResponse.RESOURCE_TYPE );
resourceHistory.setAction( action );
resourceHistory.setWorkFlow( action.getWorkflow( ) );
resourceHistory.setCreationDate( WorkflowUtils.getCurrentTimestamp( ) );
resourceHistory.setUserAccessCode( AlertConstants.USER_AUTO );
_resourceHistoryService.create( resourceHistory );
// Update Resource
ResourceWorkflow resourceWorkflow = _resourceWorkflowService.findByPrimaryKey( nIdFormResponse, FormResponse.RESOURCE_TYPE,
action.getWorkflow( ).getId( ) );
resourceWorkflow.setState( state );
_resourceWorkflowService.update( resourceWorkflow );
// If the new state has automatic reflexive actions
WorkflowService.getInstance( ).doProcessAutomaticReflexiveActions( nIdFormResponse, FormResponse.RESOURCE_TYPE, state.getId( ),
resourceWorkflow.getExternalParentId( ), locale, null );
// if new state has action automatic
WorkflowService.getInstance( ).executeActionAutomatic( nIdFormResponse, FormResponse.RESOURCE_TYPE, action.getWorkflow( ).getId( ),
resourceWorkflow.getExternalParentId( ), null );
// Remove the Alert
desactivateByHistory( alert.getIdResourceHistory( ), alert.getIdTask( ), true );
}
}
}
// PRIVATE METHODS
/**
* Build the reference entry into String
*
* @param entry
* the entry
* @param locale
* the Locale
* @return the reference entry
*/
private String buildReferenceEntryToString( Question question )
{
StringBuilder sbReferenceEntry = new StringBuilder( );
sbReferenceEntry.append( question.getId( ) );
sbReferenceEntry.append( AlertConstants.SPACE + AlertConstants.OPEN_BRACKET );
sbReferenceEntry.append( question.getTitle( ) );
sbReferenceEntry.append( AlertConstants.SPACE + AlertConstants.HYPHEN + AlertConstants.SPACE );
sbReferenceEntry.append( question.getEntry( ).getEntryType( ).getTitle( ) );
sbReferenceEntry.append( AlertConstants.CLOSED_BRACKET );
return sbReferenceEntry.toString( );
}
/**
* Fill the list of entry types
*
* @param strPropertyEntryTypes
* the property containing the entry types
* @return a list of integer
*/
private static List<Integer> fillListEntryTypes( String strPropertyEntryTypes )
{
List<Integer> listEntryTypes = new ArrayList<>( );
String strEntryTypes = AppPropertiesService.getProperty( strPropertyEntryTypes );
if ( StringUtils.isNotBlank( strEntryTypes ) )
{
String [ ] listAcceptEntryTypesForIdDemand = strEntryTypes.split( AlertConstants.COMMA );
for ( String strAcceptEntryType : listAcceptEntryTypesForIdDemand )
{
if ( StringUtils.isNotBlank( strAcceptEntryType ) && StringUtils.isNumeric( strAcceptEntryType ) )
{
int nAcceptedEntryType = Integer.parseInt( strAcceptEntryType );
listEntryTypes.add( nAcceptedEntryType );
}
}
}
return listEntryTypes;
}
@Override
public void deleteByHistory( int nIdResourceHistory, int nIdTask )
{
_alertDAO.deleteByHistory( nIdResourceHistory, nIdTask, PluginService.getPlugin( AlertPlugin.PLUGIN_NAME ) );
}
}