diff --git a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/business/FormsPDFTaskTemplate.java b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/business/FormsPDFTaskTemplate.java index 0aa3820..1d569d8 100644 --- a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/business/FormsPDFTaskTemplate.java +++ b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/business/FormsPDFTaskTemplate.java @@ -38,57 +38,69 @@ @Dependent @Named( "workflow-formspdf.formsPDFTaskTemplate" ) -public class FormsPDFTaskTemplate { +public class FormsPDFTaskTemplate +{ - private int _nId; + private int _nId; - private String _strName; - - private int _nIdForm; - - private boolean _bGeneric; + private String _strName; - private String _strContent; + private int _nIdForm; - private boolean _isRte; + private boolean _bGeneric; - private String _strFileName; + private String _strContent; - public int getId() { - return _nId; - } + private boolean _isRte; - public void setId(int nId) { - this._nId = nId; - } + private String _strFileName; - public String getName() { - return _strName; - } + private boolean _isReplaceEmpty; - public void setName(String strName) { - this._strName = strName; - } + public int getId( ) + { + return _nId; + } - public String getContent() { - return _strContent; - } + public void setId( int nId ) + { + this._nId = nId; + } + + public String getName( ) + { + return _strName; + } + + public void setName( String strName ) + { + this._strName = strName; + } + + public String getContent( ) + { + return _strContent; + } - public void setContent(String strContent) { - this._strContent = strContent; - } + public void setContent( String strContent ) + { + this._strContent = strContent; + } - public int getIdForm() { - return _nIdForm; - } + public int getIdForm( ) + { + return _nIdForm; + } - public void setIdForm(int nIdForm) { - this._nIdForm = nIdForm; - } + public void setIdForm( int nIdForm ) + { + this._nIdForm = nIdForm; + } - public boolean isGeneric() { - return _bGeneric; - } + public boolean isGeneric( ) + { + return _bGeneric; + } public void setGeneric( boolean bGeneric ) { @@ -115,4 +127,13 @@ public void setFileName( String strFileName ) this._strFileName = strFileName; } + public boolean isReplaceEmpty( ) + { + return _isReplaceEmpty; + } + + public void setReplaceEmpty( boolean _isReplaceEmpty ) + { + this._isReplaceEmpty = _isReplaceEmpty; + } } diff --git a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/business/FormsPDFTaskTemplateDAO.java b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/business/FormsPDFTaskTemplateDAO.java index 12673c7..284ec02 100644 --- a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/business/FormsPDFTaskTemplateDAO.java +++ b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/business/FormsPDFTaskTemplateDAO.java @@ -43,171 +43,177 @@ import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped -public class FormsPDFTaskTemplateDAO implements IFormsPDFTaskTemplateDAO { - - private static final String SQL_QUERY_SELECTALL = "SELECT id_template, name, id_form, is_generic, content, is_rte, file_name FROM workflow_task_formspdf_template"; - - private static final String SQL_QUERY_SELECT = SQL_QUERY_SELECTALL + " WHERE id_template = ?"; - - private static final String SQL_QUERY_SELECT_WITH_FORM = "SELECT worklow_template.id_template, worklow_template.name, worklow_template.id_form, form.title, worklow_template.is_generic, worklow_template.content, worklow_template.is_rte, worklow_template.file_name FROM workflow_task_formspdf_template worklow_template" - + " LEFT JOIN forms_form form ON form.id_form = worklow_template.id_form"; - - private static final String SQL_QUERY_SELECT_BY_ID_FORM_OR_GENERIC = SQL_QUERY_SELECTALL + " WHERE id_form = ? OR is_generic = true"; - - private static final String SQL_QUERY_INSERT = "INSERT INTO workflow_task_formspdf_template ( name, id_form, is_generic, content, is_rte, file_name ) VALUES ( ?, ?, ?, ?, ?, ? ) "; - - private static final String SQL_QUERY_DELETE = "DELETE FROM workflow_task_formspdf_template WHERE id_template = ? "; - - private static final String SQL_QUERY_UPDATE = "UPDATE workflow_task_formspdf_template SET name = ?, id_form = ?, is_generic = ?, content = ?, is_rte = ?, file_name = ? WHERE id_template = ?"; - @Override - public void insert(FormsPDFTaskTemplate formsPDFTaskTemplate) - { - try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_INSERT, Statement.RETURN_GENERATED_KEYS, FormsPDFPlugin.getPlugin( ) ) ) +public class FormsPDFTaskTemplateDAO implements IFormsPDFTaskTemplateDAO +{ + + private static final String SQL_QUERY_SELECTALL = "SELECT id_template, name, id_form, is_generic, content, is_rte, file_name, is_replace_empty_response FROM workflow_task_formspdf_template"; + + private static final String SQL_QUERY_SELECT = SQL_QUERY_SELECTALL + " WHERE id_template = ?"; + + private static final String SQL_QUERY_SELECT_WITH_FORM = "SELECT workflow_template.id_template, workflow_template.name, workflow_template.id_form, form.title, workflow_template.is_generic, workflow_template.content, workflow_template.is_rte, workflow_template.file_name, workflow_template.is_replace_empty_response FROM workflow_task_formspdf_template workflow_template" + + " LEFT JOIN forms_form form ON form.id_form = workflow_template.id_form"; + + private static final String SQL_QUERY_SELECT_BY_ID_FORM_OR_GENERIC = SQL_QUERY_SELECTALL + " WHERE id_form = ? OR is_generic = true"; + + private static final String SQL_QUERY_INSERT = "INSERT INTO workflow_task_formspdf_template ( name, id_form, is_generic, content, is_rte, file_name, is_replace_empty_response ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) "; + + private static final String SQL_QUERY_DELETE = "DELETE FROM workflow_task_formspdf_template WHERE id_template = ? "; + + private static final String SQL_QUERY_UPDATE = "UPDATE workflow_task_formspdf_template SET name = ?, id_form = ?, is_generic = ?, content = ?, is_rte = ?, file_name = ?, is_replace_empty_response = ? WHERE id_template = ?"; + + @Override + public void insert( FormsPDFTaskTemplate formsPDFTaskTemplate ) + { + try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_INSERT, Statement.RETURN_GENERATED_KEYS, FormsPDFPlugin.getPlugin( ) ) ) + { + int nIndex = 0; + daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getName( ) ); + daoUtil.setInt( ++nIndex, formsPDFTaskTemplate.getIdForm( ) ); + daoUtil.setBoolean( ++nIndex, formsPDFTaskTemplate.isGeneric( ) ); + daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getContent( ) ); + daoUtil.setBoolean( ++nIndex, formsPDFTaskTemplate.isRte( ) ); + daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getFileName( ) ); + daoUtil.setBoolean( ++nIndex, formsPDFTaskTemplate.isReplaceEmpty( ) ); + + daoUtil.executeUpdate( ); + + if ( daoUtil.nextGeneratedKey( ) ) + { + formsPDFTaskTemplate.setId( daoUtil.getGeneratedKeyInt( 1 ) ); + } + } + } + + @Override + public void store( FormsPDFTaskTemplate formsPDFTaskTemplate ) + { + try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_UPDATE, FormsPDFPlugin.getPlugin( ) ) ) + { + + int nIndex = 0; + daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getName( ) ); + daoUtil.setInt( ++nIndex, formsPDFTaskTemplate.getIdForm( ) ); + daoUtil.setBoolean( ++nIndex, formsPDFTaskTemplate.isGeneric( ) ); + daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getContent( ) ); + daoUtil.setBoolean( ++nIndex, formsPDFTaskTemplate.isRte( ) ); + daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getFileName( ) ); + daoUtil.setBoolean( ++nIndex, formsPDFTaskTemplate.isReplaceEmpty( ) ); + + daoUtil.setInt( ++nIndex, formsPDFTaskTemplate.getId( ) ); + + daoUtil.executeUpdate( ); + } + } + + @Override + public FormsPDFTaskTemplate load( int nIdTemplate ) + { + try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECT, FormsPDFPlugin.getPlugin( ) ) ) + { + daoUtil.setInt( 1, nIdTemplate ); + daoUtil.executeQuery( ); + + FormsPDFTaskTemplate formsPDFTaskTemplate = null; + + if ( daoUtil.next( ) ) + { + formsPDFTaskTemplate = dataToObject( daoUtil ); + } + + return formsPDFTaskTemplate; + } + } + + @Override + public List loadByIdFormPlusGenerics( int nIdForm ) + { + List listFormsPDFTaskTemplate = new ArrayList<>( ); + + try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECT_BY_ID_FORM_OR_GENERIC, FormsPDFPlugin.getPlugin( ) ) ) + { + daoUtil.setInt( 1, nIdForm ); + + daoUtil.executeQuery( ); + while ( daoUtil.next( ) ) + { + listFormsPDFTaskTemplate.add( dataToObject( daoUtil ) ); + } + } + return listFormsPDFTaskTemplate; + } + + @Override + public void delete( int nIdTemplate ) + { + try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_DELETE, FormsPDFPlugin.getPlugin( ) ) ) { - int nIndex = 0; - daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getName() ); - daoUtil.setInt( ++nIndex, formsPDFTaskTemplate.getIdForm()); - daoUtil.setBoolean( ++nIndex, formsPDFTaskTemplate.isGeneric()); - daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getContent() ); - daoUtil.setBoolean( ++nIndex, formsPDFTaskTemplate.isRte() ); - daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getFileName( ) ); - - daoUtil.executeUpdate( ); - - if ( daoUtil.nextGeneratedKey( ) ) - { - formsPDFTaskTemplate.setId( daoUtil.getGeneratedKeyInt( 1 ) ); - } + daoUtil.setInt( 1, nIdTemplate ); + daoUtil.executeUpdate( ); } - } - - @Override - public void store(FormsPDFTaskTemplate formsPDFTaskTemplate) - { - try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_UPDATE, FormsPDFPlugin.getPlugin( ) )) - { - - int nIndex = 0; - daoUtil.setString(++nIndex, formsPDFTaskTemplate.getName()); - daoUtil.setInt(++nIndex, formsPDFTaskTemplate.getIdForm()); - daoUtil.setBoolean(++nIndex, formsPDFTaskTemplate.isGeneric()); - daoUtil.setString(++nIndex, formsPDFTaskTemplate.getContent()); - daoUtil.setBoolean(++nIndex, formsPDFTaskTemplate.isRte()); - daoUtil.setString( ++nIndex, formsPDFTaskTemplate.getFileName( ) ); - - daoUtil.setInt(++nIndex, formsPDFTaskTemplate.getId()); - - daoUtil.executeUpdate(); - } - } - - @Override - public FormsPDFTaskTemplate load( int nIdTemplate ) - { - try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECT, FormsPDFPlugin.getPlugin( ) )) - { - daoUtil.setInt(1, nIdTemplate); - daoUtil.executeQuery(); - - FormsPDFTaskTemplate formsPDFTaskTemplate = null; - - if (daoUtil.next()) - { - formsPDFTaskTemplate = dataToObject(daoUtil); - } - - return formsPDFTaskTemplate; - } - } - - @Override - public List loadByIdFormPlusGenerics( int nIdForm ) - { - List listFormsPDFTaskTemplate = new ArrayList<>(); - - try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECT_BY_ID_FORM_OR_GENERIC, FormsPDFPlugin.getPlugin( ) )) - { - daoUtil.setInt(1, nIdForm); - - daoUtil.executeQuery(); - while (daoUtil.next()) - { - listFormsPDFTaskTemplate.add(dataToObject(daoUtil)); - } - } - return listFormsPDFTaskTemplate; - } - - @Override - public void delete( int nIdTemplate ) - { - try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_DELETE, FormsPDFPlugin.getPlugin( ) )) - { - daoUtil.setInt( 1, nIdTemplate ); - daoUtil.executeUpdate( ); - } - } - - @Override - public List selectAll() - { - List listFormsPDFTaskTemplate = new ArrayList<>(); - - try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECTALL, FormsPDFPlugin.getPlugin( ) )) - { - daoUtil.executeQuery(); - while (daoUtil.next()) - { - listFormsPDFTaskTemplate.add(dataToObject(daoUtil)); - } - } - return listFormsPDFTaskTemplate; - } - - @Override - public List selectAllWithForms() - { - List listFormsPDFTaskTemplateDto = new ArrayList<>(); - - try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECT_WITH_FORM, WorkflowUtils.getPlugin( ) ) ) + } + + @Override + public List selectAll( ) + { + List listFormsPDFTaskTemplate = new ArrayList<>( ); + + try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECTALL, FormsPDFPlugin.getPlugin( ) ) ) { daoUtil.executeQuery( ); while ( daoUtil.next( ) ) { - listFormsPDFTaskTemplateDto.add( dataToObjectDto( daoUtil ) ); + listFormsPDFTaskTemplate.add( dataToObject( daoUtil ) ); + } + } + return listFormsPDFTaskTemplate; + } + + @Override + public List selectAllWithForms( ) + { + List listFormsPDFTaskTemplateDto = new ArrayList<>( ); + + try ( DAOUtil daoUtil = new DAOUtil( SQL_QUERY_SELECT_WITH_FORM, WorkflowUtils.getPlugin( ) ) ) + { + daoUtil.executeQuery( ); + while ( daoUtil.next( ) ) + { + listFormsPDFTaskTemplateDto.add( dataToObjectDto( daoUtil ) ); } } return listFormsPDFTaskTemplateDto; - } - - private FormsPDFTaskTemplateDTO dataToObjectDto(DAOUtil daoUtil) - { - FormsPDFTaskTemplate formsPDFTaskTemplate = dataToObject(daoUtil); - FormsPDFTaskTemplateDTO formsPDFTaskTemplateDto = new FormsPDFTaskTemplateDTO(); - formsPDFTaskTemplateDto.setId(formsPDFTaskTemplate.getId()); - formsPDFTaskTemplateDto.setName(formsPDFTaskTemplate.getName()); - formsPDFTaskTemplateDto.setGeneric(formsPDFTaskTemplate.isGeneric()); - formsPDFTaskTemplateDto.setIdForm(formsPDFTaskTemplate.getIdForm()); - formsPDFTaskTemplateDto.setContent(formsPDFTaskTemplate.getContent()); - formsPDFTaskTemplateDto.setRte(formsPDFTaskTemplate.isRte()); - formsPDFTaskTemplateDto.setFormTitle(daoUtil.getString( "title" )); - formsPDFTaskTemplateDto.setFileName(formsPDFTaskTemplate.getFileName( ) ); - - return formsPDFTaskTemplateDto; - } - - private FormsPDFTaskTemplate dataToObject(DAOUtil daoUtil) - { - FormsPDFTaskTemplate formsPDFTaskTemplate = new FormsPDFTaskTemplate( ); - - formsPDFTaskTemplate.setId( daoUtil.getInt( "id_template" ) ); - formsPDFTaskTemplate.setName( daoUtil.getString( "name" ) ); - formsPDFTaskTemplate.setIdForm(daoUtil.getInt( "id_form" ) ); - formsPDFTaskTemplate.setGeneric(daoUtil.getBoolean( "is_generic" ) ); - formsPDFTaskTemplate.setContent( daoUtil.getString( "content" ) ); - formsPDFTaskTemplate.setRte( daoUtil.getBoolean( "is_rte" ) ); - formsPDFTaskTemplate.setFileName( daoUtil.getString( "file_name" ) ); - - return formsPDFTaskTemplate; - } + } + + private FormsPDFTaskTemplateDTO dataToObjectDto( DAOUtil daoUtil ) + { + FormsPDFTaskTemplate formsPDFTaskTemplate = dataToObject( daoUtil ); + FormsPDFTaskTemplateDTO formsPDFTaskTemplateDto = new FormsPDFTaskTemplateDTO( ); + formsPDFTaskTemplateDto.setId( formsPDFTaskTemplate.getId( ) ); + formsPDFTaskTemplateDto.setName( formsPDFTaskTemplate.getName( ) ); + formsPDFTaskTemplateDto.setGeneric( formsPDFTaskTemplate.isGeneric( ) ); + formsPDFTaskTemplateDto.setIdForm( formsPDFTaskTemplate.getIdForm( ) ); + formsPDFTaskTemplateDto.setContent( formsPDFTaskTemplate.getContent( ) ); + formsPDFTaskTemplateDto.setRte( formsPDFTaskTemplate.isRte( ) ); + formsPDFTaskTemplateDto.setFormTitle( daoUtil.getString( "title" ) ); + formsPDFTaskTemplateDto.setFileName( formsPDFTaskTemplate.getFileName( ) ); + formsPDFTaskTemplateDto.setReplaceEmpty( formsPDFTaskTemplate.isReplaceEmpty( ) ); + + return formsPDFTaskTemplateDto; + } + + private FormsPDFTaskTemplate dataToObject( DAOUtil daoUtil ) + { + FormsPDFTaskTemplate formsPDFTaskTemplate = new FormsPDFTaskTemplate( ); + + formsPDFTaskTemplate.setId( daoUtil.getInt( "id_template" ) ); + formsPDFTaskTemplate.setName( daoUtil.getString( "name" ) ); + formsPDFTaskTemplate.setIdForm( daoUtil.getInt( "id_form" ) ); + formsPDFTaskTemplate.setGeneric( daoUtil.getBoolean( "is_generic" ) ); + formsPDFTaskTemplate.setContent( daoUtil.getString( "content" ) ); + formsPDFTaskTemplate.setRte( daoUtil.getBoolean( "is_rte" ) ); + formsPDFTaskTemplate.setFileName( daoUtil.getString( "file_name" ) ); + formsPDFTaskTemplate.setReplaceEmpty( daoUtil.getBoolean( "is_replace_empty_response" ) ); + + return formsPDFTaskTemplate; + } } diff --git a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/resources/formspdf_messages.properties b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/resources/formspdf_messages.properties index d6615ee..71950a0 100644 --- a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/resources/formspdf_messages.properties +++ b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/resources/formspdf_messages.properties @@ -59,7 +59,9 @@ modify.template.noRTE=Edit without a rich text editor. The macros to display the modify.template.withRTE=Edit with a rich text editor. The macros to display the answers are between "[]". Example: [displayEntry q=position_1] modify.template.filename=Dynamic file name modify.template.filenameComment=You can add a dynamic part to the generated file name by using the available bookmarks. The form name and the document generation date are automatically added to the generated file name. - +modify.template.replaceEmpty=Display "N/A" for empty fields +modify.template.replaceEmpty.defaultValue=N/A + markers.label_table_title=Available bookmarks markers.label_description=Description markers.label_marker=Bookmark diff --git a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/resources/formspdf_messages_fr.properties b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/resources/formspdf_messages_fr.properties index 1f2e416..eb973a0 100644 --- a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/resources/formspdf_messages_fr.properties +++ b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/resources/formspdf_messages_fr.properties @@ -60,6 +60,8 @@ modify.template.noRTE=Sans un rich text editor. Les macros pour afficher les ré modify.template.withRTE=Avec un rich text editor. Les macros pour afficher les réponses sont entre "[]". Exemple : [@displayEntry q=position_1/] modify.template.filename=Nom du fichier modify.template.filenameComment=Vous pouvez ajouter une partie dynamique dans le nom du fichier généré en utilisant les signets disponibles. Le nom du formulaire et la date de génération du document sont automatiquement ajoutés au nom du fichier. +modify.template.replaceEmpty=Afficher "Néant" pour les champs vides +modify.template.replaceEmpty.defaultValue=Néant markers.label_table_title=Signets disponibles markers.label_description=Description diff --git a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/service/task/FormsPDFTask.java b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/service/task/FormsPDFTask.java index af5bdc4..2e821c5 100644 --- a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/service/task/FormsPDFTask.java +++ b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/service/task/FormsPDFTask.java @@ -33,9 +33,10 @@ */ package fr.paris.lutece.plugins.workflow.modules.formspdf.service.task; -import java.util.Locale; -import java.util.Map; +import java.util.*; +import fr.paris.lutece.plugins.forms.util.FormsConstants; +import org.apache.logging.log4j.util.Strings; import org.jsoup.Jsoup; import fr.paris.lutece.plugins.filegenerator.service.TemporaryFileGeneratorService; @@ -78,8 +79,10 @@ public class FormsPDFTask extends Task */ private static final String PROPERTY_LABEL_TITLE = "module.workflow.formspdf.title"; private static final String PROPERTY_LABEL_DESCRIPTION = "module.workflow.formspdf.export.pdf.description"; + private static final String EMPTY_RESPONSE_VALUE = "module.workflow.formspdf.modify.template.replaceEmpty.defaultValue"; private static final String FTL_SQUARE_BRACKET_TAG = "[#ftl]"; + /** * the FormJasperConfigService to manage the task configuration */ @@ -92,7 +95,7 @@ public class FormsPDFTask extends Task */ @Inject private IResourceHistoryService _resourceHistoryService; - + /** * the TemporaryFileGeneratorService to generate the temporary file */ @@ -116,6 +119,8 @@ public void processTask( int nIdResourceHistory, HttpServletRequest request, Loc FormsPDFTaskTemplate formsPDFTaskTemplate = null; try { + Locale currentLocale = null != locale ? locale : LocaleService.getContextUserLocale( request ); + nIdFormResponse = resourceHistory.getIdResource( ); FormResponse frep = FormResponseHome.findByPrimaryKey( nIdFormResponse ); @@ -128,16 +133,20 @@ public void processTask( int nIdResourceHistory, HttpServletRequest request, Loc } FormResponse formResponse = FormResponseHome.findByPrimaryKey( nIdFormResponse ); Map model = GenericFormsProvider.getValuesModel( formResponse, request, false ); - removeNullEntries ( model ); - + removeNullEntries( model ); + formsPDFTaskTemplate = FormsPDFTaskTemplateHome.findByPrimaryKey( formsPDFTaskConfig.getIdTemplate( ) ); - + + if ( formsPDFTaskTemplate.isReplaceEmpty( ) ) + { + replaceNullEntries( model, currentLocale ); + } + if ( formsPDFTaskTemplate.isRte( ) ) { formsPDFTaskTemplate.setContent( addSquareBracketTag( formsPDFTaskTemplate.getContent( ) ) ); } - Locale currentLocale = null != locale ? locale : LocaleService.getContextUserLocale( request ); String pdfFileName = ""; String templatePdfFileName = formsPDFTaskTemplate.getFileName( ); if ( null != templatePdfFileName && !"".equals( templatePdfFileName ) ) @@ -154,24 +163,27 @@ public void processTask( int nIdResourceHistory, HttpServletRequest request, Loc } catch( Exception e ) { - AppLogService.error( "FormsPDFTask, invalid file_name {} for template {}", ( ) -> templatePdfFileName, ( ) -> formsPDFTaskConfig.getIdTemplate( ) ); + AppLogService.error( "FormsPDFTask, invalid file_name {} for template {}", ( ) -> templatePdfFileName, + ( ) -> formsPDFTaskConfig.getIdTemplate( ) ); } if ( 0 < pdfFileName.length( ) ) { pdfFileName = "_" + pdfFileName; } } - - formsPDFTaskTemplate.setContent(AppTemplateService.getTemplateFromStringFtl(formsPDFTaskTemplate.getContent(), currentLocale, model).getHtml()); - HtmlToPDFGenerator htmltopdf = new HtmlToPDFGenerator( form.getTitle( ) + pdfFileName, I18nService.getLocalizedString( PROPERTY_LABEL_DESCRIPTION, locale ), frep, - formsPDFTaskTemplate ); + + formsPDFTaskTemplate + .setContent( AppTemplateService.getTemplateFromStringFtl( formsPDFTaskTemplate.getContent( ), currentLocale, model ).getHtml( ) ); + HtmlToPDFGenerator htmltopdf = new HtmlToPDFGenerator( form.getTitle( ) + pdfFileName, + I18nService.getLocalizedString( PROPERTY_LABEL_DESCRIPTION, locale ), frep, formsPDFTaskTemplate ); _temporaryFileGeneratorService.generateFile( htmltopdf, user ); } catch( Exception e ) { // print the error in a pdf - formsPDFTaskTemplate.setContent( e.getMessage()); - HtmlToPDFGenerator htmltopdf = new HtmlToPDFGenerator( "error", I18nService.getLocalizedString( PROPERTY_LABEL_DESCRIPTION, locale ), new FormResponse(), formsPDFTaskTemplate ); + formsPDFTaskTemplate.setContent( e.getMessage( ) ); + HtmlToPDFGenerator htmltopdf = new HtmlToPDFGenerator( "error", I18nService.getLocalizedString( PROPERTY_LABEL_DESCRIPTION, locale ), + new FormResponse( ), formsPDFTaskTemplate ); _temporaryFileGeneratorService.generateFile( htmltopdf, user ); throw new RuntimeException( strError, e ); } @@ -211,38 +223,60 @@ public void doRemoveConfig( ) } /** - * remove null values from the model + * remove null values from the model * * @param model - * @param collectionMarkersValue - * @param key + * the model containing the form question responses, mutated in place */ private void removeNullEntries( Map model ) { - model.entrySet().removeIf( e -> - { - if ( e.getKey( ).contains( "position_" ) ) - { - FormQuestionResponse formQuestionResponse = (FormQuestionResponse) model.get( e.getKey( ) ); - return ( formQuestionResponse == null || formQuestionResponse.getQuestion().getEntry() == null ) ; - } - else - { - return false; - } - }); + model.entrySet( ).removeIf( e -> { + if ( e.getKey( ).startsWith( FormsConstants.MARK_POSITION ) ) + { + FormQuestionResponse formQuestionResponse = (FormQuestionResponse) model.get( e.getKey( ) ); + return ( formQuestionResponse == null || formQuestionResponse.getQuestion( ).getEntry( ) == null ); + } + else + { + return false; + } + } ); } + /** + * Replaces empty response values in the model with a localized default label (e.g. "N/A"), for keys identifying a question by its code ("code_*"). + * + * @param model + * the model containing the form question responses, mutated in place + * @param currentLocale + * the locale used to resolve the default label + */ + private void replaceNullEntries( Map model, Locale currentLocale ) + { + model.forEach( ( key, value ) -> { + if ( key.startsWith( FormsConstants.MARK_CODE ) ) + { + FormQuestionResponse formQuestionResponse = (FormQuestionResponse) model.get( key ); + Optional.ofNullable( formQuestionResponse ).map( FormQuestionResponse::getEntryResponse ).orElse( List.of( ) ).forEach( response -> { + if ( Strings.isEmpty( response.getResponseValue( ) ) ) + { + response.setResponseValue( I18nService.getLocalizedString( EMPTY_RESPONSE_VALUE, currentLocale ) ); + } + } ); + } + } ); + } /** * Add square bracket tag at the beginning of the template to process the template with the brackets included in the RTE + * * @param strtemplate * @return */ - private String addSquareBracketTag(String strtemplate) + private String addSquareBracketTag( String strtemplate ) { - strtemplate = FTL_SQUARE_BRACKET_TAG + strtemplate; + strtemplate = FTL_SQUARE_BRACKET_TAG + strtemplate; return strtemplate; } diff --git a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/web/task/FormsPDFTaskTemplateJspBean.java b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/web/task/FormsPDFTaskTemplateJspBean.java index bee7509..84061e5 100644 --- a/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/web/task/FormsPDFTaskTemplateJspBean.java +++ b/src/java/fr/paris/lutece/plugins/workflow/modules/formspdf/web/task/FormsPDFTaskTemplateJspBean.java @@ -62,6 +62,7 @@ import fr.paris.lutece.portal.util.mvc.commons.annotations.View; import fr.paris.lutece.portal.web.cdi.mvc.Models; import fr.paris.lutece.portal.web.constants.Messages; +import org.apache.commons.text.StringEscapeUtils; @RequestScoped @Named @@ -69,24 +70,24 @@ public class FormsPDFTaskTemplateJspBean extends MVCAdminJspBean { - private static final long serialVersionUID = 1L; - - public static final int DEFAULT_ID_VALUE = NumberUtils.BYTE_MINUS_ONE; - - // Templates - private static final String TEMPLATE_MANAGE_FORMS_PDF_TEMPLATES = "/admin/plugins/workflow/modules/formspdf/manage_forms_pdf_templates.html"; - private static final String TEMPLATE_MODIFY_FORMS_PDF_TEMPLATE = "/admin/plugins/workflow/modules/formspdf/modify_forms_pdf_template.html"; - private static final String TEMPLATE_MARKER_DESCRIPTIONS = "/admin/plugins/workflow/modules/formspdf/formspdf_marker_descriptions.html"; - - // Views + private static final long serialVersionUID = 1L; + + public static final int DEFAULT_ID_VALUE = NumberUtils.BYTE_MINUS_ONE; + + // Templates + private static final String TEMPLATE_MANAGE_FORMS_PDF_TEMPLATES = "/admin/plugins/workflow/modules/formspdf/manage_forms_pdf_templates.html"; + private static final String TEMPLATE_MODIFY_FORMS_PDF_TEMPLATE = "/admin/plugins/workflow/modules/formspdf/modify_forms_pdf_template.html"; + private static final String TEMPLATE_MARKER_DESCRIPTIONS = "/admin/plugins/workflow/modules/formspdf/formspdf_marker_descriptions.html"; + + // Views private static final String VIEW_MANAGE_TEMPLATES = "manageTemplates"; private static final String VIEW_MODIFY_TEMPLATE = "modifyTemplate"; - + // Actions private static final String ACTION_MODIFY_TEMPLATE = "modifyTemplate"; private static final String ACTION_REMOVE_TEMPLATE = "removeTemplate"; - private static final String ACTION_GET_MARKER_DESCRIPTIONS = "getMarkerDescriptions"; - + private static final String ACTION_GET_MARKER_DESCRIPTIONS = "getMarkerDescriptions"; + // Parameters private static final String PARAMETER_TASK_ID = "task_id"; private static final String PARAMETER_TEMPLATE_ID = "template_id"; @@ -94,210 +95,212 @@ public class FormsPDFTaskTemplateJspBean extends MVCAdminJspBean private static final String PARAMETER_TEMPLATE_ID_FORM = "template_id_form"; private static final String PARAMETER_TEMPLATE_ASSOCIATE_FORM = "template_associate_form"; private static final String PARAMETER_TEMPLATE_CONTENT = "template_content"; - private static final String PARAMETER_RICH_TEXT_EDITOR = "rte"; - private static final String PARAMETER_TEMPLATE_FILE_NAME = "template_filename"; + private static final String PARAMETER_RICH_TEXT_EDITOR = "rte"; + private static final String PARAMETER_TEMPLATE_FILE_NAME = "template_filename"; + private static final String PARAMETER_TEMPLATE_REPLACE_EMPTY = "checkbox_replaceEmpty"; - // Markers - private static final String MARK_RICH_TEXT_EDITOR = "rte"; + // Markers + private static final String MARK_RICH_TEXT_EDITOR = "rte"; private static final String MARK_TEMPLATE_PDF_LIST = "template_pdf_list"; private static final String MARK_FORMS_PDF_TASK_TEMPLATE = "forms_pdf_task_template"; private static final String MARK_TASK_ID = "task_id"; private static final String MARK_LIST_MARKERS = "list_markers"; private static final String MARK_FORMS_LIST = "forms_list"; - //Properties + // Properties + + private static final String PROPERTY_PAGE_TITLE_MANAGE_FORMS_PDF_TEMPLATES = "module.workflow.formspdf.manage.template.title"; + private static final String PROPERTY_PAGE_TITLE_MODIFY_FORMS_PDF_TEMPLATES = "module.workflow.formspdf.modify.template.title"; + + @Inject + private Models model; - private static final String PROPERTY_PAGE_TITLE_MANAGE_FORMS_PDF_TEMPLATES = "module.workflow.formspdf.manage.template.title"; - private static final String PROPERTY_PAGE_TITLE_MODIFY_FORMS_PDF_TEMPLATES = "module.workflow.formspdf.modify.template.title"; - - @Inject - private Models model; - @View( value = VIEW_MANAGE_TEMPLATES, defaultView = true ) public String getManageTemplates( HttpServletRequest request ) - { - model.put( MARK_TASK_ID, NumberUtils.toInt( request.getParameter( PARAMETER_TASK_ID ), DEFAULT_ID_VALUE ) ); + { + model.put( MARK_TASK_ID, NumberUtils.toInt( request.getParameter( PARAMETER_TASK_ID ), DEFAULT_ID_VALUE ) ); model.put( MARK_TEMPLATE_PDF_LIST, FormsPDFTaskTemplateHome.findAllWithFormTitles( ) ); - return getPage( PROPERTY_PAGE_TITLE_MANAGE_FORMS_PDF_TEMPLATES, TEMPLATE_MANAGE_FORMS_PDF_TEMPLATES, model ); + return getPage( PROPERTY_PAGE_TITLE_MANAGE_FORMS_PDF_TEMPLATES, TEMPLATE_MANAGE_FORMS_PDF_TEMPLATES, model ); } - + @View( value = VIEW_MODIFY_TEMPLATE ) public String getModifyTemplate( HttpServletRequest request ) { - FormsPDFTaskTemplate formsPDFTaskTemplate = null; - int nIdTemplate = NumberUtils.toInt( request.getParameter( PARAMETER_TEMPLATE_ID ), DEFAULT_ID_VALUE ); - if ( nIdTemplate > 0 ) - { - formsPDFTaskTemplate = FormsPDFTaskTemplateHome.findByPrimaryKey( nIdTemplate ); - } - else - { - formsPDFTaskTemplate = new FormsPDFTaskTemplate( ); - formsPDFTaskTemplate.setGeneric (true ); - formsPDFTaskTemplate.setRte( true ); - } - Boolean isRichTextEditor = Boolean.parseBoolean( request.getParameter( PARAMETER_RICH_TEXT_EDITOR ) ); - if(request.getParameter( PARAMETER_RICH_TEXT_EDITOR ) == null) - { - isRichTextEditor = formsPDFTaskTemplate.isRte( ); - } - model.put( MARK_RICH_TEXT_EDITOR, isRichTextEditor ); - // format the content - if ( isRichTextEditor ) - { - if( !formsPDFTaskTemplate.isRte( ) ) - { - formsPDFTaskTemplate.setContent( convertMacroToSquareBrackets( formsPDFTaskTemplate.getContent( ) ) ); - } - } - else - { - if( formsPDFTaskTemplate.isRte( ) ) - { - formsPDFTaskTemplate.setContent( convertMacroToSuppMinor( formsPDFTaskTemplate.getContent( ) ) ); - } - } - model.put( MARK_FORMS_PDF_TASK_TEMPLATE, formsPDFTaskTemplate ); - - model.put( MARK_FORMS_LIST, getFormsList( ) ); - - // markers - Form form = FormHome.findByPrimaryKey( formsPDFTaskTemplate.getIdForm( ) ); - model.put( MARK_LIST_MARKERS, GenericFormsProvider.getProviderMarkerDescriptions( form != null ? form : new Form( ) ) ); - model.put( MARK_TASK_ID, NumberUtils.toInt( request.getParameter(PARAMETER_TASK_ID), DEFAULT_ID_VALUE ) ); - - return getPage( PROPERTY_PAGE_TITLE_MODIFY_FORMS_PDF_TEMPLATES, TEMPLATE_MODIFY_FORMS_PDF_TEMPLATE, model ); - } - + FormsPDFTaskTemplate formsPDFTaskTemplate = null; + int nIdTemplate = NumberUtils.toInt( request.getParameter( PARAMETER_TEMPLATE_ID ), DEFAULT_ID_VALUE ); + if ( nIdTemplate > 0 ) + { + formsPDFTaskTemplate = FormsPDFTaskTemplateHome.findByPrimaryKey( nIdTemplate ); + } + else + { + formsPDFTaskTemplate = new FormsPDFTaskTemplate( ); + formsPDFTaskTemplate.setGeneric( true ); + formsPDFTaskTemplate.setRte( true ); + } + Boolean isRichTextEditor = Boolean.parseBoolean( request.getParameter( PARAMETER_RICH_TEXT_EDITOR ) ); + if ( request.getParameter( PARAMETER_RICH_TEXT_EDITOR ) == null ) + { + isRichTextEditor = formsPDFTaskTemplate.isRte( ); + } + model.put( MARK_RICH_TEXT_EDITOR, isRichTextEditor ); + // format the content + if ( isRichTextEditor ) + { + if ( !formsPDFTaskTemplate.isRte( ) ) + { + formsPDFTaskTemplate.setContent( convertMacroToSquareBrackets( formsPDFTaskTemplate.getContent( ) ) ); + } + } + else + { + if ( formsPDFTaskTemplate.isRte( ) ) + { + formsPDFTaskTemplate.setContent( convertMacroToSuppMinor( formsPDFTaskTemplate.getContent( ) ) ); + } + } + model.put( MARK_FORMS_PDF_TASK_TEMPLATE, formsPDFTaskTemplate ); + + model.put( MARK_FORMS_LIST, getFormsList( ) ); + + // markers + Form form = FormHome.findByPrimaryKey( formsPDFTaskTemplate.getIdForm( ) ); + model.put( MARK_LIST_MARKERS, GenericFormsProvider.getProviderMarkerDescriptions( form != null ? form : new Form( ) ) ); + model.put( MARK_TASK_ID, NumberUtils.toInt( request.getParameter( PARAMETER_TASK_ID ), DEFAULT_ID_VALUE ) ); + + return getPage( PROPERTY_PAGE_TITLE_MODIFY_FORMS_PDF_TEMPLATES, TEMPLATE_MODIFY_FORMS_PDF_TEMPLATE, model ); + } + @Action( value = ACTION_MODIFY_TEMPLATE ) public String doModifyTemplate( HttpServletRequest request ) { - if ( StringUtils.isBlank( request.getParameter( PARAMETER_TEMPLATE_CONTENT ) ) ) - { - addError( Messages.MANDATORY_FIELDS, getLocale( ) ); - return getModifyTemplate( request ); - } - - int nIdTemplate = NumberUtils.toInt( request.getParameter( PARAMETER_TEMPLATE_ID ), DEFAULT_ID_VALUE ); - FormsPDFTaskTemplate formsPDFTaskTemplateToEdit = FormsPDFTaskTemplateHome.findByPrimaryKey( nIdTemplate ); - - if ( formsPDFTaskTemplateToEdit == null ) - { - formsPDFTaskTemplateToEdit = new FormsPDFTaskTemplate( ); - populateFormsPDFTaskTemplate( request, formsPDFTaskTemplateToEdit ); - FormsPDFTaskTemplateHome.create( formsPDFTaskTemplateToEdit ); - } - else - { - populateFormsPDFTaskTemplate( request, formsPDFTaskTemplateToEdit ); - FormsPDFTaskTemplateHome.update( formsPDFTaskTemplateToEdit ); - } - - Map mapParameters = new LinkedHashMap<>( ); + if ( StringUtils.isBlank( request.getParameter( PARAMETER_TEMPLATE_CONTENT ) ) ) + { + addError( Messages.MANDATORY_FIELDS, getLocale( ) ); + return getModifyTemplate( request ); + } + + int nIdTemplate = NumberUtils.toInt( request.getParameter( PARAMETER_TEMPLATE_ID ), DEFAULT_ID_VALUE ); + FormsPDFTaskTemplate formsPDFTaskTemplateToEdit = FormsPDFTaskTemplateHome.findByPrimaryKey( nIdTemplate ); + + if ( formsPDFTaskTemplateToEdit == null ) + { + formsPDFTaskTemplateToEdit = new FormsPDFTaskTemplate( ); + populateFormsPDFTaskTemplate( request, formsPDFTaskTemplateToEdit ); + FormsPDFTaskTemplateHome.create( formsPDFTaskTemplateToEdit ); + } + else + { + populateFormsPDFTaskTemplate( request, formsPDFTaskTemplateToEdit ); + FormsPDFTaskTemplateHome.update( formsPDFTaskTemplateToEdit ); + } + + Map mapParameters = new LinkedHashMap<>( ); mapParameters.put( PARAMETER_TASK_ID, request.getParameter( PARAMETER_TASK_ID ) ); - return redirect( request, VIEW_MANAGE_TEMPLATES, mapParameters ); + return redirect( request, VIEW_MANAGE_TEMPLATES, mapParameters ); } - + @Action( value = ACTION_REMOVE_TEMPLATE ) public String doRemoveTemplate( HttpServletRequest request ) { - int nIdTemplate = NumberUtils.toInt( request.getParameter( PARAMETER_TEMPLATE_ID ), DEFAULT_ID_VALUE ); - - if (nIdTemplate > DEFAULT_ID_VALUE) - { - FormsPDFTaskTemplateHome.remove(nIdTemplate); - } - - Map mapParameters = new LinkedHashMap<>( ); + int nIdTemplate = NumberUtils.toInt( request.getParameter( PARAMETER_TEMPLATE_ID ), DEFAULT_ID_VALUE ); + + if ( nIdTemplate > DEFAULT_ID_VALUE ) + { + FormsPDFTaskTemplateHome.remove( nIdTemplate ); + } + + Map mapParameters = new LinkedHashMap<>( ); mapParameters.put( PARAMETER_TASK_ID, request.getParameter( PARAMETER_TASK_ID ) ); return redirect( request, VIEW_MANAGE_TEMPLATES, mapParameters ); } - + private FormsPDFTaskTemplate populateFormsPDFTaskTemplate( HttpServletRequest request, FormsPDFTaskTemplate formsPDFTaskTemplateToEdit ) { - formsPDFTaskTemplateToEdit.setName( request.getParameter( PARAMETER_TEMPLATE_NAME ) ); - - boolean isAssociateForm = Boolean.parseBoolean( request.getParameter(PARAMETER_TEMPLATE_ASSOCIATE_FORM ) ); - formsPDFTaskTemplateToEdit.setGeneric( !isAssociateForm ); - if ( isAssociateForm ) - { - formsPDFTaskTemplateToEdit.setIdForm ( NumberUtils.toInt( request.getParameter( PARAMETER_TEMPLATE_ID_FORM ), DEFAULT_ID_VALUE ) ); - } - else - { - formsPDFTaskTemplateToEdit.setIdForm( DEFAULT_ID_VALUE ); - } - - formsPDFTaskTemplateToEdit.setContent( request.getParameter( PARAMETER_TEMPLATE_CONTENT ) ); - formsPDFTaskTemplateToEdit.setRte( Boolean.parseBoolean( request.getParameter( PARAMETER_RICH_TEXT_EDITOR ) ) ); - formsPDFTaskTemplateToEdit.setFileName( request.getParameter( PARAMETER_TEMPLATE_FILE_NAME ) ); - - return formsPDFTaskTemplateToEdit; + formsPDFTaskTemplateToEdit.setName( request.getParameter( PARAMETER_TEMPLATE_NAME ) ); + + boolean isAssociateForm = Boolean.parseBoolean( request.getParameter( PARAMETER_TEMPLATE_ASSOCIATE_FORM ) ); + formsPDFTaskTemplateToEdit.setGeneric( !isAssociateForm ); + if ( isAssociateForm ) + { + formsPDFTaskTemplateToEdit.setIdForm( NumberUtils.toInt( request.getParameter( PARAMETER_TEMPLATE_ID_FORM ), DEFAULT_ID_VALUE ) ); + } + else + { + formsPDFTaskTemplateToEdit.setIdForm( DEFAULT_ID_VALUE ); + } + + formsPDFTaskTemplateToEdit.setContent( StringEscapeUtils.unescapeHtml4( request.getParameter( PARAMETER_TEMPLATE_CONTENT ) ) ); + formsPDFTaskTemplateToEdit.setRte( Boolean.parseBoolean( request.getParameter( PARAMETER_RICH_TEXT_EDITOR ) ) ); + formsPDFTaskTemplateToEdit.setFileName( StringEscapeUtils.unescapeHtml4( request.getParameter( PARAMETER_TEMPLATE_FILE_NAME ) ) ); + formsPDFTaskTemplateToEdit.setReplaceEmpty( Boolean.parseBoolean( request.getParameter( PARAMETER_TEMPLATE_REPLACE_EMPTY ) ) ); + + return formsPDFTaskTemplateToEdit; + } + + /** + * Convert the macro to display responses to the usual supp and minor + * + * @param strtemplate + * @return the string with the macro converted + */ + private String convertMacroToSuppMinor( String strtemplate ) + { + if ( strtemplate != null ) + { + strtemplate = strtemplate.replaceAll( "\\[@displayEntry q=position_(\\d+)/]", "<@displayEntry q=position_$1/>" ); + } + return strtemplate; + } + + /** + * Convert the macro to display responses to the square brackets + * + * @param strtemplate + * @return the string with the macro converted + */ + private String convertMacroToSquareBrackets( String strtemplate ) + { + if ( strtemplate != null ) + { + strtemplate = strtemplate.replaceAll( "<@displayEntry q=position_(\\d+)/>", "[@displayEntry q=position_$1/]" ); + } + return strtemplate; + } + + @Action( value = ACTION_GET_MARKER_DESCRIPTIONS, securityTokenDisabled = true ) + @ResponseBody + public String getMarkerDescriptions( @RequestParam( value = "form_id" ) int formId, @RequestParam( value = "rte" ) boolean rte, HttpServletRequest request ) + { + Locale locale = null; + if ( request != null ) + { + locale = request.getLocale( ); + } + + Form form = FormHome.findByPrimaryKey( formId ); + model.put( MARK_LIST_MARKERS, GenericFormsProvider.getProviderMarkerDescriptions( form != null ? form : new Form( ) ) ); + model.put( MARK_RICH_TEXT_EDITOR, rte ); + + HtmlTemplate templateMarker = AppTemplateService.getTemplate( TEMPLATE_MARKER_DESCRIPTIONS, locale, model ); + return templateMarker.getHtml( ); } - /** - * Convert the macro to display responses to the usual supp and minor - * @param strtemplate - * @return the string with the macro converted - */ - private String convertMacroToSuppMinor( String strtemplate ) - { - if( strtemplate != null ) - { - strtemplate = strtemplate.replaceAll( "\\[@displayEntry q=position_(\\d+)/]", "<@displayEntry q=position_$1/>" ); - } - return strtemplate; - } - - /** - * Convert the macro to display responses to the square brackets - * @param strtemplate - * @return the string with the macro converted - */ - private String convertMacroToSquareBrackets(String strtemplate) - { - if( strtemplate != null ) - { - strtemplate = strtemplate.replaceAll( "<@displayEntry q=position_(\\d+)/>", "[@displayEntry q=position_$1/]" ); - } - return strtemplate; - } - - @Action( value = ACTION_GET_MARKER_DESCRIPTIONS, securityTokenDisabled = true ) - @ResponseBody - public String getMarkerDescriptions( @RequestParam(value = "form_id" ) int formId, - @RequestParam(value = "rte" ) boolean rte, - HttpServletRequest request ) - { - Locale locale = null; - if( request != null ) - { - locale = request.getLocale( ); - } - - Form form = FormHome.findByPrimaryKey( formId ); - model.put( MARK_LIST_MARKERS, GenericFormsProvider.getProviderMarkerDescriptions( form != null ? form : new Form( ) ) ); - model.put( MARK_RICH_TEXT_EDITOR, rte ); - - HtmlTemplate templateMarker = AppTemplateService.getTemplate( TEMPLATE_MARKER_DESCRIPTIONS, locale, model ); - return templateMarker.getHtml( ); - } - - /** - * Get the list of forms - * - * @return a ReferenceList - */ + /** + * Get the list of forms + * + * @return a ReferenceList + */ private ReferenceList getFormsList( ) { ReferenceList formsList = FormHome.getFormsReferenceList( ); ReferenceList referenceListForms = new ReferenceList( ); - referenceListForms.addItem( FormsConstants.DEFAULT_ID_VALUE, StringUtils.EMPTY ); + referenceListForms.addItem( FormsConstants.DEFAULT_ID_VALUE, StringUtils.EMPTY ); if ( formsList != null ) { - referenceListForms.addAll( formsList ); + referenceListForms.addAll( formsList ); } return referenceListForms; diff --git a/src/sql/plugins/workflow/modules/formspdf/plugin/create_db_workflow-formspdf.sql b/src/sql/plugins/workflow/modules/formspdf/plugin/create_db_workflow-formspdf.sql index d5b77f0..0e9e6fa 100644 --- a/src/sql/plugins/workflow/modules/formspdf/plugin/create_db_workflow-formspdf.sql +++ b/src/sql/plugins/workflow/modules/formspdf/plugin/create_db_workflow-formspdf.sql @@ -21,6 +21,7 @@ CREATE TABLE workflow_task_formspdf_template ( is_generic SMALLINT DEFAULT 1 NOT NULL, content LONG VARCHAR, is_rte SMALLINT DEFAULT 0 NOT NULL, - PRIMARY KEY (id_template) + is_replace_empty_response SMALLINT DEFAULT 0 NOT NULL, + PRIMARY KEY (id_template) ) ; diff --git a/src/sql/plugins/workflow/modules/formspdf/upgrade/update_db_workflow-formspdf-2.0.1-2.0.2.sql b/src/sql/plugins/workflow/modules/formspdf/upgrade/update_db_workflow-formspdf-2.0.1-2.0.2.sql new file mode 100644 index 0000000..a337192 --- /dev/null +++ b/src/sql/plugins/workflow/modules/formspdf/upgrade/update_db_workflow-formspdf-2.0.1-2.0.2.sql @@ -0,0 +1,4 @@ +-- liquibase formatted sql +-- changeset workflow-formspdf:update_db_workflow-formspdf-2.0.1-2.0.2.sql +-- preconditions onFail:MARK_RAN onError:WARN +ALTER TABLE workflow_task_formspdf_template ADD COLUMN is_replace_empty_response SMALLINT DEFAULT 0 NOT NULL; \ No newline at end of file diff --git a/src/test/java/fr/paris/lutece/plugins/workflow/modules/formspdf/service/task/FormsPDFTaskReplaceNullEntriesTest.java b/src/test/java/fr/paris/lutece/plugins/workflow/modules/formspdf/service/task/FormsPDFTaskReplaceNullEntriesTest.java new file mode 100644 index 0000000..edb2bb5 --- /dev/null +++ b/src/test/java/fr/paris/lutece/plugins/workflow/modules/formspdf/service/task/FormsPDFTaskReplaceNullEntriesTest.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2002-2026, 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.formspdf.service.task; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import fr.paris.lutece.plugins.forms.business.FormQuestionResponse; +import fr.paris.lutece.plugins.genericattributes.business.Response; +import fr.paris.lutece.portal.service.i18n.I18nService; +import fr.paris.lutece.test.LuteceTestCase; + +/** + * Unit tests for {@link FormsPDFTask#replaceNullEntries(Map, Locale)}. The method is private, so it is invoked via reflection. + */ +public class FormsPDFTaskReplaceNullEntriesTest extends LuteceTestCase +{ + private static final Locale FR = Locale.FRENCH; + private static final String EMPTY_RESPONSE_KEY = "module.workflow.formspdf.modify.template.replaceEmpty.defaultValue"; + + /** + * Invokes the private replaceNullEntries method via reflection. + */ + @SuppressWarnings( "unchecked" ) + private void invokeReplaceNullEntries( Map model, Locale locale ) throws Exception + { + Method method = FormsPDFTask.class.getDeclaredMethod( "replaceNullEntries", Map.class, Locale.class ); + method.setAccessible( true ); + FormsPDFTask task = new FormsPDFTask( ); + method.invoke( task, model, locale ); + } + + private FormQuestionResponse buildFormQuestionResponse( String... responseValues ) + { + FormQuestionResponse fqr = new FormQuestionResponse( ); + List responses = new java.util.ArrayList<>( ); + for ( String value : responseValues ) + { + Response response = new Response( ); + response.setResponseValue( value ); + responses.add( response ); + } + fqr.setEntryResponse( responses ); + return fqr; + } + + @Test + public void testEmptyResponseValueIsReplacedByLocalizedDefault( ) throws Exception + { + Map model = new HashMap<>( ); + FormQuestionResponse fqr = buildFormQuestionResponse( "" ); + model.put( "code_question_1", fqr ); + + invokeReplaceNullEntries( model, FR ); + + String expected = I18nService.getLocalizedString( EMPTY_RESPONSE_KEY, FR ); + assertEquals( expected, fqr.getEntryResponse( ).get( 0 ).getResponseValue( ) ); + } + + @Test + public void testNullResponseValueIsReplacedByLocalizedDefault( ) throws Exception + { + Map model = new HashMap<>( ); + FormQuestionResponse fqr = buildFormQuestionResponse( (String) null ); + model.put( "code_question_1", fqr ); + + invokeReplaceNullEntries( model, FR ); + + String expected = I18nService.getLocalizedString( EMPTY_RESPONSE_KEY, FR ); + assertEquals( expected, fqr.getEntryResponse( ).get( 0 ).getResponseValue( ) ); + } + + @Test + public void testNonEmptyResponseValueIsNotModified( ) throws Exception + { + Map model = new HashMap<>( ); + FormQuestionResponse fqr = buildFormQuestionResponse( "réponse existante" ); + model.put( "code_question_1", fqr ); + + invokeReplaceNullEntries( model, FR ); + + assertEquals( "réponse existante", fqr.getEntryResponse( ).get( 0 ).getResponseValue( ) ); + } + + @Test + public void testKeysWithoutCodePrefixAreIgnored( ) throws Exception + { + Map model = new HashMap<>( ); + FormQuestionResponse fqr = buildFormQuestionResponse( "" ); + model.put( "position_1", fqr ); + + invokeReplaceNullEntries( model, FR ); + + assertEquals( "", fqr.getEntryResponse( ).get( 0 ).getResponseValue( ) ); + } + + @Test + public void testMultipleResponsesInSameQuestionAreAllProcessed( ) throws Exception + { + Map model = new HashMap<>( ); + FormQuestionResponse fqr = buildFormQuestionResponse( "", "valeur", "" ); + model.put( "code_question_multi", fqr ); + + invokeReplaceNullEntries( model, FR ); + + String expected = I18nService.getLocalizedString( EMPTY_RESPONSE_KEY, FR ); + List responses = fqr.getEntryResponse( ); + assertEquals( expected, responses.get( 0 ).getResponseValue( ) ); + assertEquals( "valeur", responses.get( 1 ).getResponseValue( ) ); + assertEquals( expected, responses.get( 2 ).getResponseValue( ) ); + } + + @Test + public void testNullFormQuestionResponseInModelDoesNotThrow( ) throws Exception + { + Map model = new HashMap<>( ); + model.put( "code_question_absent", null ); + + invokeReplaceNullEntries( model, FR ); + } + + @Test + public void testEmptyModelDoesNotThrow( ) throws Exception + { + Map model = new HashMap<>( ); + invokeReplaceNullEntries( model, FR ); + assertTrue( model.isEmpty( ) ); + } +} diff --git a/src/test/java/fr/paris/lutece/plugins/workflow/modules/formspdf/web/task/FormsPDFTaskTemplateJspBeanTest.java b/src/test/java/fr/paris/lutece/plugins/workflow/modules/formspdf/web/task/FormsPDFTaskTemplateJspBeanTest.java new file mode 100644 index 0000000..fe6e77d --- /dev/null +++ b/src/test/java/fr/paris/lutece/plugins/workflow/modules/formspdf/web/task/FormsPDFTaskTemplateJspBeanTest.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2002-2026, 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.formspdf.web.task; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; + + +import jakarta.servlet.http.HttpServletRequest; + +import org.junit.jupiter.api.Test; + +import fr.paris.lutece.plugins.workflow.modules.formspdf.business.FormsPDFTaskTemplate; +import fr.paris.lutece.test.LuteceTestCase; + +/** + * Unit tests for the private helper methods of {@link FormsPDFTaskTemplateJspBean}: populateFormsPDFTaskTemplate, convertMacroToSuppMinor, + * convertMacroToSquareBrackets. + */ +public class FormsPDFTaskTemplateJspBeanTest extends LuteceTestCase +{ + private static final String PARAMETER_TEMPLATE_NAME = "template_name"; + private static final String PARAMETER_TEMPLATE_ID_FORM = "template_id_form"; + private static final String PARAMETER_TEMPLATE_ASSOCIATE_FORM = "template_associate_form"; + private static final String PARAMETER_TEMPLATE_CONTENT = "template_content"; + private static final String PARAMETER_RICH_TEXT_EDITOR = "rte"; + private static final String PARAMETER_TEMPLATE_FILE_NAME = "template_filename"; + private static final String PARAMETER_TEMPLATE_REPLACE_EMPTY = "checkbox_replaceEmpty"; + + // ---------- Fake HttpServletRequest, no external library needed ---------- + + /** + * Builds a minimal HttpServletRequest fake backed by a parameter map. getParameter(name) returns the mapped value; every other method returns a sensible + * default (null / false / 0) since it is never used by the methods under test. + */ + private HttpServletRequest fakeRequest( Map parameters ) + { + InvocationHandler handler = ( proxy, method, args ) -> { + if ( "getParameter".equals( method.getName( ) ) && args != null && args.length == 1 ) + { + return parameters.get( (String) args [0] ); + } + Class returnType = method.getReturnType( ); + if ( returnType == boolean.class ) + { + return false; + } + if ( returnType == int.class ) + { + return 0; + } + if ( returnType == long.class ) + { + return 0L; + } + return null; + }; + return (HttpServletRequest) Proxy.newProxyInstance( getClass( ).getClassLoader( ), new Class [ ] { + HttpServletRequest.class + }, handler ); + } + + // ---------- Helpers to invoke private methods via reflection ---------- + + private FormsPDFTaskTemplate invokePopulate( HttpServletRequest request, FormsPDFTaskTemplate template ) throws Exception + { + Method method = FormsPDFTaskTemplateJspBean.class.getDeclaredMethod( "populateFormsPDFTaskTemplate", HttpServletRequest.class, + FormsPDFTaskTemplate.class ); + method.setAccessible( true ); + FormsPDFTaskTemplateJspBean jspBean = new FormsPDFTaskTemplateJspBean( ); + return (FormsPDFTaskTemplate) method.invoke( jspBean, request, template ); + } + + private String invokeConvertMacroToSuppMinor( String strTemplate ) throws Exception + { + Method method = FormsPDFTaskTemplateJspBean.class.getDeclaredMethod( "convertMacroToSuppMinor", String.class ); + method.setAccessible( true ); + FormsPDFTaskTemplateJspBean jspBean = new FormsPDFTaskTemplateJspBean( ); + return (String) method.invoke( jspBean, strTemplate ); + } + + private String invokeConvertMacroToSquareBrackets( String strTemplate ) throws Exception + { + Method method = FormsPDFTaskTemplateJspBean.class.getDeclaredMethod( "convertMacroToSquareBrackets", String.class ); + method.setAccessible( true ); + FormsPDFTaskTemplateJspBean jspBean = new FormsPDFTaskTemplateJspBean( ); + return (String) method.invoke( jspBean, strTemplate ); + } + + // ---------- populateFormsPDFTaskTemplate ---------- + + @Test + public void testPopulateWithAssociatedFormSetsIdForm( ) throws Exception + { + Map params = new HashMap<>( ); + params.put( PARAMETER_TEMPLATE_NAME, "Mon template" ); + params.put( PARAMETER_TEMPLATE_ASSOCIATE_FORM, "true" ); + params.put( PARAMETER_TEMPLATE_ID_FORM, "5" ); + params.put( PARAMETER_TEMPLATE_CONTENT, "

contenu

" ); + params.put( PARAMETER_RICH_TEXT_EDITOR, "true" ); + params.put( PARAMETER_TEMPLATE_FILE_NAME, "export.pdf" ); + params.put( PARAMETER_TEMPLATE_REPLACE_EMPTY, "true" ); + + FormsPDFTaskTemplate template = new FormsPDFTaskTemplate( ); + invokePopulate( fakeRequest( params ), template ); + + assertEquals( "Mon template", template.getName( ) ); + assertFalse( template.isGeneric( ) ); + assertEquals( 5, template.getIdForm( ) ); + assertEquals( "

contenu

", template.getContent( ) ); + assertTrue( template.isRte( ) ); + assertEquals( "export.pdf", template.getFileName( ) ); + assertTrue( template.isReplaceEmpty( ) ); + } + + @Test + public void testPopulateWithoutAssociatedFormUsesDefaultIdForm( ) throws Exception + { + Map params = new HashMap<>( ); + params.put( PARAMETER_TEMPLATE_NAME, "Générique" ); + params.put( PARAMETER_TEMPLATE_ASSOCIATE_FORM, "false" ); + params.put( PARAMETER_TEMPLATE_CONTENT, "

contenu générique

" ); + params.put( PARAMETER_RICH_TEXT_EDITOR, "false" ); + params.put( PARAMETER_TEMPLATE_FILE_NAME, "" ); + params.put( PARAMETER_TEMPLATE_REPLACE_EMPTY, "false" ); + + FormsPDFTaskTemplate template = new FormsPDFTaskTemplate( ); + invokePopulate( fakeRequest( params ), template ); + + assertTrue( template.isGeneric( ) ); + assertEquals( FormsPDFTaskTemplateJspBean.DEFAULT_ID_VALUE, template.getIdForm( ) ); + assertFalse( template.isRte( ) ); + assertFalse( template.isReplaceEmpty( ) ); + } + + @Test + public void testPopulateWithMissingReplaceEmptyParameterDefaultsToFalse( ) throws Exception + { + // Simulates an unchecked checkbox: the parameter is simply absent from the request + Map params = new HashMap<>( ); + params.put( PARAMETER_TEMPLATE_NAME, "Test" ); + params.put( PARAMETER_TEMPLATE_ASSOCIATE_FORM, "false" ); + params.put( PARAMETER_TEMPLATE_CONTENT, "contenu" ); + params.put( PARAMETER_RICH_TEXT_EDITOR, "false" ); + // PARAMETER_TEMPLATE_FILE_NAME and PARAMETER_TEMPLATE_REPLACE_EMPTY intentionally omitted + + FormsPDFTaskTemplate template = new FormsPDFTaskTemplate( ); + invokePopulate( fakeRequest( params ), template ); + + assertFalse( template.isReplaceEmpty( ) ); + } + + // ---------- convertMacroToSuppMinor ---------- + + @Test + public void testConvertMacroToSuppMinorReplacesSquareBrackets( ) throws Exception + { + String input = "reponse : [@displayEntry q=position_3/]"; + String result = invokeConvertMacroToSuppMinor( input ); + assertEquals( "reponse : <@displayEntry q=position_3/>", result ); + } + + @Test + public void testConvertMacroToSuppMinorWithNullReturnsNull( ) throws Exception + { + assertNull( invokeConvertMacroToSuppMinor( null ) ); + } + + @Test + public void testConvertMacroToSuppMinorWithNoMacroLeavesUnchanged( ) throws Exception + { + String input = "aucun signet ici"; + assertEquals( input, invokeConvertMacroToSuppMinor( input ) ); + } + + // ---------- convertMacroToSquareBrackets ---------- + + @Test + public void testConvertMacroToSquareBracketsReplacesAngleBrackets( ) throws Exception + { + String input = "reponse : <@displayEntry q=position_7/>"; + String result = invokeConvertMacroToSquareBrackets( input ); + assertEquals( "reponse : [@displayEntry q=position_7/]", result ); + } + + @Test + public void testConvertMacroToSquareBracketsWithNullReturnsNull( ) throws Exception + { + assertNull( invokeConvertMacroToSquareBrackets( null ) ); + } + + @Test + public void testRoundTripConversionIsIdempotent( ) throws Exception + { + String original = "[@displayEntry q=position_1/]"; + String converted = invokeConvertMacroToSuppMinor( original ); + String backToOriginal = invokeConvertMacroToSquareBrackets( converted ); + assertEquals( original, backToOriginal ); + } +} diff --git a/webapp/WEB-INF/templates/admin/plugins/workflow/modules/formspdf/modify_forms_pdf_template.html b/webapp/WEB-INF/templates/admin/plugins/workflow/modules/formspdf/modify_forms_pdf_template.html index f2c2238..f733142 100644 --- a/webapp/WEB-INF/templates/admin/plugins/workflow/modules/formspdf/modify_forms_pdf_template.html +++ b/webapp/WEB-INF/templates/admin/plugins/workflow/modules/formspdf/modify_forms_pdf_template.html @@ -22,6 +22,9 @@ <@select name='template_id_form' id="template_id_form" items=forms_list default_value='${(forms_pdf_task_template.idForm)!0}' /> + <@formGroup> + <@checkBox orientation='switch' labelFor='replaceEmpty' labelKey='#i18n{module.workflow.formspdf.modify.template.replaceEmpty}' name='checkbox_replaceEmpty' id='replaceEmpty' value='true' checked=(forms_pdf_task_template.replaceEmpty)!false /> + <#if rte> <@checkBox orientation='switch' labelFor='rte' labelKey='#i18n{module.workflow.formspdf.modify.template.withRTE}' id='rte' name='macro_checkbox_rte' checked=rte params='onchange="javascript:toggleRTE();"' /> <@formGroup labelFor='template_content' labelKey='#i18n{module.workflow.formspdf.modify.template.content}' mandatory=true rows=2> @@ -82,6 +85,7 @@ } } + document.getElementById("template_id_form").addEventListener("change", function() { const formId = this.value; if (!formId) return;