ProposalWSService.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.service;

import java.sql.Timestamp;
import java.text.Normalizer;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;

import fr.paris.lutece.plugins.extend.business.extender.history.ResourceExtenderHistory;
import fr.paris.lutece.plugins.extend.modules.comment.business.Comment;
import fr.paris.lutece.plugins.extend.modules.comment.service.CommentService;
import fr.paris.lutece.plugins.extend.modules.comment.service.ICommentService;
import fr.paris.lutece.plugins.extend.modules.comment.service.extender.CommentResourceExtender;
import fr.paris.lutece.plugins.extend.service.extender.history.IResourceExtenderHistoryService;
import fr.paris.lutece.plugins.extend.service.extender.history.ResourceExtenderHistoryService;
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.util.ParticipatoryIdeationConstants;
import fr.paris.lutece.plugins.workflowcore.business.action.Action;
import fr.paris.lutece.plugins.workflowcore.service.workflow.IWorkflowService;
import fr.paris.lutece.portal.service.datastore.DatastoreService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.spring.SpringContextService;
import fr.paris.lutece.portal.service.template.AppTemplateService;
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.html.HtmlTemplate;

public class ProposalWSService implements IProposalWSService
{

    private static final String BEAN_PROPOSAL_WEB_SERVICE_SERVICE = "participatoryideation.proposalWSService";
    private static IProposalWSService _singleton;
    private static SolrProposalIndexer _solrProposalIndexer;
    private static final String BEAN_SOLR_PROPOSAL_INDEXER = "participatoryideation.solrProposalIndexer";
    private static ICommentService _commentService;
    private static IResourceExtenderHistoryService _resourceHistoryService;

    // properties
    private static final String PROPERTY_POLITENESS_COMMENTS_PROJECTS_NOT_SELECTED = "eudonetbp.site_property.mail.politeness_comments_projects_not_selected.htmlblock";
    // Mark
    private static final String MARK_COMMENT = "comment";

    /**
     * Get the unique instance of the Proposal Web Service Service
     * 
     * @return The instance
     */
    public static IProposalWSService getInstance( )
    {
        if ( _singleton == null )
        {
            _solrProposalIndexer = SpringContextService.getBean( BEAN_SOLR_PROPOSAL_INDEXER );
            _singleton = SpringContextService.getBean( BEAN_PROPOSAL_WEB_SERVICE_SERVICE );
            _commentService = SpringContextService.getBean( CommentService.BEAN_SERVICE );
            _resourceHistoryService = SpringContextService.getBean( ResourceExtenderHistoryService.BEAN_SERVICE );

        }
        return _singleton;

    }

    @Override
    public Collection<Proposal> getProposalsList( )
    {

        return ProposalHome.getProposalsList( );

    }

    @Override
    public Proposal getProposalByIdentifiant( int nKey )
    {

        return ProposalHome.findByPrimaryKey( nKey );

    }

    @Override
    public Proposal getProposalByIdentifiantAndCampaign( int nKey, String strCampaign )
    {

        return ProposalHome.findByCodes( strCampaign, nKey );

    }

    @Override
    public Collection<Proposal> getProposalsListSearch( ProposalSearcher proposalSearcher )
    {

        return ProposalHome.getProposalsListSearch( proposalSearcher );
    }

    @Override
    public void updateProposal( Proposal proposalLutece, Proposal proposalEudonet, HttpServletRequest request )
    {
        updateProposal( proposalLutece, proposalEudonet, true, request );
    }

    @Override
    public void updateProposal( Proposal proposalLutece, Proposal proposalEudonet, boolean notify, HttpServletRequest request )
    {

        String valStatusLutece = proposalLutece.getStatusPublic( ).getValeur( ); // statut PUBLIC sur LUTECE
        String valStatusEudonet = proposalEudonet.getStatusEudonet( ).getValeur( ); // statut EUDONET sur LUTECE (si non valué, sera value au statut PUBLIC sur
        // LUTECE)
        String valStatusEudonetLutece = valStatusLutece; // statut PUBLIC sur EUDONET

        if ( proposalLutece.getStatusEudonet( ) != null )
        {
            valStatusEudonetLutece = proposalLutece.getStatusEudonet( ).getValeur( );
        }

        if ( valStatusLutece.equals( valStatusEudonet )
                || ( !valStatusLutece.equals( valStatusEudonet ) && !valStatusLutece.equals( valStatusEudonetLutece )
                        && !valStatusEudonet.equals( valStatusEudonetLutece ) )
                || ( valStatusLutece.equals( Proposal.Status.STATUS_SUPPRIME_PAR_USAGER.getValeur( ) ) )
                || ( valStatusEudonet.equals( Proposal.Status.STATUS_SUPPRIME_PAR_USAGER.getValeur( ) ) ) )
        {
            // On ne fait rien
        }
        else
        {
            ProposalHome.updateBO( proposalEudonet );
            if ( proposalEudonet.getMotifRecev( ) != null && StringUtils.isNotEmpty( proposalEudonet.getMotifRecev( ) )
                    && StringUtils.isNotBlank( proposalEudonet.getMotifRecev( ) ) && !( proposalLutece.getMotifRecev( ) != null
                            && proposalEudonet.getMotifRecev( ) != null && proposalEudonet.getMotifRecev( ).equals( proposalLutece.getMotifRecev( ) ) ) )
            {
                createComment( proposalEudonet );
            }
            if ( proposalEudonet.getStatusPublic( ).equals( Proposal.Status.STATUS_SUPPRIME_PAR_MDP )
                    || proposalEudonet.getStatusPublic( ).equals( Proposal.Status.STATUS_SUPPRIME_PAR_USAGER ) )
            {
                _solrProposalIndexer.removeProposal( proposalEudonet );
            }
            if ( WorkflowService.getInstance( ).isAvailable( ) )
            {
                processAction( valStatusEudonet, proposalLutece, notify, request );
            }
        }
    }

    @Override
    public Proposal updateProposal( Proposal proposal )
    {

        proposal = ProposalHome.updateBO( proposal );
        return proposal;
    }

    @Override
    public void createComment( Proposal proposal )
    {
        String strCommentPNS = DatastoreService.getDataValue( PROPERTY_POLITENESS_COMMENTS_PROJECTS_NOT_SELECTED, "" );
        String strContentCommentPNS = proposal.getMotifRecev( );
        Map<String, String> model = new HashMap<String, String>( );
        model.put( MARK_COMMENT, proposal.getMotifRecev( ) );
        try
        {
            HtmlTemplate t = AppTemplateService.getTemplateFromStringFtl( strCommentPNS, new Locale( "fr", "FR" ), model );
            strContentCommentPNS = t.getHtml( );
        }
        catch( Exception e )
        {
            // _service.addToLog( "Erreur updateProposal: "+e.getMessage( ));
            AppLogService.error( "Erreur avec le template freemarker dans les proprietes du site: ", e );
        }

        Comment comment = new Comment( );
        comment.setIdExtendableResource( "" + proposal.getId( ) );
        comment.setExtendableResourceType( Proposal.PROPERTY_RESOURCE_TYPE );
        comment.setIdParentComment( 0 );
        comment.setComment( strContentCommentPNS );
        Timestamp currentDate = new Timestamp( new Date( ).getTime( ) );
        comment.setDateComment( currentDate );
        comment.setDateLastModif( currentDate );
        comment.setName( "Mairie de Paris" );
        comment.setEmail( "lutece@lutece.com" );
        comment.setPublished( true );
        comment.setIpAddress( "" );
        comment.setIsAdminComment( true );
        comment.setIsImportant( true );
        // comment.setCommentOrder(1);
        comment.setPinned( true );
        _commentService.create( comment );

        ResourceExtenderHistory history = new ResourceExtenderHistory( );
        history.setExtenderType( CommentResourceExtender.EXTENDER_TYPE_COMMENT );
        // history.setIdExtendableResource( proposal.getCodeCampaign() + "-" + String.format("%06d", proposal.getCodeProposal()) );
        history.setIdExtendableResource( "" + proposal.getId( ) );
        history.setExtendableResourceType( Proposal.PROPERTY_RESOURCE_TYPE );
        history.setIpAddress( StringUtils.EMPTY );
        history.setUserGuid( AppPropertiesService.getProperty( ParticipatoryIdeationConstants.PROPERTY_GENERATE_PROPOSAL_LUTECE_USER_NAME ) ); // Le commentaire
                                                                                                                                               // est déposé par
        // l'équipe
        // du Budget Participatif.
        _resourceHistoryService.create( history );
    }

    private void processAction( String proposalStatut, Proposal proposal, boolean notify, HttpServletRequest request )
    {

        boolean foundAction = false;
        int nIdWorkflow = AppPropertiesService.getPropertyInt( ParticipatoryIdeationConstants.PROPERTY_WORKFLOW_ID, -1 );
        String proposalStatutLibelle = removeAccent(
                I18nService.getLocalizedString( ( Proposal.Status.getByValue( proposalStatut ).getLibelle( ) ), new Locale( "fr", "FR" ) ) )
                + ( notify ? " (avec notification)" : " (sans notification)" );

        if ( nIdWorkflow != -1 )
        {
            List<Action> actionsList = WorkflowService.getInstance( ).getMassActions( nIdWorkflow );
            for ( Action action : actionsList )
            {
                String actionLibelle = removeAccent( action.getName( ) );
                if ( actionLibelle.equals( proposalStatutLibelle ) )
                {
                    foundAction = true;
                    IWorkflowService _service = SpringContextService
                            .getBean( fr.paris.lutece.plugins.workflowcore.service.workflow.WorkflowService.BEAN_SERVICE );
                    _service.doProcessAction( proposal.getId( ), Proposal.WORKFLOW_RESOURCE_TYPE, action.getId( ), -1, request, new Locale( "fr", "FR" ), false,
                            null );
                    // WorkflowService.getInstance( ).doProcessAction(proposal.getId( ), Proposal.WORKFLOW_RESOURCE_TYPE, action.getId( ), -1 , null, new
                    // Locale( "fr" ,
                    // "FR" ), false);
                }
            }

            if ( !foundAction )
            {
                AppLogService.error( "No such action on workflow #" + nIdWorkflow + " : '" + proposalStatutLibelle + "'" );
            }

            /*
             * State state= WorkflowService.getInstance( ).getState( proposal.getId( ), Proposal.WORKFLOW_RESOURCE_TYPE, nIdWorkflow, -1 ); if(state != null){
             * WorkflowService.getInstance( ).doProcessAutomaticReflexiveActions(proposal.getId( ), Proposal.WORKFLOW_RESOURCE_TYPE, state.getId( ), -1, new
             * Locale( "fr" , "FR" )); }
             */
        }
    }

    @Override
    public void processActionByName( String strWorkflowProposalActionName, int nIdProposal, HttpServletRequest request )
    {

        int nIdWorkflow = AppPropertiesService.getPropertyInt( ParticipatoryIdeationConstants.PROPERTY_WORKFLOW_ID, -1 );

        if ( nIdWorkflow != -1 && WorkflowService.getInstance( ).isAvailable( ) && !StringUtils.isEmpty( strWorkflowProposalActionName ) )
        {

            List<Action> actionsList = WorkflowService.getInstance( ).getMassActions( nIdWorkflow );

            for ( Action action : actionsList )
            {

                if ( action.getName( ).equals( strWorkflowProposalActionName ) )
                {

                    WorkflowService.getInstance( ).doProcessAction( nIdProposal, Proposal.WORKFLOW_RESOURCE_TYPE, action.getId( ), -1, request,
                            new Locale( "fr", "FR" ), true );

                }
            }
        }

    }

    @Override
    public void processActionByName( String strWorkflowProposalActionName, int nIdProposal )
    {

        int nIdWorkflow = AppPropertiesService.getPropertyInt( ParticipatoryIdeationConstants.PROPERTY_WORKFLOW_ID, -1 );

        if ( nIdWorkflow != -1 && WorkflowService.getInstance( ).isAvailable( ) && !StringUtils.isEmpty( strWorkflowProposalActionName ) )
        {

            List<Action> actionsList = WorkflowService.getInstance( ).getMassActions( nIdWorkflow );

            for ( Action action : actionsList )
            {

                if ( action.getName( ).equals( strWorkflowProposalActionName ) )
                {

                    WorkflowService.getInstance( ).doProcessAction( nIdProposal, Proposal.WORKFLOW_RESOURCE_TYPE, action.getId( ), -1, null,
                            new Locale( "fr", "FR" ), true );

                }
            }
        }

    }

    public static String removeAccent( String source )
    {
        return Normalizer.normalize( source, Normalizer.Form.NFD ).replaceAll( "[^\\p{ASCII}]", "" );
    }

}