ProposalJspBean.java
/*
* Copyright (c) 2002-2020, 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.participatoryideation.web;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import fr.paris.lutece.plugins.leaflet.business.GeolocItem;
import fr.paris.lutece.plugins.participatoryideation.business.capgeo.QpvQva;
import fr.paris.lutece.plugins.participatoryideation.business.proposal.Proposal;
import fr.paris.lutece.plugins.participatoryideation.business.proposal.ProposalHome;
import fr.paris.lutece.plugins.participatoryideation.business.proposal.ProposalSearcher;
import fr.paris.lutece.plugins.participatoryideation.service.IdeationErrorException;
import fr.paris.lutece.plugins.participatoryideation.service.IdeationStaticService;
import fr.paris.lutece.plugins.participatoryideation.service.ProposalService;
import fr.paris.lutece.plugins.participatoryideation.service.ProposalUsersService;
import fr.paris.lutece.plugins.participatoryideation.service.SolrProposalIndexer;
import fr.paris.lutece.plugins.participatoryideation.service.campaign.IdeationCampaignDataProvider;
import fr.paris.lutece.plugins.participatoryideation.service.capgeo.QpvQvaService;
import fr.paris.lutece.plugins.participatoryideation.util.CsvUtils;
import fr.paris.lutece.plugins.participatoryideation.util.ParticipatoryIdeationConstants;
import fr.paris.lutece.plugins.participatoryideation.util.ProposalExportUtils;
import fr.paris.lutece.plugins.workflowcore.business.state.State;
import fr.paris.lutece.portal.business.file.File;
import fr.paris.lutece.portal.service.admin.AccessDeniedException;
import fr.paris.lutece.portal.service.admin.AdminUserService;
import fr.paris.lutece.portal.service.message.AdminMessage;
import fr.paris.lutece.portal.service.message.AdminMessageService;
import fr.paris.lutece.portal.service.spring.SpringContextService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPathService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.portal.service.workflow.WorkflowService;
import fr.paris.lutece.portal.util.mvc.admin.annotations.Controller;
import fr.paris.lutece.portal.util.mvc.commons.annotations.Action;
import fr.paris.lutece.portal.util.mvc.commons.annotations.View;
/**
* This class provides the user interface to manage Proposal features ( manage, create, modify, remove )
*/
@Controller( controllerJsp = "ManageProposals.jsp", controllerPath = "jsp/admin/plugins/participatoryideation/", right = "PARTICIPATORYIDEATION_PROPOSALS_MANAGEMENT" )
public class ProposalJspBean extends ManageIdeationProposalsJspBean
{
// //////////////////////////////////////////////////////////////////////////
// ParticipatoryIdeationConstants
// templates
private static final String TEMPLATE_MANAGE_PROPOSALS = "/admin/plugins/participatoryideation/manage_proposals.html";
private static final String TEMPLATE_INIT_PROPOSAL = "/admin/plugins/participatoryideation/init_proposal.html";
private static final String TEMPLATE_COMPLETE_PROPOSAL = "/admin/plugins/participatoryideation/complete_proposal.html";
private static final String TEMPLATE_MODIFY_PROPOSAL = "/admin/plugins/participatoryideation/modify_proposal.html";
private static final String TEMPLATE_CONFIRM_REMOVE_PROPOSAL = "/admin/plugins/participatoryideation/confirm_remove_proposal.html";
// Parameters
private static final String PARAMETER_CAMPAIGN_CODE = "campaign_code";
private static final String PARAMETER_ID_PROPOSAL = "id";
private static final String PARAMETER_ID_ACTION = "id_action";
private static final String PARAMETER_ID_RESOURCE = "id_resource";
private static final String PARAMETER_FILTER_CODE_CAMPAIGN = "filter_code_campaign";
private static final String PARAMETER_FILTER_CODE_THEME = "filter_code_theme";
private static final String PARAMETER_FILTER_TITRE_OU_DESCRIPTION = "filter_titre_ou_description";
private static final String PARAMETER_FILTER_PUBLIC_STATE = "filter_status";
private static final String PARAMETER_FILTER_QPVQVA = "filter_qpvqva";
private static final String PARAMETER_FILTER_FIELD4 = "filter_field4";
private static final String PARAMETER_FILTER_TYPE_LOCATION = "filter_type_location";
private static final String PARAMETER_FILTER_AREA = "filter_arrondissement";
private static final String PARAMETER_SORT_COLUMN = "sort_column";
private static final String PARAMETER_SORT_ORDER = "sort_order";
private static final String PARAMETER_MOTIFRECEV = "motifRecev";
private static final String PARAMETER_PLUGIN_NAME = "plugin_name";
// Properties for page titles
private static final String PROPERTY_PAGE_TITLE_MANAGE_PROPOSALS = "participatoryideation.manage_proposals.pageTitle";
private static final String PROPERTY_PAGE_TITLE_CREATE_PROPOSAL = "participatoryideation.create_proposal.pageTitle";
private static final String PROPERTY_PAGE_TITLE_MODIFY_PROPOSAL = "participatoryideation.modify_proposal.pageTitle";
private static final String PROPERTY_PAGE_TITLE_CONFIRM_REMOVE_PROPOSAL = "participatoryideation.confirm_remove_proposal.pageTitle";
// Markers
private static final String MARK_CAMPAIGN_CODE = "campaign_code";
private static final String MARK_CAMPAIGN_LIST = "campaign_list";
private static final String MARK_CAMPAIGNTHEME_LIST = "campaigntheme_list";
private static final String MARK_FIELD4_LIST = "field4_list";
private static final String MARK_PROPOSAL_LIST = "proposal_list";
private static final String MARK_PROPOSAL = "proposal";
private static final String MARK_PROPOSAL_BO_FORM = "proposal_bo_form";
private static final String MARK_FILTER_CODE_CAMPAIGN = "filter_code_campaign";
private static final String MARK_FILTER_CODE_THEME = "filter_code_theme";
private static final String MARK_FILTER_TITRE_OU_DESCRIPTION = "filter_titre_ou_description";
private static final String MARK_FILTER_QPVQVA = "filter_qpvqva";
private static final String MARK_FILTER_FIELD4 = "filter_field4";
private static final String MARK_FILTER_TYPE_LOCATION = "filter_type_location";
private static final String MARK_FILTER_ARRONDISSEMENT = "filter_arrondissement";
private static final String MARK_LANGUAGE = "language";
private static final String MARK_LOCATION_TYPE_LIST = "type_location_list";
private static final String MARK_AREA_LIST = "area_list";
private static final String MARK_SORT_COLUMN = "sort_column";
private static final String MARK_SORT_ORDER = "sort_order";
private static final String MARK_WORKFLOW_STATE_MAP = "workflow_state_map"; // Workflow state of each proposal. Key = id of proposal.
private static final String MARK_WORKFLOW_ACTIONS_MAP = "workflow_actions_map"; // Workflow actions of each proposal. Key = id of proposal.
private static final String MARK_RESOURCE_HISTORY = "workflow_history";
private static final String JSP_MANAGE_PROPOSALS = "jsp/admin/plugins/participatoryideation/ManageProposals.jsp";
// Properties
private static final String MESSAGE_ERROR_PROPOSAL_REMOVED = "participatoryideation.message.error.proposal.removed";
private static final String MESSAGE_ERROR_CAMPAIGN_NOT_SPECIFIED = "participatoryideation.message.error.campaign.notSpecified";
private static final String MESSAGE_ERROR_ARRONDISSEMENT_EMPTY = "participatoryideation.validation.proposal.Arrondissement.notEmpty";
private static final String MESSAGE_ERROR_ADDRESS_FORMAT = "participatoryideation.validation.proposal.Address.Format";
private static final String MESSAGE_ERROR_ADDRESS_LOCATION_TYPE_EMPTY = "participatoryideation.validation.proposal.LocationType.NotEmpty";
private static final String MESSAGE_ERROR_PROPOSAL_NO_SUCH_WORKFLOW_ACTION = "participatoryideation.message.error.workflow.noSuchAction";
private static final String MESSAGE_ERROR_PROPOSAL_NO_SUCH_WORKFLOW_RESOURCE = "participatoryideation.message.error.workflow.noSuchResource";
private static final String VALIDATION_ATTRIBUTES_PREFIX = "participatoryideation.model.entity.proposal.attribute.";
private static final String PROPERTY_CSV_EXTENSION = "participatoryideation.csv.extension";
private static final String PROPERTY_CSV_FILE_NAME = "participatoryideation.csv.file.name";
// Views
private static final String VIEW_MANAGE_PROPOSALS = "manageProposals";
private static final String VIEW_INIT_PROPOSAL = "initProposal";
private static final String VIEW_COMPLETE_PROPOSAL = "completeProposal";
private static final String VIEW_MODIFY_PROPOSAL = "modifyProposal";
private static final String VIEW_CONFIRM_REMOVE_PROPOSAL = "confirmRemoveProposal";
// Actions
private static final String ACTION_CREATE_PROPOSAL = "createProposal";
private static final String ACTION_MODIFY_PROPOSAL = "modifyProposal";
private static final String ACTION_SEARCH_PROPOSAL = "searchProposal";
private static final String ACTION_CANCEL_SEARCH = "cancelSearch";
private static final String ACTION_CONFIRM_REMOVE_PROPOSAL = "confirmRemoveProposal";
private static final String ACTION_PROCESS_WORKFLOW_ACTION = "processWorkflowAction";
// Infos
private static final String INFO_PROPOSAL_CREATED = "participatoryideation.info.proposal.created";
private static final String INFO_PROPOSAL_UPDATED = "participatoryideation.info.proposal.updated";
private static final String INFO_PROPOSAL_REMOVED = "participatoryideation.info.proposal.removed";
private static SolrProposalIndexer _solrProposalIndexer = SpringContextService.getBean( "participatoryideation.solrProposalIndexer" );
// Workflow
private static final String WORKFLOW_ID_DEFAULT = "100";
private static final String WORKFLOW_ID = AppPropertiesService.getProperty( ParticipatoryIdeationConstants.PROPERTY_WORKFLOW_ID, WORKFLOW_ID_DEFAULT );
// Session variable to store working values
private ProposalBoForm _proposalBoForm;
private Proposal _proposal;
private ProposalSearcher _proposalSearcher;
private static ProposalSearcher defaultSearcher;
static
{
defaultSearcher = new ProposalSearcher( );
defaultSearcher.setOrderAscDesc( ProposalSearcher.ORDER_DESC );
defaultSearcher.setOrderColumn( ProposalSearcher.COLUMN_REFERENCE );
}
// ***********************************************************************************
// * MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MA *
// * MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MANAGE MA *
// ***********************************************************************************
/**
* Build the Manage View
*
* @param request
* The HTTP request
* @return The page
*/
@View( value = VIEW_MANAGE_PROPOSALS, defaultView = true )
public String getManageProposals( HttpServletRequest request )
{
_proposal = null;
_proposalBoForm = null;
ProposalSearcher currentSearcher = _proposalSearcher != null ? _proposalSearcher : defaultSearcher;
List<Proposal> listProposals = (List<Proposal>) ProposalHome.getProposalsListSearch( currentSearcher );
Map<String, Object> model = getPaginatedListModel( request, MARK_PROPOSAL_LIST, listProposals, JSP_MANAGE_PROPOSALS );
if ( _proposalSearcher != null )
{
if ( StringUtils.isNotBlank( _proposalSearcher.getCodeCampaign( ) ) )
{
model.put( MARK_FILTER_CODE_CAMPAIGN, _proposalSearcher.getCodeCampaign( ) );
}
if ( StringUtils.isNotBlank( _proposalSearcher.getCodeTheme( ) ) )
{
model.put( MARK_FILTER_CODE_THEME, _proposalSearcher.getCodeTheme( ) );
}
if ( StringUtils.isNotBlank( _proposalSearcher.getTitreOuDescriptionouRef( ) ) )
{
model.put( MARK_FILTER_TITRE_OU_DESCRIPTION, _proposalSearcher.getTitreOuDescriptionouRef( ) );
}
if ( _proposalSearcher.getStatusPublic( ) != null )
{
model.put( PARAMETER_FILTER_PUBLIC_STATE, _proposalSearcher.getStatusPublic( ) );
}
if ( StringUtils.isNotBlank( _proposalSearcher.getTypeQpvQva( ) ) )
{
model.put( MARK_FILTER_QPVQVA, _proposalSearcher.getTypeQpvQva( ) );
}
if ( StringUtils.isNotBlank( _proposalSearcher.getField4( ) ) )
{
model.put( MARK_FILTER_FIELD4, _proposalSearcher.getField4( ) );
}
if ( StringUtils.isNotBlank( _proposalSearcher.getTypeLocation( ) ) )
{
model.put( MARK_FILTER_TYPE_LOCATION, _proposalSearcher.getTypeLocation( ) );
}
if ( StringUtils.isNotBlank( _proposalSearcher.getArrondissement( ) ) )
{
model.put( MARK_FILTER_ARRONDISSEMENT, _proposalSearcher.getArrondissement( ) );
}
if ( StringUtils.isNotBlank( _proposalSearcher.getOrderColumn( ) ) )
{
model.put( MARK_SORT_COLUMN, _proposalSearcher.getOrderColumn( ) );
}
if ( StringUtils.isNotBlank( _proposalSearcher.getOrderAscDesc( ) ) )
{
model.put( MARK_SORT_ORDER, _proposalSearcher.getOrderAscDesc( ) );
}
}
IdeationStaticService.getInstance( ).fillAllStaticContent( model );
// Add workflow informations for each proposal
if ( WorkflowService.getInstance( ).isAvailable( ) )
{
// Identify workflow id
int workflowId = -1;
try
{
workflowId = Integer.parseInt( WORKFLOW_ID );
}
catch( NumberFormatException e )
{
workflowId = Integer.parseInt( WORKFLOW_ID_DEFAULT );
AppLogService.error( "No such ideation workflow id : #" + WORKFLOW_ID + ", so using #100 by default.", e );
}
// Add data
Map<String, State> stateMap = new HashMap<>( );
Map<String, Collection<fr.paris.lutece.plugins.workflowcore.business.action.Action>> actionsMap = new HashMap<>( );
for ( Proposal proposal : listProposals )
{
stateMap.put( "" + proposal.getId( ),
WorkflowService.getInstance( ).getState( proposal.getId( ), Proposal.WORKFLOW_RESOURCE_TYPE, workflowId, -1 ) );
actionsMap.put( "" + proposal.getId( ),
WorkflowService.getInstance( ).getActions( proposal.getId( ), Proposal.WORKFLOW_RESOURCE_TYPE, workflowId, getUser( ) ) );
}
model.put( MARK_WORKFLOW_STATE_MAP, stateMap );
model.put( MARK_WORKFLOW_ACTIONS_MAP, actionsMap );
}
return getPage( PROPERTY_PAGE_TITLE_MANAGE_PROPOSALS, TEMPLATE_MANAGE_PROPOSALS, model );
}
// ***********************************************************************************
// * SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SE *
// * SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SEARCH SE *
// ***********************************************************************************
/**
* Process the search filters/sorts
*
* @param request
* The HTTP request
* @return The page
*/
@Action( value = ACTION_SEARCH_PROPOSAL )
public String doSearchProposal( HttpServletRequest request )
{
if ( _proposalSearcher == null )
{
_proposalSearcher = new ProposalSearcher( );
}
String strCodeCampaign = request.getParameter( PARAMETER_FILTER_CODE_CAMPAIGN );
if ( strCodeCampaign != null )
{
if ( StringUtils.isBlank( strCodeCampaign ) )
{
_proposalSearcher.setCodeCampaign( null );
}
else
{
_proposalSearcher.setCodeCampaign( strCodeCampaign );
}
}
String strCodeTheme = request.getParameter( PARAMETER_FILTER_CODE_THEME );
if ( strCodeTheme != null )
{
if ( StringUtils.isBlank( strCodeTheme ) )
{
_proposalSearcher.setCodeTheme( null );
}
else
{
_proposalSearcher.setCodeTheme( strCodeTheme );
}
}
String strTitre = request.getParameter( PARAMETER_FILTER_TITRE_OU_DESCRIPTION );
if ( strTitre != null )
{
if ( StringUtils.isBlank( strTitre ) )
{
_proposalSearcher.setTitreOuDescriptionouRef( null );
}
else
{
_proposalSearcher.setTitreOuDescriptionouRef( strTitre );
}
}
String strPublicState = request.getParameter( PARAMETER_FILTER_PUBLIC_STATE );
if ( strPublicState != null )
{
if ( StringUtils.isBlank( strPublicState ) )
{
_proposalSearcher.setStatusPublic( null );
}
else
{
_proposalSearcher.setStatusPublic( strPublicState );
}
}
String strTypeQpvQva = request.getParameter( PARAMETER_FILTER_QPVQVA );
if ( strTypeQpvQva != null )
{
if ( StringUtils.isBlank( strTypeQpvQva ) )
{
_proposalSearcher.setTypeQpvQva( null );
}
else
{
_proposalSearcher.setTypeQpvQva( strTypeQpvQva );
}
}
String strField4 = request.getParameter( PARAMETER_FILTER_FIELD4 );
if ( strField4 != null )
{
if ( StringUtils.isBlank( strField4 ) )
{
_proposalSearcher.setField4( null );
}
else
{
_proposalSearcher.setField4( strField4 );
}
}
String strTypeLocation = request.getParameter( PARAMETER_FILTER_TYPE_LOCATION );
if ( strTypeLocation != null )
{
if ( StringUtils.isBlank( strTypeLocation ) )
{
_proposalSearcher.setTypeLocation( null );
}
else
{
_proposalSearcher.setTypeLocation( strTypeLocation );
}
}
String strArrondissement = request.getParameter( PARAMETER_FILTER_AREA );
if ( strArrondissement != null )
{
if ( StringUtils.isBlank( strArrondissement ) )
{
_proposalSearcher.setArrondissement( null );
}
else
{
_proposalSearcher.setArrondissement( strArrondissement );
}
}
String strSortColumn = request.getParameter( PARAMETER_SORT_COLUMN );
if ( strSortColumn != null )
{
if ( StringUtils.isBlank( strSortColumn ) )
{
_proposalSearcher.setOrderColumn( null );
}
else
{
_proposalSearcher.setOrderColumn( strSortColumn );
}
}
String strSortAscDesc = request.getParameter( PARAMETER_SORT_ORDER );
if ( strSortAscDesc != null )
{
if ( StringUtils.isBlank( strSortAscDesc ) )
{
_proposalSearcher.setOrderAscDesc( null );
}
else
{
_proposalSearcher.setOrderAscDesc( strSortAscDesc );
}
}
return redirectView( request, VIEW_MANAGE_PROPOSALS );
}
/**
* Reset the search
*
* @param request
* The HTTP request
* @return The page
*/
@Action( value = ACTION_CANCEL_SEARCH )
public String doCancelSearch( HttpServletRequest request )
{
_proposalSearcher = null;
return redirectView( request, VIEW_MANAGE_PROPOSALS );
}
// ***********************************************************************************
// * CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE CR *
// * CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE CREATE CR *
// ***********************************************************************************
// * First step : initialize the proposal by specifying the campaign *
// * Second step : complete other data *
// ***********************************************************************************
@View( VIEW_INIT_PROPOSAL )
public String getInitProposal( HttpServletRequest request )
{
_proposal = new Proposal( );
Map<String, Object> model = getModel( );
model.put( MARK_CAMPAIGN_LIST, IdeationCampaignDataProvider.getInstance( ).getCampaigns( ) );
model.put( MARK_PROPOSAL, _proposal );
model.put( MARK_LANGUAGE, getLocale( ) );
return getPage( PROPERTY_PAGE_TITLE_CREATE_PROPOSAL, TEMPLATE_INIT_PROPOSAL, model );
}
@View( VIEW_COMPLETE_PROPOSAL )
public String getCompleteProposal( HttpServletRequest request )
{
Map<String, Object> model = getModel( );
// If no campaign specified, expect it in request.
if ( StringUtils.isBlank( _proposal.getCodeCampaign( ) ) )
{
_proposal.setCodeCampaign( request.getParameter( PARAMETER_CAMPAIGN_CODE ) );
if ( StringUtils.isBlank( _proposal.getCodeCampaign( ) ) )
{
Map<String, Object> requestParameters = new HashMap<String, Object>( );
requestParameters.put( PARAMETER_PLUGIN_NAME, "participatoryideation" );
String strMessageUrl = AdminMessageService.getMessageUrl( request, MESSAGE_ERROR_CAMPAIGN_NOT_SPECIFIED, JSP_MANAGE_PROPOSALS,
AdminMessage.TYPE_ERROR, requestParameters );
return redirect( request, strMessageUrl );
}
}
// Data depending of specified campaign
String campaignCode = _proposal.getCodeCampaign( );
model.put( MARK_CAMPAIGN_CODE, campaignCode );
model.put( MARK_CAMPAIGNTHEME_LIST, IdeationCampaignDataProvider.getInstance( ).getCampaignThemes( campaignCode ) );
model.put( MARK_AREA_LIST, IdeationCampaignDataProvider.getInstance( ).getCampaignAllAreaLabels( campaignCode ) );
// Data NOT depending of specified campaign
model.put( MARK_LOCATION_TYPE_LIST, ProposalService.getInstance( ).getTypeLocationList( ) );
model.put( MARK_FIELD4_LIST, ProposalService.getInstance( ).getField4CodesList( ) );
model.put( MARK_PROPOSAL, _proposal );
model.put( MARK_LANGUAGE, getLocale( ) );
return getPage( PROPERTY_PAGE_TITLE_CREATE_PROPOSAL, TEMPLATE_COMPLETE_PROPOSAL, model );
}
@Action( ACTION_CREATE_PROPOSAL )
public String doCreateProposal( HttpServletRequest request )
{
populate( _proposal, request );
// Check constraints
if ( !validateBean( _proposal, VALIDATION_ATTRIBUTES_PREFIX ) || !isProposalAddressValid( request ) )
{
return redirectView( request, VIEW_COMPLETE_PROPOSAL );
}
if ( Proposal.LOCATION_AREA_TYPE_WHOLE.equals( _proposal.getLocationType( ) ) && StringUtils.isEmpty( _proposal.getGeoJson( ) ) )
{
_proposal.setLocationArdt( null );
}
_proposal.setCodeProposal( 0 );
// _proposal.setCodeCampaign( CampaignHome.getLastCampaign( ).getCode( ) );
_proposal.setSubmitterType( AppPropertiesService.getProperty( ParticipatoryIdeationConstants.PROPERTY_GENERATE_PROPOSAL_SUBMITTER_TYPE ) );
_proposal.setSubmitter( AppPropertiesService.getProperty( ParticipatoryIdeationConstants.PROPERTY_GENERATE_PROPOSAL_SUBMITTER ) );
_proposal.setLuteceUserName( AdminUserService.getAdminUser( request ).getAccessCode() );
_proposal.setFromBackOffice(true);
_proposal.setCreationTimestamp( new java.sql.Timestamp( ( new java.util.Date( ) ).getTime( ) ) );
_proposal.setStatusPublic( Proposal.Status.STATUS_SUBMITTED );
_proposal.setTypeQpvQva( IdeationApp.QPV_QVA_NO );
_proposal.setDocs( new ArrayList<File>( ) );
_proposal.setImgs( new ArrayList<File>( ) );
_proposal.setField1( "" );
_proposal.setfield2( "" );
_proposal.setField3( "" );
/* Identifying QPV from address if GeoJSON available */
if ( StringUtils.isNotEmpty( _proposal.getGeoJson( ) ) )
{
List<QpvQva> listQpvqva;
try
{
listQpvqva = QpvQvaService.getQpvQva( _proposal.getLongitude( ), _proposal.getLatitude( ) );
if ( listQpvqva.size( ) == 0 )
{
_proposal.setTypeQpvQva( IdeationApp.QPV_QVA_NO );
_proposal.setIdQpvQva( null );
_proposal.setLibelleQpvQva( null );
}
else
{
// For backwards compatibility, choose a QPV/QVA in priority if it exists
QpvQva resQpvQva = null;
for ( QpvQva qpvqva : listQpvqva )
{
if ( StringUtils.isNotBlank( qpvqva.getType( ) ) )
{
resQpvQva = qpvqva;
break;
}
}
// If not qpvqva, just take the first one...
if ( resQpvQva == null )
{
resQpvQva = listQpvqva.get( 0 );
}
if ( StringUtils.isNotBlank( resQpvQva.getType( ) ) )
{
_proposal.setTypeQpvQva( resQpvQva.getType( ) );
_proposal.setIdQpvQva( resQpvQva.getId( ) );
_proposal.setLibelleQpvQva( resQpvQva.getLibelle( ) );
}
else
if ( StringUtils.isNotBlank( resQpvQva.getGpruNom( ) ) )
{
_proposal.setTypeQpvQva( IdeationApp.QPV_QVA_GPRU );
_proposal.setIdQpvQva( resQpvQva.getFid( ) );
_proposal.setLibelleQpvQva( resQpvQva.getGpruNom( ) );
}
else
if ( StringUtils.isNotBlank( resQpvQva.getExtBp( ) ) )
{
_proposal.setTypeQpvQva( IdeationApp.QPV_QVA_QBP );
_proposal.setIdQpvQva( resQpvQva.getFid( ) );
_proposal.setLibelleQpvQva( resQpvQva.getExtBp( ) );
}
else
{
_proposal.setTypeQpvQva( resQpvQva.getType( ) );
_proposal.setIdQpvQva( resQpvQva.getId( ) );
_proposal.setLibelleQpvQva( resQpvQva.getLibelle( ) );
}
}
}
catch( Exception e )
{
_proposal.setTypeQpvQva( IdeationApp.QPV_QVA_ERR );
_proposal.setIdQpvQva( null );
_proposal.setLibelleQpvQva( null );
AppLogService.error( "IDEATION : error when trying to identify QPV from address", e );
}
}
else
{
_proposal.setAdress( null );
}
try
{
ProposalService.getInstance( ).createProposal( _proposal );
}
catch( IdeationErrorException e )
{
AppLogService.error( "IDEATION : error when trying to create proposal into DB from BO", e );
}
_proposal = null;
addInfo( INFO_PROPOSAL_CREATED, getLocale( ) );
return redirectView( request, VIEW_MANAGE_PROPOSALS );
}
// ***********************************************************************************
// * MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MO *
// * MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MODIFY MO *
// ***********************************************************************************
/**
* Returns the form to update info about a proposal
*
* @param request
* The Http request
* @return The HTML form to update info
*/
@View( VIEW_MODIFY_PROPOSAL )
public String getModifyProposal( HttpServletRequest request )
{
int nId = Integer.parseInt( request.getParameter( PARAMETER_ID_PROPOSAL ) );
// Always reload proposal because the daemon may modify it.
// We store the user input that needs to be saved in _proposalBoForm
_proposal = ProposalHome.findByPrimaryKey( nId );
if ( _proposalBoForm == null || _proposalBoForm.getId( ) != nId )
{
_proposalBoForm = new ProposalBoForm( );
}
Map<String, Object> model = getModel( );
model.put( MARK_PROPOSAL, _proposal );
model.put( MARK_PROPOSAL_BO_FORM, _proposalBoForm );
if ( _proposal.getCodeCampaign( ) != null )
{
IdeationStaticService.getInstance( ).fillCampaignStaticContent( model, _proposal.getCodeCampaign( ) );
}
else
{
IdeationStaticService.getInstance( ).fillAllStaticContent( model );
}
if ( WorkflowService.getInstance( ).isAvailable( ) )
{
int idWorkflow = AppPropertiesService.getPropertyInt( ParticipatoryIdeationConstants.PROPERTY_WORKFLOW_ID, -1 );
model.put( MARK_RESOURCE_HISTORY, WorkflowService.getInstance( ).getDisplayDocumentHistory( _proposal.getId( ), Proposal.WORKFLOW_RESOURCE_TYPE,
idWorkflow, request, getLocale( ) ) );
}
return getPage( PROPERTY_PAGE_TITLE_MODIFY_PROPOSAL, TEMPLATE_MODIFY_PROPOSAL, model );
}
/**
* Process the change form of a proposal
*
* @param request
* The Http request
* @return The Jsp URL of the process result
*/
@Action( ACTION_MODIFY_PROPOSAL )
public String doModifyProposal( HttpServletRequest request )
{
populate( _proposalBoForm, request );
// Check constraints
if ( !validateBean( _proposalBoForm, VALIDATION_ATTRIBUTES_PREFIX ) )
{
return redirect( request, VIEW_MODIFY_PROPOSAL, PARAMETER_ID_PROPOSAL, _proposal.getId( ) );
}
copyProposalBoFormToProposal( _proposalBoForm, _proposal );
ProposalHome.updateBO( _proposal );
addInfo( INFO_PROPOSAL_UPDATED, getLocale( ) );
try
{
// There is a race condition here because this
// proposal was loaded in the view, the daemon may have changed it
// A workaround is to save it again if it is wrongly indexed.
// It only affects this because the rest of the use of _proposal doesn't use
// fields that are changed by the daemon, but the indexing does.
_solrProposalIndexer.writeProposal( _proposal );
}
catch( Exception e )
{
addInfo( "The proposal modify is done, but Solr was unable to index the document due to exception '" + e.getClass( ).getSimpleName( ) + " : "
+ e.getMessage( ) + "'." );
AppLogService.error( "An error occured during SOLR indexation of proposal #" + _proposalBoForm.getId( ) + " '" + _proposalBoForm.getTitre( ) + "'.",
e );
}
return redirectView( request, VIEW_MANAGE_PROPOSALS );
}
// ***********************************************************************************
// * REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE RE *
// * REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE RE *
// ***********************************************************************************
/**
*
* @param request
* the HTTP request
* @return the url view manage proposals
* @throws AccessDeniedException
* the access denied exception
*/
public String doRemoveProposal( HttpServletRequest request ) throws AccessDeniedException
{
int nIdProposal = Integer.parseInt( request.getParameter( PARAMETER_ID_PROPOSAL ) );
Proposal proposal = ProposalHome.findByPrimaryKey( nIdProposal );
ProposalService.getInstance( ).removeProposalByMdp( proposal );
addInfo( INFO_PROPOSAL_REMOVED, getLocale( ) );
return ( AppPathService.getBaseUrl( request ) + JSP_MANAGE_PROPOSALS );
}
/**
* Returns the form to put the explanation for the deletion
*
* @param request
* The Http request
* @return The HTML form to update info
*/
@View( VIEW_CONFIRM_REMOVE_PROPOSAL )
public String getConfirmRemoveProposalPage( HttpServletRequest request )
{
int nIdProposal = Integer.parseInt( request.getParameter( PARAMETER_ID_PROPOSAL ) );
if ( ( _proposal == null ) || ( _proposal.getId( ) != nIdProposal ) )
{
_proposal = ProposalHome.findByPrimaryKey( nIdProposal );
}
if ( _proposal.getStatusIsRemoved( ) )
{
Map<String, Object> requestParameters = new HashMap<String, Object>( );
requestParameters.put( PARAMETER_PLUGIN_NAME, "participatoryideation" );
String strMessageUrl = AdminMessageService.getMessageUrl( request, MESSAGE_ERROR_PROPOSAL_REMOVED, JSP_MANAGE_PROPOSALS, AdminMessage.TYPE_ERROR,
requestParameters );
return redirect( request, strMessageUrl );
}
Map<String, Object> model = getModel( );
model.put( MARK_PROPOSAL, _proposal );
return getPage( PROPERTY_PAGE_TITLE_CONFIRM_REMOVE_PROPOSAL, TEMPLATE_CONFIRM_REMOVE_PROPOSAL, model );
}
/**
*
* @param request
* the HTTP request
* @return the admin message to confirm removing proposal
* @throws AccessDeniedException
* the access denied exception
*/
@Action( ACTION_CONFIRM_REMOVE_PROPOSAL )
public String getConfirmRemoveProposal( HttpServletRequest request ) throws AccessDeniedException
{
int nIdProposal = Integer.parseInt( request.getParameter( PARAMETER_ID_PROPOSAL ) );
if ( ( _proposal == null ) || ( _proposal.getId( ) != nIdProposal ) )
{
_proposal = ProposalHome.findByPrimaryKey( nIdProposal );
}
if ( _proposal.getStatusIsRemoved( ) )
{
Map<String, Object> requestParameters = new HashMap<String, Object>( );
requestParameters.put( PARAMETER_PLUGIN_NAME, "participatoryideation" );
String strMessageUrl = AdminMessageService.getMessageUrl( request, MESSAGE_ERROR_PROPOSAL_REMOVED, JSP_MANAGE_PROPOSALS, AdminMessage.TYPE_ERROR,
requestParameters );
return redirect( request, strMessageUrl );
}
String strMotifRecev = request.getParameter( PARAMETER_MOTIFRECEV );
_proposal.setMotifRecev( strMotifRecev );
ProposalHome.updateBO( _proposal );
addInfo( INFO_PROPOSAL_UPDATED, getLocale( ) );
return redirect( request, doRemoveProposal( request ) );
}
// *********************************************************************************************
// * WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW *
// * WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW WORKFLOW *
// *********************************************************************************************
/**
* Process an workflow action.
*
* @param request
* the HTTP request
* @return Manage proposal admin page
* @throws AccessDeniedException
* the access denied exception
*/
@Action( ACTION_PROCESS_WORKFLOW_ACTION )
public String doProcessWorkflowAction( HttpServletRequest request ) throws AccessDeniedException
{
int actionId;
int resourceId;
// Get action id and resource id from HTTP request
String strActionId = request.getParameter( PARAMETER_ID_ACTION );
String strResourceId = request.getParameter( PARAMETER_ID_RESOURCE );
try
{
actionId = Integer.parseInt( strActionId );
}
catch( NumberFormatException e )
{
Object [ ] msgParams = {
strActionId
};
String strMessageUrl = AdminMessageService.getMessageUrl( request, MESSAGE_ERROR_PROPOSAL_NO_SUCH_WORKFLOW_ACTION, msgParams, JSP_MANAGE_PROPOSALS,
AdminMessage.TYPE_ERROR );
return redirect( request, strMessageUrl );
}
try
{
resourceId = Integer.parseInt( strResourceId );
}
catch( NumberFormatException e )
{
Object [ ] msgParams = {
strResourceId
};
String strMessageUrl = AdminMessageService.getMessageUrl( request, MESSAGE_ERROR_PROPOSAL_NO_SUCH_WORKFLOW_RESOURCE, msgParams,
JSP_MANAGE_PROPOSALS, AdminMessage.TYPE_ERROR );
return redirect( request, strMessageUrl );
}
// Process workflow action
WorkflowService.getInstance( ).doProcessAction( resourceId, Proposal.WORKFLOW_RESOURCE_TYPE, actionId, -1, request, request.getLocale( ), false );
// Re-index because status has changed
Proposal proposalToReindex = ProposalHome.findByPrimaryKey(resourceId);
_solrProposalIndexer.writeProposal( proposalToReindex );
return redirectView( request, VIEW_MANAGE_PROPOSALS );
}
// ***********************************************************************************
// * EXPORT-USERS EXPORT-USERS EXPORT-USERS EXPORT-USERS EXPORT-USERS EXPORT-USERS E *
// * EXPORT-USERS EXPORT-USERS EXPORT-USERS EXPORT-USERS EXPORT-USERS EXPORT-USERS E *
// ***********************************************************************************
/**
* Export the values from core_user_preferences into csv file
*
* @param request
* The Http request
* @param response
* The Http response
*/
public void doExportCsvUsers( HttpServletRequest request, HttpServletResponse response )
{
int nId = Integer.parseInt( request.getParameter( PARAMETER_ID_PROPOSAL ) );
if ( _proposal == null || ( _proposal.getId( ) != nId ) )
{
_proposal = ProposalHome.findByPrimaryKey( nId );
}
List<Integer> subIds = (List<Integer>) ProposalHome.getSubProposalsId( nId, ProposalHome.GetSubProposalsMethod.ALL_FAMILY );
List<ArrayList<String>> valuesList = ProposalUsersService.getExportInfosList( subIds );
try
{
// Generate CSV file
String strFormatExtension = AppPropertiesService.getProperty( PROPERTY_CSV_EXTENSION );
String strFileName = "proposal" + nId + "_" + AppPropertiesService.getProperty( PROPERTY_CSV_FILE_NAME ) + "." + strFormatExtension;
ProposalExportUtils.addHeaderResponse( request, response, strFileName, strFormatExtension );
OutputStream os = response.getOutputStream( );
// say how to decode the csv file, with utf8
byte [ ] bom = new byte [ ] {
(byte) 0xEF, (byte) 0xBB, (byte) 0xBF
}; // BOM values
os.write( bom ); // adds BOM
CsvUtils.writeCsv( CsvUtils.PROPOSALUSERS_PREFIX_CSV, valuesList, os, getLocale( ) );
os.flush( );
os.close( );
}
catch( IOException e )
{
AppLogService.error( e );
}
}
// ***********************************************************************************
// * UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS U *
// * UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS UTILS U *
// ***********************************************************************************
private void copyProposalBoFormToProposal( ProposalBoForm proposalBoForm, Proposal proposal )
{
if ( StringUtils.isNotEmpty( proposalBoForm.getTitre( ) ) )
{
proposal.setTitre( proposalBoForm.getTitre( ) );
}
else
{
proposal.setTitre( null );
}
if ( StringUtils.isNotEmpty( proposalBoForm.getDescription( ) ) )
{
proposal.setDescription( proposalBoForm.getDescription( ) );
}
else
{
proposal.setDescription( null );
}
if ( StringUtils.isNotEmpty( proposalBoForm.getCout( ) ) )
{
proposal.setCout( Long.parseLong( proposalBoForm.getCout( ) ) );
}
else
{
proposal.setCout( null );
}
// Trying to determine LocationType using LocationArdt.
proposal.setLocationType(
StringUtils.isNotEmpty( proposalBoForm.getLocationArdt( ) ) ? Proposal.LOCATION_AREA_TYPE_LOCALIZED : Proposal.LOCATION_AREA_TYPE_WHOLE );
if ( StringUtils.isNotEmpty( proposalBoForm.getLocationArdt( ) ) )
{
proposal.setLocationArdt( proposalBoForm.getLocationArdt( ) );
}
else
{
proposal.setLocationArdt( null );
}
proposal.setTypeQpvQva( proposalBoForm.getTypeQpvQva( ) );
if ( IdeationApp.QPV_QVA_QPV.equals( proposalBoForm.getTypeQpvQva( ) ) || IdeationApp.QPV_QVA_QVA.equals( proposalBoForm.getTypeQpvQva( ) )
|| IdeationApp.QPV_QVA_GPRU.equals( proposalBoForm.getTypeQpvQva( ) ) || IdeationApp.QPV_QVA_QBP.equals( proposalBoForm.getTypeQpvQva( ) ) )
{
proposal.setIdQpvQva( proposalBoForm.getIdQpvQva( ) );
proposal.setLibelleQpvQva( proposalBoForm.getLibelleQpvQva( ) );
}
else
{
proposal.setIdQpvQva( null );
proposal.setLibelleQpvQva( null );
}
proposal.setField4( proposalBoForm.getField4( ) );
if ( StringUtils.isNotEmpty( proposalBoForm.getIdProjet( ) ) )
{
proposal.setIdProjet( proposalBoForm.getIdProjet( ) );
}
else
{
proposal.setIdProjet( null );
}
if ( StringUtils.isNotEmpty( proposalBoForm.getTitreProjet( ) ) )
{
proposal.setTitreProjet( proposalBoForm.getTitreProjet( ) );
}
else
{
proposal.setTitreProjet( null );
}
if ( StringUtils.isNotEmpty( proposalBoForm.getUrlProjet( ) ) )
{
proposal.setUrlProjet( proposalBoForm.getUrlProjet( ) );
}
else
{
proposal.setUrlProjet( null );
}
if ( StringUtils.isNotEmpty( proposalBoForm.getWinnerProjet( ) ) )
{
proposal.setWinnerProjet( proposalBoForm.getWinnerProjet( ) );
}
else
{
proposal.setWinnerProjet( null );
}
}
private boolean isProposalAddressValid( HttpServletRequest request )
{
boolean bIsValid = true;
if ( _proposal.getLocationType( ).equals( Proposal.LOCATION_AREA_TYPE_LOCALIZED ) && StringUtils.isEmpty( _proposal.getLocationArdt( ) ) )
{
addError( MESSAGE_ERROR_ARRONDISSEMENT_EMPTY, request.getLocale( ) );
bIsValid = false;
}
if ( StringUtils.isNotBlank( _proposal.getAdress( ) ) )
{
if ( StringUtils.isEmpty( _proposal.getLocationType( ) ) )
{
addError( MESSAGE_ERROR_ADDRESS_LOCATION_TYPE_EMPTY, request.getLocale( ) );
bIsValid = false;
}
// FIXME : This code is waiting for reintegration of geojson mecanism...
// if ( StringUtils.isEmpty( _proposal.getGeoJson( ) ) )
// {
// addError( MESSAGE_ERROR_ADDRESS_NOT_VALID + " - Unable to identity GeoJSON for address '" + _proposal.getAdress( ) + "'", request.getLocale( ) );
// bIsValid = false;
// }
}
else
{
_proposal.setLatitude( null );
_proposal.setLongitude( null );
}
if ( StringUtils.isNotEmpty( _proposal.getGeoJson( ) ) )
{
GeolocItem geolocItem = null;
try
{
geolocItem = GeolocItem.fromJSON( _proposal.getGeoJson( ) );
_proposal.setAdress( geolocItem.getAddress( ) );
_proposal.setLatitude( geolocItem.getLat( ) );
_proposal.setLongitude( geolocItem.getLon( ) );
// FIXME : Trying to automaticly identify zip code from geojson
// private static final java.util.regex.Pattern _patternAdresseArrondissement = java.util.regex.Pattern.compile( ", 75[0-1]([0-2][0-9]) PARIS"
// );
// Matcher m = _patternAdresseArrondissement.matcher( _proposal.getAdress( ) );
// if ( m.find( ) ) {
// int nArdt = Integer.parseInt( m.group( 1 ) );
// String strArdt = ProposalService.getInstance( ).getArrondissementCode( nArdt );
// if ( _proposal.getLocationType( ).equals( Proposal.LOCATION_TYPE_ARDT )
// && StringUtils.isNotEmpty( _proposal.getLocationArdt( ) )
// && ( !strArdt.equals( _proposal.getLocationArdt( ) ) ) )
// {
// addError( MESSAGE_ERROR_ADDRESS_ARDT_MISMATCH, request.getLocale( ) );
// bIsValid = false;
// }
// else
// {
// _proposal.setLocationArdt( strArdt );
// }
// }
}
catch( Exception e )
{
addError( MESSAGE_ERROR_ADDRESS_FORMAT, getLocale( ) );
AppLogService.error( "ProposalJspBean: malformed data from client: address = " + _proposal.getGeoJson( ) + "; exception " + e );
bIsValid = false;
}
}
return bIsValid;
}
}