IdeationCampaignDataProvider.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.campaign;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import org.apache.commons.lang.StringUtils;
import fr.paris.lutece.plugins.participatoryideation.business.proposal.Proposal;
import fr.paris.lutece.plugins.participatoryideation.business.submitter.SubmitterType;
import fr.paris.lutece.plugins.participatoryideation.business.submitter.SubmitterTypeHome;
import fr.paris.lutece.plugins.participatoryideation.util.ParticipatoryIdeationConstants;
import fr.paris.lutece.portal.service.spring.SpringContextService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.util.ReferenceItem;
import fr.paris.lutece.util.ReferenceList;
/**
* This class provides ideation campaign default data. Campaign phases are considered as opened.
*
* TODO : some data should be configurable in a simple way in BO (for example, string with list of values separated by comma...)
*/
public class IdeationCampaignDataProvider implements IIdeationCampaignDataProvider
{
private static String PROPERTY_PREFIX = "participatoryideation.campaign.";
private static String PROPERTY_SEP = ";";
// Campaigns
private static ReferenceList campaigns = null;
// Themes
// Map :
// Key = campaign code
// Value = Reference list with code and label
private static Map<String, ReferenceList> themeLabels = null;
// Themes
// Map :
// Key = campaign code
// Value = Reference list with code and front color rgb
private static Map<String, ReferenceList> themeFrontRgbs = null;
// Areas
// Map :
// Key = campaign code
// Value = Reference list with code and label
private static Map<String, ReferenceList> areaLabels = null;
// Area types
// Map :
// Key = campaign code
// Value = Reference list with code and type (whole / localized)
private static Map<String, ReferenceList> areaTypes = null;
// Phase date
// Map :
// Key = campaign code
// Value = Array with two values : begin datetime, end datetime
private static Map<String, Timestamp [ ]> dates = null;
//
// Areas Map :
// Key = campaign code
// Value = Map :
// Key = field code
// Value = data
//
private static Map<String, Map<String, String [ ]>> fields = null;
// *********************************************************************************************
// * SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON *
// * SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON SINGLETON *
// *********************************************************************************************
private static final String BEAN_IDEATIONCAMPAIGN_DATA_PROVIDER = "participatoryideation.ideationCampaignDataProvider";
private static IIdeationCampaignDataProvider _singleton;
public static IIdeationCampaignDataProvider getInstance( )
{
if ( _singleton == null )
{
_singleton = SpringContextService.getBean( BEAN_IDEATIONCAMPAIGN_DATA_PROVIDER );
loadProperties( );
}
return _singleton;
}
// *********************************************************************************************
// * CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN *
// * CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN CAMPAIGN *
// *********************************************************************************************
@Override
public ReferenceList getCampaigns( )
{
return campaigns;
}
@Override
public ReferenceItem getLastCampaign( )
{
return getCampaigns( ).stream( ).sorted( new Comparator<ReferenceItem>( )
{
@Override
public int compare( ReferenceItem c1, ReferenceItem c2 )
{
return c2.getCode( ).compareTo( c1.getCode( ) );
}
} ).findFirst( ).get( );
}
// *********************************************************************************************
// * PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASE *
// * PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASES PHASE *
// *********************************************************************************************
@Override
public boolean isBeforeBeginning( String codeCampaign, String phase )
{
if ( ParticipatoryIdeationConstants.IDEATION.equals( phase ) )
{
return new Date( ).before( dates.get( codeCampaign ) [0] );
}
AppLogService.error( "Unexpected phase code '" + phase + "'." );
return false;
}
@Override
public boolean isAfterBeginning( String codeCampaign, String phase )
{
if ( ParticipatoryIdeationConstants.IDEATION.equals( phase ) )
{
return new Date( ).after( dates.get( codeCampaign ) [0] );
}
AppLogService.error( "Unexpected phase code '" + phase + "'." );
return false;
}
@Override
public boolean isDuring( String codeCampaign, String phase )
{
return isAfterBeginning( codeCampaign, phase ) && isBeforeEnd( codeCampaign, phase );
}
@Override
public boolean isBeforeEnd( String codeCampaign, String phase )
{
if ( ParticipatoryIdeationConstants.IDEATION.equals( phase ) )
{
return new Date( ).before( dates.get( codeCampaign ) [1] );
}
AppLogService.error( "Unexpected phase code '" + phase + "'." );
return false;
}
@Override
public boolean isAfterEnd( String codeCampaign, String phase )
{
if ( ParticipatoryIdeationConstants.IDEATION.equals( phase ) )
{
return new Date( ).after( dates.get( codeCampaign ) [1] );
}
AppLogService.error( "Unexpected phase code '" + phase + "'." );
return false;
}
@Override
public boolean isBeforeBeginning( String phase )
{
return isBeforeBeginning( getLastCampaign( ).getCode( ), phase );
}
@Override
public boolean isAfterBeginning( String phase )
{
return isAfterBeginning( getLastCampaign( ).getCode( ), phase );
}
@Override
public boolean isDuring( String phase )
{
return isDuring( getLastCampaign( ).getCode( ), phase );
}
@Override
public boolean isBeforeEnd( String phase )
{
return isBeforeEnd( getLastCampaign( ).getCode( ), phase );
}
@Override
public boolean isAfterEnd( String phase )
{
return isAfterEnd( getLastCampaign( ).getCode( ), phase );
}
// *********************************************************************************************
// * AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA *
// * AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA AREA *
// *********************************************************************************************
@Override
public ReferenceItem getCampaignWholeAreaLabel( String codeCampaign )
{
Stream< ReferenceItem > areaStream = areaLabels.get( codeCampaign ).stream( );
// Assuming there should be only one whole-typed item
Optional< ReferenceItem > opt = areaStream.filter( r -> Proposal.LOCATION_AREA_TYPE_WHOLE.contentEquals( r.getCode( ) ) ).findFirst( );
return opt.get( );
}
@Override
public ReferenceList getCampaignLocalizedAreaLabels( String codeCampaign )
{
ReferenceList result = new ReferenceList( );
for ( ReferenceItem item : areaLabels.get( codeCampaign ) )
{
if ( !Proposal.LOCATION_AREA_TYPE_WHOLE.equals( item.getCode( ) ) )
{
result.add( item );
}
}
return result;
}
@Override
public int getCampaignNumberLocalizedAreas( String codeCampaign )
{
return getCampaignLocalizedAreaLabels( codeCampaign ).size( );
}
@Override
public ReferenceItem getLastCampaignWholeAreaLabel( )
{
return getCampaignWholeAreaLabel( getLastCampaign( ).getCode( ) );
}
@Override
public ReferenceList getLastCampaignLocalizedAreaLabels( )
{
return getCampaignLocalizedAreaLabels( getLastCampaign( ).getCode( ) );
}
@Override
public int getLastCampaignNumberLocalizedAreas( )
{
return getLastCampaignLocalizedAreaLabels( ).size( );
}
@Override
public ReferenceList getCampaignAllAreaLabels( String codeCampaign )
{
ReferenceList result = new ReferenceList( );
for ( ReferenceItem item : areaLabels.get( codeCampaign ) )
{
if ( Proposal.LOCATION_AREA_TYPE_LOCALIZED.equals( item.getName( ) ) )
{
result.add( item );
}
}
return result;
}
@Override
public ReferenceList getCampaignAllAreaTypes( String codeCampaign )
{
ReferenceList result = new ReferenceList( );
for ( ReferenceItem item : areaTypes.get( codeCampaign ) )
{
if ( Proposal.LOCATION_AREA_TYPE_LOCALIZED.equals( item.getName( ) ) )
{
result.add( item );
}
}
return result;
}
@Override
public ReferenceList getLastCampaignAllAreaLabels( )
{
return getCampaignAllAreaLabels( getLastCampaign( ).getCode( ) );
}
@Override
public ReferenceList getLastCampaignAllAreaTypes( )
{
return getCampaignAllAreaTypes( getLastCampaign( ).getCode( ) );
}
// *********************************************************************************************
// * SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER *
// * SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER SUBMITTER *
// *********************************************************************************************
@Override
public Collection<SubmitterType> getCampaignSubmitterTypes( String codeCampaign )
{
return SubmitterTypeHome.getSubmitterTypesListByCampaign( codeCampaign );
}
// *********************************************************************************************
// * THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEME *
// * THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEMES THEME *
// *********************************************************************************************
@Override
public ReferenceList getCampaignThemes( String codeCampaign )
{
return themeLabels.get( codeCampaign );
}
@Override
public ReferenceList getLastCampaignThemes( )
{
return getCampaignThemes( getLastCampaign( ).getCode( ) );
}
@Override
public ReferenceList getCampaignThemesFrontRgb( String codeCampaign )
{
return themeFrontRgbs.get( codeCampaign );
}
// *********************************************************************************************
// * FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELD *
// * FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELDS FIELD *
// *********************************************************************************************
@Override
public String [ ] getCampaignFieldData( String codeCampaign, String fieldCode )
{
return getCampaignFieldsData( codeCampaign ).get( fieldCode );
}
@Override
public Map<String, String [ ]> getCampaignFieldsData( String codeCampaign )
{
return fields.get( codeCampaign );
}
// *********************************************************************************************
// * LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD *
// * LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD LOAD *
// *********************************************************************************************
private static void loadProperties( )
{
// Campaigns
campaigns = new ReferenceList( );
for ( int i = 1; true; i++ )
{
String propName = PROPERTY_PREFIX + i;
String propValue = AppPropertiesService.getProperty( propName );
if ( StringUtils.isBlank( propValue ) )
{
break;
}
String [ ] campaign = propValue.split( PROPERTY_SEP );
if ( campaign.length != 2 )
{
AppLogService.error( "The property '" + propName + "' should be formated as 'code" + PROPERTY_SEP + "label' but is '" + propValue + "'." );
break;
}
campaigns.addItem( campaign [0], campaign [1] );
}
// Themes for each campaign
themeLabels = new HashMap<>( );
themeFrontRgbs = new HashMap<>( );
for ( ReferenceItem campaign : campaigns )
{
ReferenceList campaignThemes = new ReferenceList( );
ReferenceList campaignThemeFrontRgbs = new ReferenceList( );
for ( int i = 1; true; i++ )
{
String propName = PROPERTY_PREFIX + campaign.getCode( ) + ".theme." + i;
String propValue = AppPropertiesService.getProperty( propName );
if ( StringUtils.isBlank( propValue ) )
{
break;
}
String [ ] theme = propValue.split( PROPERTY_SEP );
if ( theme.length != 3 )
{
AppLogService.error( "The property '" + propName + "' should be formated as 'code" + PROPERTY_SEP + "label" + PROPERTY_SEP
+ "color' but is '" + propValue + "'." );
break;
}
campaignThemes.addItem( theme [0], theme [1] );
campaignThemeFrontRgbs.addItem( theme [0], theme [2] );
}
themeLabels.put( campaign.getCode( ), campaignThemes );
themeFrontRgbs.put( campaign.getCode( ), campaignThemeFrontRgbs );
}
// Areas for each campaign
areaLabels = new HashMap<>( );
areaTypes = new HashMap<>( );
for ( ReferenceItem campaign : campaigns )
{
ReferenceList campaignAreas = new ReferenceList( );
ReferenceList campaignTypes = new ReferenceList( );
for ( int i = 1; true; i++ )
{
String propName = PROPERTY_PREFIX + campaign.getCode( ) + ".area." + i;
String propValue = AppPropertiesService.getProperty( propName );
if ( StringUtils.isBlank( propValue ) )
{
break;
}
String [ ] area = propValue.split( PROPERTY_SEP );
if ( area.length != 3 )
{
AppLogService.error( "The property '" + propName + "' should be formated as 'code" + PROPERTY_SEP + "label" + PROPERTY_SEP
+ "type' but is '" + propValue + "'." );
break;
}
campaignAreas.addItem( area [0], area [1] );
campaignTypes.addItem( area [0], area [2] );
}
areaLabels.put( campaign.getCode( ), campaignAreas );
areaTypes.put( campaign.getCode( ), campaignTypes );
}
// Phase dates for each campaign
dates = new HashMap<>( );
for ( ReferenceItem campaign : campaigns )
{
Timestamp [ ] beginEnd = new Timestamp [ 2];
String propName = PROPERTY_PREFIX + campaign.getCode( ) + ".ideation";
String propValue = AppPropertiesService.getProperty( propName );
if ( StringUtils.isBlank( propValue ) )
{
break;
}
String [ ] beginEndStr = propValue.split( PROPERTY_SEP );
if ( beginEndStr.length != 2 )
{
AppLogService
.error( "The property '" + propName + "' should be formated as 'timestamp" + PROPERTY_SEP + "timestamp' but is '" + propValue + "'." );
break;
}
beginEnd [0] = Timestamp.valueOf( LocalDateTime.parse( beginEndStr [0] ) );
beginEnd [1] = Timestamp.valueOf( LocalDateTime.parse( beginEndStr [1] ) );
dates.put( campaign.getCode( ), beginEnd );
}
// Fields for each campaign
fields = new HashMap<>( );
for ( ReferenceItem campaign : campaigns )
{
Map<String, String [ ]> fieldData = new HashMap<>( );
for ( int i = 1; i < 5; i++ ) // TODO : add unlimited fields in the last form step
{
String fieldName = "field" + i;
String propName = PROPERTY_PREFIX + campaign.getCode( ) + "." + fieldName;
String propActiveValue = AppPropertiesService.getProperty( propName + ".active" );
String propLabelValue = AppPropertiesService.getProperty( propName + ".label" );
String propDescriptionValue = AppPropertiesService.getProperty( propName + ".description" );
String propMandatoryValue = AppPropertiesService.getProperty( propName + ".mandatory" );
fieldData.put( fieldName, new String [ ] {
propActiveValue, propLabelValue, propDescriptionValue, propMandatoryValue
} );
}
fields.put( campaign.getCode( ), fieldData );
}
}
}