diff --git a/pom.xml b/pom.xml index a857a0001..96a9be43d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,18 +7,18 @@ org.springframework.boot spring-boot-starter-parent - 3.3.3 + 3.3.4 org.esupportail esup-signature - 1.29.17 + 1.30.0-SNAPSHOT esup-signature org.esupportail.esupsignature.EsupSignatureApplication 17 UTF-8 - 6.0 + 6.1 5.4.3 true false @@ -160,9 +160,9 @@ 0.59 - org.webjars.bower - google-code-prettify - 1.0.5 + org.webjars + prettify + 4-Mar-2013-1 org.webjars @@ -183,7 +183,7 @@ org.webjars.npm pdfjs-dist - 4.4.168 + 4.6.82 org.webjars.npm @@ -236,9 +236,9 @@ 3.2.5 - org.webjars.bowergithub.ajaxorg + org.webjars.npm ace-builds - 1.4.13 + 1.35.3 org.webjars @@ -303,6 +303,11 @@ dss-model ${dss.framework.version} + + eu.europa.ec.joinup.sd-dss + dss-validation + ${dss.framework.version} + eu.europa.ec.joinup.sd-dss dss-spi @@ -438,6 +443,12 @@ eu.europa.ec.joinup.sd-dss dss-pades-pdfbox ${dss.framework.version} + + + pdfbox + org.apache.pdfbox + + @@ -565,7 +576,7 @@ org.apache.pdfbox pdfbox - 2.0.31 + 2.0.32 commons-logging diff --git a/src/main/java/org/esupportail/esupsignature/dss/config/DSSBeanConfig.java b/src/main/java/org/esupportail/esupsignature/dss/config/DSSBeanConfig.java index a442e67ee..de35040fc 100644 --- a/src/main/java/org/esupportail/esupsignature/dss/config/DSSBeanConfig.java +++ b/src/main/java/org/esupportail/esupsignature/dss/config/DSSBeanConfig.java @@ -19,10 +19,16 @@ import eu.europa.esig.dss.service.ocsp.OnlineOCSPSource; import eu.europa.esig.dss.service.tsp.OnlineTSPSource; import eu.europa.esig.dss.service.x509.aia.JdbcCacheAIASource; +import eu.europa.esig.dss.spi.client.http.DSSCacheFileLoader; import eu.europa.esig.dss.spi.client.http.DSSFileLoader; import eu.europa.esig.dss.spi.client.http.IgnoreDataLoader; import eu.europa.esig.dss.spi.client.jdbc.JdbcCacheConnector; +import eu.europa.esig.dss.spi.policy.SignaturePolicyProvider; import eu.europa.esig.dss.spi.tsl.TrustedListsCertificateSource; +import eu.europa.esig.dss.spi.validation.CertificateVerifier; +import eu.europa.esig.dss.spi.validation.CommonCertificateVerifier; +import eu.europa.esig.dss.spi.validation.OCSPFirstRevocationDataLoadingStrategyFactory; +import eu.europa.esig.dss.spi.validation.RevocationDataVerifier; import eu.europa.esig.dss.spi.x509.KeyStoreCertificateSource; import eu.europa.esig.dss.spi.x509.aia.AIASource; import eu.europa.esig.dss.spi.x509.aia.DefaultAIASource; @@ -42,9 +48,6 @@ import eu.europa.esig.dss.tsl.function.OfficialJournalSchemeInformationURI; import eu.europa.esig.dss.tsl.job.TLValidationJob; import eu.europa.esig.dss.tsl.source.LOTLSource; -import eu.europa.esig.dss.validation.CertificateVerifier; -import eu.europa.esig.dss.validation.CommonCertificateVerifier; -import eu.europa.esig.dss.validation.SignaturePolicyProvider; import eu.europa.esig.dss.xades.signature.XAdESService; import eu.europa.esig.dss.xml.common.DocumentBuilderFactoryBuilder; import eu.europa.esig.dss.xml.common.SchemaFactoryBuilder; @@ -263,7 +266,7 @@ public CacheCleaner cacheCleaner(DSSFileLoader offlineLoader) { CacheCleaner cacheCleaner = new CacheCleaner(); cacheCleaner.setCleanMemory(true); cacheCleaner.setCleanFileSystem(true); - cacheCleaner.setDSSFileLoader(offlineLoader); + cacheCleaner.setDSSFileLoader((DSSCacheFileLoader) offlineLoader); return cacheCleaner; } @@ -290,13 +293,20 @@ public LOTLSource europeanLOTL(KeyStoreCertificateSource ojContentKeyStore) { } @Bean - public CertificateVerifier certificateVerifier(JdbcCacheOCSPSource jdbcCacheOCSPSource, JdbcCacheCRLSource jdbcCacheCRLSource, JdbcCacheAIASource jdbcCacheAIASource, TrustedListsCertificateSource trustedListSource) { + public RevocationDataVerifier revocationDataVerifier() { + return RevocationDataVerifier.createDefaultRevocationDataVerifier(); + } + + @Bean + public CertificateVerifier certificateVerifier(JdbcCacheOCSPSource jdbcCacheOCSPSource, JdbcCacheCRLSource jdbcCacheCRLSource, JdbcCacheAIASource jdbcCacheAIASource, TrustedListsCertificateSource trustedListSource, RevocationDataVerifier revocationDataVerifier) { CommonCertificateVerifier certificateVerifier = new CommonCertificateVerifier(); certificateVerifier.setCrlSource(jdbcCacheCRLSource); certificateVerifier.setOcspSource(jdbcCacheOCSPSource); certificateVerifier.setAIASource(jdbcCacheAIASource); certificateVerifier.setTrustedCertSources(trustedListSource); + certificateVerifier.setRevocationDataVerifier(revocationDataVerifier); certificateVerifier.setAlertOnMissingRevocationData(new ExceptionOnStatusAlert()); + certificateVerifier.setRevocationDataLoadingStrategyFactory(new OCSPFirstRevocationDataLoadingStrategyFactory()); certificateVerifier.setCheckRevocationForUntrustedChains(dssProperties.getCheckRevocationForUntrustedChains()); return certificateVerifier; } diff --git a/src/main/java/org/esupportail/esupsignature/dss/service/DSSService.java b/src/main/java/org/esupportail/esupsignature/dss/service/DSSService.java index 8cdba8898..080465257 100644 --- a/src/main/java/org/esupportail/esupsignature/dss/service/DSSService.java +++ b/src/main/java/org/esupportail/esupsignature/dss/service/DSSService.java @@ -1,10 +1,10 @@ package org.esupportail.esupsignature.dss.service; import eu.europa.esig.dss.model.identifier.Identifier; -import eu.europa.esig.dss.spi.tsl.LOTLInfo; -import eu.europa.esig.dss.spi.tsl.ParsingInfoRecord; -import eu.europa.esig.dss.spi.tsl.TLInfo; -import eu.europa.esig.dss.spi.tsl.TLValidationJobSummary; +import eu.europa.esig.dss.model.tsl.LOTLInfo; +import eu.europa.esig.dss.model.tsl.ParsingInfoRecord; +import eu.europa.esig.dss.model.tsl.TLInfo; +import eu.europa.esig.dss.model.tsl.TLValidationJobSummary; import eu.europa.esig.dss.spi.x509.CommonTrustedCertificateSource; import eu.europa.esig.dss.spi.x509.KeyStoreCertificateSource; import eu.europa.esig.dss.tsl.job.TLValidationJob; diff --git a/src/main/java/org/esupportail/esupsignature/entity/Workflow.java b/src/main/java/org/esupportail/esupsignature/entity/Workflow.java index bc37f177a..ab0c7a750 100644 --- a/src/main/java/org/esupportail/esupsignature/entity/Workflow.java +++ b/src/main/java/org/esupportail/esupsignature/entity/Workflow.java @@ -27,6 +27,8 @@ public class Workflow { @Column(columnDefinition = "TEXT") private String message; + private String mailFrom; + private Integer counter; @Temporal(TemporalType.TIMESTAMP) @@ -85,6 +87,8 @@ public class Workflow { private Boolean sealAtEnd = false; + private String signRequestParamsDetectionPattern; + @Transient private String messageToDisplay; @@ -128,6 +132,14 @@ public void setMessage(String message) { this.message = message; } + public String getMailFrom() { + return mailFrom; + } + + public void setMailFrom(String mailFrom) { + this.mailFrom = mailFrom; + } + public Integer getCounter() { return counter; } @@ -333,4 +345,12 @@ public Boolean getForbidDownloadsBeforeEnd() { public void setForbidDownloadsBeforeEnd(Boolean forbidDownloadsBeforeEnd) { this.forbidDownloadsBeforeEnd = forbidDownloadsBeforeEnd; } + + public String getSignRequestParamsDetectionPattern() { + return signRequestParamsDetectionPattern; + } + + public void setSignRequestParamsDetectionPattern(String signRequestParamsDetectionPattern) { + this.signRequestParamsDetectionPattern = signRequestParamsDetectionPattern; + } } diff --git a/src/main/java/org/esupportail/esupsignature/repository/OtpRepository.java b/src/main/java/org/esupportail/esupsignature/repository/OtpRepository.java index 96ebf7ff3..23050ab35 100644 --- a/src/main/java/org/esupportail/esupsignature/repository/OtpRepository.java +++ b/src/main/java/org/esupportail/esupsignature/repository/OtpRepository.java @@ -1,10 +1,14 @@ package org.esupportail.esupsignature.repository; import org.esupportail.esupsignature.entity.Otp; +import org.esupportail.esupsignature.entity.enums.SignRequestStatus; import org.springframework.data.repository.CrudRepository; +import java.util.List; + public interface OtpRepository extends CrudRepository { Otp findByUrlId(String url); + List findBySignBookStatus(SignRequestStatus status); } diff --git a/src/main/java/org/esupportail/esupsignature/repository/SignBookRepository.java b/src/main/java/org/esupportail/esupsignature/repository/SignBookRepository.java index 12be92d69..39d9711e1 100644 --- a/src/main/java/org/esupportail/esupsignature/repository/SignBookRepository.java +++ b/src/main/java/org/esupportail/esupsignature/repository/SignBookRepository.java @@ -52,6 +52,49 @@ and size(sb.signRequests) > 0 """) Page findByRecipientAndCreateByEppnIndexed(User user, String workflowFilter, String docTitleFilter, User creatorFilter, Date startDateFilter, Date endDateFilter, Pageable pageable); + @Query(""" + select distinct sb from SignBook sb + left join sb.team team + left join sb.signRequests sr + left join sr.recipientHasSigned rhs + left join sb.liveWorkflow lw + left join lw.liveWorkflowSteps lws + left join lws.recipients r + left join r.user u + where (:workflowFilter is null or sb.workflowName = :workflowFilter) + and (:docTitleFilter is null or sb.subject = :docTitleFilter) + and (:recipientUser is null or key(rhs).user = :recipientUser or :recipientUser in (u)) + and (:creatorFilter is null or sb.createBy = :creatorFilter) + and size(sb.signRequests) > 0 + and (sb.createDate between :startDateFilter and :endDateFilter) + """) + Page findByWorkflowName(User recipientUser, String workflowFilter, String docTitleFilter, User creatorFilter, Date startDateFilter, Date endDateFilter, Pageable pageable); + + @Query(""" + select distinct sb.subject from SignBook sb + where (:workflowFilter is null or sb.workflowName = :workflowFilter) + """) + List findByWorkflowNameSubjects(String workflowFilter); + + @Query(""" + select distinct sb.createBy from SignBook sb + where (:workflowFilter is null or sb.workflowName = :workflowFilter) + """) + List findByWorkflowNameCreators(String workflowFilter); + + @Query(""" + select distinct u from SignBook sb + left join sb.team team + left join sb.signRequests sr + left join sr.recipientHasSigned rhs + left join sb.liveWorkflow lw + left join lw.liveWorkflowSteps lws + left join lws.recipients r + left join r.user u + where (:workflowFilter is null or sb.workflowName = :workflowFilter) and u is not null + """) + List findByWorkflowNameRecipientsUsers(String workflowFilter); + @Query(""" select distinct sb from SignBook sb left join sb.team team @@ -236,6 +279,5 @@ where sr.id in (select l.signRequestId from Log as l where l.eppn = :eppn and l. Page findOnShareByEppn(String eppn, User recipientUser, String workflowFilter, String docTitleFilter, User creatorFilter, Date startDateFilter, Date endDateFilter, Pageable pageable); List findByCreateByEppn(String userEppn); - } diff --git a/src/main/java/org/esupportail/esupsignature/service/DataService.java b/src/main/java/org/esupportail/esupsignature/service/DataService.java index f592a8084..1c35fcbef 100644 --- a/src/main/java/org/esupportail/esupsignature/service/DataService.java +++ b/src/main/java/org/esupportail/esupsignature/service/DataService.java @@ -125,7 +125,7 @@ public byte[] generateFile(Data data, InputStream inputStream) throws IOExceptio if(inputStream != null && inputStream.available() > 0) { return pdfService.fill(inputStream, data.getDatas(), false, true); } else if(form.getDocument() != null) { - return pdfService.fill(pdfService.removeSignField(form.getDocument().getInputStream()), data.getDatas(), false, true); + return pdfService.fill(pdfService.removeSignField(form.getDocument().getInputStream(), data.getForm().getWorkflow()), data.getDatas(), false, true); } else { logger.error("no pdf model"); } diff --git a/src/main/java/org/esupportail/esupsignature/service/FormService.java b/src/main/java/org/esupportail/esupsignature/service/FormService.java index fc849d940..dc336ab8f 100644 --- a/src/main/java/org/esupportail/esupsignature/service/FormService.java +++ b/src/main/java/org/esupportail/esupsignature/service/FormService.java @@ -2,7 +2,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.cos.COSString; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.interactive.action.PDAction; @@ -315,8 +317,10 @@ private List getFields(InputStream inputStream, Workflow workflow) throws PDAnnotationAdditionalActions pdAnnotationAdditionalActions = pdAnnotationWidget.getActions(); if (pdAnnotationAdditionalActions != null && pdAnnotationAdditionalActions.getCOSObject().size() > 0) { if (pdAnnotationAdditionalActions.getCOSObject().getCOSObject(COSName.K) != null) { - COSString cosString = (COSString) pdAnnotationAdditionalActions.getCOSObject().getCOSObject(COSName.K).getItem(COSName.JS); - type = cosString.toString(); + COSObject cosObject = pdAnnotationAdditionalActions.getCOSObject().getCOSObject(COSName.K); + if(cosObject.getObject() instanceof COSDictionary cosDictionary) { + type = ((COSString) cosDictionary.getDictionaryObject(COSName.JS)).toString(); + } } } if (type == null || type.equals("text")) { @@ -466,7 +470,7 @@ public Set
getManagerForms(String userEppn) { @Transactional public void updateSignRequestParams(Long formId, InputStream inputStream) { Form form = getById(formId); - List findedSignRequestParams = signRequestParamsService.scanSignatureFields(inputStream, 0); + List findedSignRequestParams = signRequestParamsService.scanSignatureFields(inputStream, 0, form.getWorkflow()); if(!findedSignRequestParams.isEmpty()) { form.getSignRequestParams().clear(); int i = 0; diff --git a/src/main/java/org/esupportail/esupsignature/service/SignBookService.java b/src/main/java/org/esupportail/esupsignature/service/SignBookService.java index 4ddf0761d..3067d54dc 100644 --- a/src/main/java/org/esupportail/esupsignature/service/SignBookService.java +++ b/src/main/java/org/esupportail/esupsignature/service/SignBookService.java @@ -33,17 +33,11 @@ import org.esupportail.esupsignature.service.utils.sign.SignService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.support.MutableSortDefinition; -import org.springframework.beans.support.PropertyComparator; -import org.springframework.beans.support.SortDefinition; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.MessageSource; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; @@ -190,6 +184,36 @@ public Long nbToSignSignBooks(String userEppn) { return signBookRepository.countToSign(user); } + @Transactional + public Page getSignBooksForManagers(String userEppn, String authUserEppn, String statusFilter, String recipientsFilter, String workflowFilter, String docTitleFilter, String creatorFilter, String dateFilter, Pageable pageable) { + User creatorFilterUser = null; + if(creatorFilter != null) { + creatorFilterUser = userService.getByEppn(creatorFilter); + } + User userFilter = null; + if(recipientsFilter != null && !recipientsFilter.equals("%") && !recipientsFilter.isEmpty()) { + userFilter = userService.getByEppn(recipientsFilter); + } + Calendar calendar = Calendar.getInstance(); + calendar.set(9999, Calendar.DECEMBER, 31); + Date startDateFilter = new Date(0); + Date endDateFilter = calendar.getTime(); + if(dateFilter != null && !dateFilter.isEmpty()) { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + try { + Date formattedDate = formatter.parse(dateFilter); + LocalDateTime nowLocalDateTime = formattedDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); + LocalDateTime startLocalDateTime = nowLocalDateTime.with(LocalTime.of(0, 0, 0)); + LocalDateTime endLocalDateTime = nowLocalDateTime.with(LocalTime.of(23, 59, 59)); + startDateFilter = Timestamp.valueOf(startLocalDateTime); + endDateFilter = Timestamp.valueOf(endLocalDateTime); + } catch (ParseException e) { + logger.error("unable to parse date : " + dateFilter); + } + } + return signBookRepository.findByWorkflowName(userFilter, workflowFilter, docTitleFilter, creatorFilterUser, startDateFilter, endDateFilter, pageable); + } + @Transactional public Page getSignBooks(String userEppn, String authUserEppn, String statusFilter, String recipientsFilter, String workflowFilter, String docTitleFilter, String creatorFilter, String dateFilter, Pageable pageable) { User user = userService.getByEppn(userEppn); @@ -580,6 +604,9 @@ public void restore(Long signBookId, String userEppn) { signRequest.setDeleted(false); signRequest.getParentSignBook().setDeleted(false); logService.create(signRequest.getId(), signRequest.getParentSignBook().getSubject(), signRequest.getParentSignBook().getWorkflowName(), signRequest.getStatus(), "Restauration par l'utilisateur", null, "SUCCESS", null, null, null, null, userEppn, userEppn); + for (Target target : signRequest.getParentSignBook().getLiveWorkflow().getTargets().stream().filter(t -> t != null && fsAccessFactoryService.getPathIOType(t.getTargetUri()).equals(DocumentIOType.rest)).collect(Collectors.toList())) { + targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), "restored", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber().toString(), userEppn, ""); + } } } } @@ -1230,6 +1257,9 @@ public void refuse(Long signRequestId, String comment, String userEppn, String a if(signBook.getSignRequests().size() > 1 && (signBook.getForceAllDocsSign() == null || !signBook.getForceAllDocsSign())) { commentService.create(signRequest.getId(), comment, 0, 0, 0, null, true, "#FF7EB9", userEppn); signRequestService.updateStatus(signRequest.getId(), SignRequestStatus.refused, "Refusé", null, "SUCCESS", null, null, null, signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber(), userEppn, authUserEppn); + for (Target target : signRequest.getParentSignBook().getLiveWorkflow().getTargets().stream().filter(t -> t != null && fsAccessFactoryService.getPathIOType(t.getTargetUri()).equals(DocumentIOType.rest)).collect(Collectors.toList())) { + targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), "refused", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber().toString(), authUserEppn, comment); + } for (Recipient recipient : signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getRecipients()) { if (recipient.getUser().getEppn().equals(userEppn)) { Action action = signRequest.getRecipientHasSigned().get(recipient); @@ -1260,6 +1290,9 @@ public void refuse(Long signRequestId, String comment, String userEppn, String a } } else { refuseSignBook(signRequest.getParentSignBook(), comment, userEppn, authUserEppn); + for (Target target : signRequest.getParentSignBook().getLiveWorkflow().getTargets().stream().filter(t -> t != null && fsAccessFactoryService.getPathIOType(t.getTargetUri()).equals(DocumentIOType.rest)).collect(Collectors.toList())) { + targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), "refused", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber().toString(), authUserEppn, comment); + } } } @@ -1291,7 +1324,7 @@ public List startWorkflow(Long id, MultipartFile[] multipartFiles, String @Transactional public void addWorkflowToSignBook(SignBook signBook, String authUserEppn, Long workflowSignBookId) throws EsupSignatureRuntimeException { Workflow workflow = workflowService.getById(workflowSignBookId); - importWorkflow(signBook, workflow, null); + importWorkflow(signBook, workflow, new ArrayList<>()); signRequestService.nextWorkFlowStep(signBook); pendingSignBook(signBook.getId(), null, authUserEppn, authUserEppn, false, true); } @@ -1344,8 +1377,6 @@ public int importFilesFromSource(Long workflowId, User user, User authUser) thro user = userService.getByEppn(fsFile.getCreateBy()); } signRequestService.addDocsToSignRequest(signRequest, true, j, new ArrayList<>(), new DssMultipartFile(fsFile.getName(), fsFile.getName(), fsFile.getContentType(), baos.toByteArray())); - fsAccessService.remove(fsFile); - j++; if (workflow.getScanPdfMetadatas()) { String signType = metadatas.get("sign_type_default_val"); User creator = userService.createUserWithEppn(metadatas.get("Creator")); @@ -1389,10 +1420,12 @@ public int importFilesFromSource(Long workflowId, User user, User authUser) thro logger.info("target set to : " + new ArrayList<>(signBook.getLiveWorkflow().getTargets()).get(0).getTargetUri()); } } + j++; } else { targetService.copyTargets(workflow.getTargets(), signBook, null); - importWorkflow(signBook, workflow, null); + importWorkflow(signBook, workflow, new ArrayList<>()); } + fsAccessService.remove(fsFile); nextStepAndPending(signBook.getId(), null, user.getEppn(), authUser.getEppn()); nbImportedFiles++; } @@ -1607,14 +1640,9 @@ public void sendSignRequestsToTarget(Long id, String authUserEppn) throws EsupSi status = SignRequestStatus.refused; } try { - ResponseEntity response = targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), status.name(), "end"); - if (response.getStatusCode().equals(HttpStatus.OK)) { - target.setTargetOk(true); - signRequestService.updateStatus(signRequest.getId(), signRequest.getStatus(), "Exporté vers " + targetUrl, null, "SUCCESS", null, null, null, null, authUserEppn, authUserEppn); - } else { - logger.error("rest export fail : " + target.getTargetUri() + " return is : " + response.getStatusCode()); - allTargetsDone = false; - } + targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), status.name(), "end", authUserEppn, ""); + target.setTargetOk(true); + signRequestService.updateStatus(signRequest.getId(), signRequest.getStatus(), "Exporté vers " + targetUrl, null, "SUCCESS", null, null, null, null, authUserEppn, authUserEppn); } catch (Exception e) { logger.error("rest export fail : " + target.getTargetUri(), e); allTargetsDone = false; @@ -1867,40 +1895,6 @@ public List getCreators(String userEppn, String workflowFilter, String doc return signBookRepository.findUserByRecipientAndCreateBy(user, workflowFilter, docTitleFilter, creatorFilterUser); } - public Page getSignBookByWorkflow(Workflow workflow, String statusFilter, String recipientsFilter, String creatorFilter, String dateFilter, Pageable pageable) { - List signBooks = getByWorkflowId(workflow.getId()); - if(StringUtils.hasText(statusFilter)) { - signBooks = signBooks.stream().filter(signBook -> signBook.getStatus().equals(SignRequestStatus.valueOf(statusFilter))).collect(Collectors.toList()); - } - if(!creatorFilter.equals("%")) { - signBooks = signBooks.stream().filter(signBook -> signBook.getCreateBy().getEppn().equals(creatorFilter)).collect(Collectors.toList()); - } - if(!recipientsFilter.equals("%")) { - signBooks = signBooks.stream().filter(signBook -> signBook.getSignRequests().get(0).getRecipientHasSigned().keySet().stream().anyMatch(recipient -> recipient.getUser().getEppn().equals(recipientsFilter))).collect(Collectors.toList()); - } - if(dateFilter != null && !dateFilter.isEmpty()) { - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - try { - Date formattedDate = formatter.parse(dateFilter); - LocalDateTime nowLocalDateTime = formattedDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(); - LocalDateTime startLocalDateTime = nowLocalDateTime.with(LocalTime.of(0, 0, 0)); - LocalDateTime endLocalDateTime = nowLocalDateTime.with(LocalTime.of(23, 59, 59)); - Date startDateFilter = Timestamp.valueOf(startLocalDateTime); - Date endDateFilter = Timestamp.valueOf(endLocalDateTime); - signBooks = signBooks.stream().filter(signBook -> signBook.getCreateDate().after(startDateFilter) && signBook.getCreateDate().before(endDateFilter)).collect(Collectors.toList()); - } catch (ParseException e) { - logger.error("unable to parse date : " + dateFilter); - } - } - if(pageable.getSort().iterator().hasNext()) { - Sort.Order order = pageable.getSort().iterator().next(); - SortDefinition sortDefinition = new MutableSortDefinition(order.getProperty(), true, order.getDirection().isAscending()); - PropertyComparator propertyComparator = new PropertyComparator<>(sortDefinition); - signBooks.sort(propertyComparator); - } - return new PageImpl<>(signBooks.stream().skip(pageable.getOffset()).limit(pageable.getPageSize()).collect(Collectors.toList()), pageable, signBooks.size()); - } - public List getSignBookForUsers(String userEppn) { User user = userService.getByEppn(userEppn); return signBookRepository.findByTeamContaining(user); @@ -2043,4 +2037,16 @@ public void addToTeam(SignBook signBook, String userEppn) { signBook.getTeam().add(user); } } + + public List getSignBooksForManagersSubjects(String workflowFilter) { + return signBookRepository.findByWorkflowNameSubjects(workflowFilter); + } + + public List getSignBooksForManagersCreators(String workflowFilter) { + return signBookRepository.findByWorkflowNameCreators(workflowFilter); + } + + public List getSignBooksForManagersRecipientsUsers(String workflowFilter) { + return signBookRepository.findByWorkflowNameRecipientsUsers(workflowFilter); + } } diff --git a/src/main/java/org/esupportail/esupsignature/service/SignRequestParamsService.java b/src/main/java/org/esupportail/esupsignature/service/SignRequestParamsService.java index e9147970a..d0d3210de 100644 --- a/src/main/java/org/esupportail/esupsignature/service/SignRequestParamsService.java +++ b/src/main/java/org/esupportail/esupsignature/service/SignRequestParamsService.java @@ -2,15 +2,23 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageTree; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; -import org.apache.pdfbox.pdmodel.interactive.form.*; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDField; +import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField; import org.esupportail.esupsignature.config.GlobalProperties; import org.esupportail.esupsignature.entity.SignRequest; import org.esupportail.esupsignature.entity.SignRequestParams; +import org.esupportail.esupsignature.entity.Workflow; import org.esupportail.esupsignature.exception.EsupSignatureIOException; import org.esupportail.esupsignature.repository.SignRequestParamsRepository; import org.esupportail.esupsignature.service.utils.pdf.PdfService; @@ -18,11 +26,14 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; -import jakarta.annotation.Resource; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Method; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; @Service @@ -46,15 +57,15 @@ public SignRequestParams getById(Long id) { return signRequestParamsRepository.findById(id).orElseThrow(); } - public SignRequestParams createFromPdf(PDTerminalField pdSignatureField, int signPageNumber, PDPage pdPage) { + public SignRequestParams createFromPdf(String name, PDRectangle pdRectangle, int signPageNumber, PDPage pdPage) { SignRequestParams signRequestParams = new SignRequestParams(); signRequestParams.setSignImageNumber(0); - signRequestParams.setPdSignatureFieldName(pdSignatureField.getPartialName()); - signRequestParams.setxPos(Math.round(pdSignatureField.getWidgets().get(0).getRectangle().getLowerLeftX() / globalProperties.getFixFactor())); - signRequestParams.setyPos(Math.round((pdPage.getBBox().getHeight() - pdSignatureField.getWidgets().get(0).getRectangle().getLowerLeftY() - pdSignatureField.getWidgets().get(0).getRectangle().getHeight()) / globalProperties.getFixFactor())); + signRequestParams.setPdSignatureFieldName(name); + signRequestParams.setxPos(Math.round(pdRectangle.getLowerLeftX() / globalProperties.getFixFactor())); + signRequestParams.setyPos(Math.round((pdPage.getBBox().getHeight() - pdRectangle.getLowerLeftY() - pdRectangle.getHeight()) / globalProperties.getFixFactor())); signRequestParams.setSignPageNumber(signPageNumber); - signRequestParams.setSignWidth(Math.round(pdSignatureField.getWidgets().get(0).getRectangle().getWidth() / globalProperties.getFixFactor())); - signRequestParams.setSignHeight(Math.round(pdSignatureField.getWidgets().get(0).getRectangle().getHeight() / globalProperties.getFixFactor())); +// signRequestParams.setSignWidth(Math.round(pdRectangle.getWidth() / globalProperties.getFixFactor())); +// signRequestParams.setSignHeight(Math.round(pdRectangle.getHeight() / globalProperties.getFixFactor())); signRequestParamsRepository.save(signRequestParams); return signRequestParams; } @@ -82,10 +93,10 @@ public SignRequestParams getSignRequestParamsFromJson(String signRequestParamsJs return null; } - public List scanSignatureFields(InputStream inputStream, int docNumber) throws EsupSignatureIOException { + public List scanSignatureFields(InputStream inputStream, int docNumber, Workflow workflow) throws EsupSignatureIOException { try { PDDocument pdDocument = PDDocument.load(inputStream); - List signRequestParamses = getSignRequestParamsFromPdf(pdDocument); + List signRequestParamses = getSignRequestParamsFromPdf(pdDocument, workflow); for(SignRequestParams signRequestParams : signRequestParamses) { signRequestParams.setSignDocumentNumber(docNumber); signRequestParamsRepository.save(signRequestParams); @@ -97,7 +108,7 @@ public List scanSignatureFields(InputStream inputStream, int } } - public List getSignRequestParamsFromPdf(PDDocument pdDocument) throws EsupSignatureIOException { + public List getSignRequestParamsFromPdf(PDDocument pdDocument, Workflow workflow) throws EsupSignatureIOException { List signRequestParamsList = new ArrayList<>(); try { PDDocumentCatalog docCatalog = pdDocument.getDocumentCatalog(); @@ -106,8 +117,7 @@ public List getSignRequestParamsFromPdf(PDDocument pdDocument if(acroForm != null) { Map pageNrByAnnotDict = pdfService.getPageNumberByAnnotDict(pdDocument); for (PDField pdField : acroForm.getFields()) { - if (pdField instanceof PDSignatureField) { - PDSignatureField pdSignatureField = (PDSignatureField) pdField; + if (pdField instanceof PDSignatureField pdSignatureField) { PDSignature pdSignature = pdSignatureField.getSignature(); if(pdSignature != null) { continue; @@ -116,31 +126,77 @@ public List getSignRequestParamsFromPdf(PDDocument pdDocument if(pageNrByAnnotDict.containsKey(signFieldName) && pageNrByAnnotDict.get(signFieldName) != null) { int pageNum = pageNrByAnnotDict.get(signFieldName); PDPage pdPage = pdPages.get(pageNum); - SignRequestParams signRequestParams = createFromPdf(pdSignatureField, pageNrByAnnotDict.get(signFieldName) + 1, pdPage); + SignRequestParams signRequestParams = createFromPdf(signFieldName, pdSignatureField.getWidgets().get(0).getRectangle(), pageNrByAnnotDict.get(signFieldName) + 1, pdPage); signRequestParamsList.add(signRequestParams); } } - //Un bouton dont le nom commence par signature est considéré comme un champ signature - if(pdField instanceof PDPushButton) { - PDPushButton pdSignatureField = (PDPushButton) pdField; - String signFieldName = pdSignatureField.getPartialName(); - if(signFieldName.toLowerCase(Locale.ROOT).startsWith("signature")) { - int pageNum = pageNrByAnnotDict.get(signFieldName); - PDPage pdPage = pdPages.get(pageNum); - SignRequestParams signRequestParams = createFromPdf(pdSignatureField, pageNrByAnnotDict.get(signFieldName) + 1, pdPage); - signRequestParamsList.add(signRequestParams); + if(workflow != null && StringUtils.hasText(workflow.getSignRequestParamsDetectionPattern())) { + String className = "org.apache.pdfbox.pdmodel.interactive.form.PD" + extractTextInBrackets(workflow.getSignRequestParamsDetectionPattern()); + try { + Class pdFieldClass = Class.forName(className); + if (pdFieldClass.isInstance(pdField)) { + Method getPartialNameMethod = pdFieldClass.getMethod("getPartialName"); + String signFieldName = (String) getPartialNameMethod.invoke(pdField); + Pattern pattern = Pattern.compile(workflow.getSignRequestParamsDetectionPattern().split("]")[1], Pattern.CASE_INSENSITIVE); + if (pattern.matcher(signFieldName).find()) { + int pageNum = pageNrByAnnotDict.get(signFieldName); + PDPage pdPage = pdPages.get(pageNum); + Method getWidgetsMethod = pdFieldClass.getMethod("getWidgets"); + List widgets = (List) getWidgetsMethod.invoke(pdField); + Method getRectangleMethod = widgets.get(0).getClass().getMethod("getRectangle"); + Object rectangle = getRectangleMethod.invoke(widgets.get(0)); + SignRequestParams signRequestParams = createFromPdf(signFieldName, (PDRectangle) rectangle, pageNrByAnnotDict.get(signFieldName) + 1, pdPage); + signRequestParamsList.add(signRequestParams); + } + } + } catch (ClassNotFoundException e) { + logger.warn("error on get sign fields"); + } + } + } + } + if(workflow != null && StringUtils.hasText(workflow.getSignRequestParamsDetectionPattern()) && workflow.getSignRequestParamsDetectionPattern().contains("AnnotationLink")) { + int i = 1; + for(PDPage pdPage : pdPages) { + List pdAnnotations = pdPage.getAnnotations(); + for (PDAnnotation pdAnnotation : pdAnnotations) { + if (pdAnnotation instanceof PDAnnotationLink pdAnnotationLink) { + if (pdAnnotationLink.getAction() instanceof PDActionURI pdActionURI) { + String signFieldName = pdActionURI.getURI(); + Pattern pattern = Pattern.compile(workflow.getSignRequestParamsDetectionPattern().split("]")[1], Pattern.CASE_INSENSITIVE); + if (pattern.matcher(signFieldName).find()) { + SignRequestParams signRequestParams = createFromPdf(signFieldName, pdAnnotationLink.getRectangle(), i, pdPage); + signRequestParamsList.add(signRequestParams); + } + } } } + i++; } } pdDocument.close(); } catch (Exception e) { logger.error("error on get sign fields", e); - throw new EsupSignatureIOException(e.getMessage()); + throw new EsupSignatureIOException(e.getMessage(), e); } return signRequestParamsList.stream().sorted(Comparator.comparingInt(SignRequestParams::getxPos)).sorted(Comparator.comparingInt(SignRequestParams::getyPos)).sorted(Comparator.comparingInt(SignRequestParams::getSignPageNumber)).collect(Collectors.toList()); } + private String extractTextInBrackets(String input) { + Pattern pattern = Pattern.compile("\\[(.*?)\\]"); + Matcher matcher = pattern.matcher(input); + if (matcher.find()) { + return matcher.group(1); + } + return null; + } + + private List convertStringToList(String input) { + String trimmedInput = input.replace("[", ""); + trimmedInput = trimmedInput.replace("]", ""); + return Arrays.asList(StringUtils.split(trimmedInput, ",")); + } + public void copySignRequestParams(SignRequest signRequest, List signRequestParamses) { for (int i = 0 ; i < signRequestParamses.size() ; i++) { SignRequestParams signRequestParams; diff --git a/src/main/java/org/esupportail/esupsignature/service/SignRequestService.java b/src/main/java/org/esupportail/esupsignature/service/SignRequestService.java index f847c42fd..de9d475c4 100644 --- a/src/main/java/org/esupportail/esupsignature/service/SignRequestService.java +++ b/src/main/java/org/esupportail/esupsignature/service/SignRequestService.java @@ -431,11 +431,11 @@ public void addDocsToSignRequest(SignRequest signRequest, boolean scanSignatureF String contentType = multipartFile.getContentType(); InputStream inputStream = new ByteArrayInputStream(bytes); if (multipartFiles.length == 1 && bytes.length > 0) { - if("application/pdf".equals(multipartFiles[0].getContentType()) && scanSignatureFields) { + if("application/pdf".equals(multipartFiles[0].getContentType()) && (scanSignatureFields || (signRequest.getParentSignBook().getLiveWorkflow().getWorkflow() != null && signRequest.getParentSignBook().getLiveWorkflow().getWorkflow().getScanPdfMetadatas()))) { bytes = pdfService.normalizeGS(bytes); List toAddSignRequestParams = new ArrayList<>(); if(signRequestParamses.isEmpty()) { - toAddSignRequestParams = signRequestParamsService.scanSignatureFields(new ByteArrayInputStream(bytes), docNumber); + toAddSignRequestParams = signRequestParamsService.scanSignatureFields(new ByteArrayInputStream(bytes), docNumber, signRequest.getParentSignBook().getLiveWorkflow().getWorkflow()); } else { for (SignRequestParams signRequestParams : signRequestParamses) { toAddSignRequestParams.add(signRequestParamsService.createSignRequestParams(signRequestParams.getSignPageNumber(), signRequestParams.getxPos(), signRequestParams.getyPos(), signRequestParams.getSignWidth(), signRequestParams.getSignHeight())); @@ -444,7 +444,7 @@ public void addDocsToSignRequest(SignRequest signRequest, boolean scanSignatureF signRequest.getSignRequestParams().addAll(toAddSignRequestParams); Reports reports = validationService.validate(new ByteArrayInputStream(bytes), null); if(reports == null || reports.getSimpleReport().getSignatureIdList().isEmpty()) { - inputStream = pdfService.removeSignField(new ByteArrayInputStream(bytes)); + inputStream = pdfService.removeSignField(new ByteArrayInputStream(bytes), signRequest.getParentSignBook().getLiveWorkflow().getWorkflow()); } } else if(contentType != null && contentType.contains("image")){ bytes = pdfService.jpegToPdf(multipartFile.getInputStream(), multipartFile.getName()).readAllBytes(); @@ -495,7 +495,7 @@ public void pendingSignRequest(SignRequest signRequest, String authUserEppn) { updateStatus(signRequest.getId(), SignRequestStatus.pending, "Envoyé pour signature", null, "SUCCESS", null, null, null, null, authUserEppn, authUserEppn); customMetricsService.incValue("esup-signature.signrequests", "new"); for (Target target : signRequest.getParentSignBook().getLiveWorkflow().getTargets().stream().filter(t -> t != null && fsAccessFactoryService.getPathIOType(t.getTargetUri()).equals(DocumentIOType.rest)).collect(Collectors.toList())) { - targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), "pending", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber().toString()); + targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), "pending", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber().toString(), authUserEppn, ""); } } @@ -639,6 +639,9 @@ public Long delete(Long signRequestId, String userEppn) { logService.create(signRequest.getId(), signRequest.getParentSignBook().getSubject(), signRequest.getParentSignBook().getWorkflowName(), SignRequestStatus.deleted, "Mise à la corbeille de la demande par l'utilisateur", "", "SUCCESS", null, null, null, null, userEppn, userEppn); } signRequest.setDeleted(true); + for (Target target : signRequest.getParentSignBook().getLiveWorkflow().getTargets().stream().filter(t -> t != null && fsAccessFactoryService.getPathIOType(t.getTargetUri()).equals(DocumentIOType.rest)).collect(Collectors.toList())) { + targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), "deleted", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber().toString(), userEppn, ""); + } return signRequest.getParentSignBook().getId(); } } @@ -673,6 +676,9 @@ public Long deleteDefinitive(Long signRequestId, String userEppn) { } } signRequestRepository.delete(signRequest); + for (Target target : signRequest.getParentSignBook().getLiveWorkflow().getTargets().stream().filter(t -> t != null && fsAccessFactoryService.getPathIOType(t.getTargetUri()).equals(DocumentIOType.rest)).collect(Collectors.toList())) { + targetService.sendRest(target.getTargetUri(), signRequest.getId().toString(), "cleaned", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStepNumber().toString(), userEppn, ""); + } long signBookId = 0; if(!signBook.getSignRequests().isEmpty()) { signBookId = signBook.getId(); diff --git a/src/main/java/org/esupportail/esupsignature/service/TargetService.java b/src/main/java/org/esupportail/esupsignature/service/TargetService.java index a638fc49c..6103cb817 100644 --- a/src/main/java/org/esupportail/esupsignature/service/TargetService.java +++ b/src/main/java/org/esupportail/esupsignature/service/TargetService.java @@ -1,5 +1,6 @@ package org.esupportail.esupsignature.service; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.annotation.Resource; import org.esupportail.esupsignature.entity.SignBook; import org.esupportail.esupsignature.entity.Target; @@ -7,7 +8,9 @@ import org.esupportail.esupsignature.exception.EsupSignatureFsException; import org.esupportail.esupsignature.repository.TargetRepository; import org.esupportail.esupsignature.service.interfaces.fs.FsAccessFactoryService; -import org.springframework.http.ResponseEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate; @@ -19,6 +22,8 @@ @Service public class TargetService { + private static final Logger logger = LoggerFactory.getLogger(TargetService.class); + @Resource private TargetRepository targetRepository; @@ -37,17 +42,39 @@ public Target createTarget(String targetUri) { return target; } - public ResponseEntity sendRest(String target, String signRequestId, String status, String step) throws EsupSignatureFsException { + public void sendRest(String target, String signRequestId, String status, String step, String userEppn, String comment) throws EsupSignatureFsException { + ResponseEntity response; RestTemplate restTemplate = new RestTemplate(); UriComponents targetUri = UriComponentsBuilder.fromUriString(target) .queryParam("signRequestId", signRequestId) .queryParam("status", status) .queryParam("step", step) + .queryParam("userEppn", userEppn) + .queryParam("comment", comment) .build(); + boolean sendOk = false; try { - return restTemplate.getForEntity(targetUri.toUri(), String.class); + response = restTemplate.getForEntity(targetUri.toUri(), String.class); + if(response.getStatusCode().equals(HttpStatus.OK)) { + sendOk = true; + } } catch (Exception e) { - throw new EsupSignatureFsException(e.getMessage()); + logger.warn(e.getMessage()); + } + try { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + ObjectMapper objectMapper = new ObjectMapper(); + HttpEntity postRequest = new HttpEntity<>(objectMapper.writeValueAsString(targetUri.getQueryParams().toSingleValueMap()), headers); + response = restTemplate.exchange(target, HttpMethod.POST, postRequest, String.class); + if(response.getStatusCode().equals(HttpStatus.OK)) { + sendOk = true; + } + }catch (Exception e) { + logger.warn(e.getMessage()); + } + if(!sendOk) { + throw new EsupSignatureFsException("error sending to target " + target); } } diff --git a/src/main/java/org/esupportail/esupsignature/service/UserKeystoreService.java b/src/main/java/org/esupportail/esupsignature/service/UserKeystoreService.java index 9ccc24e95..f2bed8e52 100644 --- a/src/main/java/org/esupportail/esupsignature/service/UserKeystoreService.java +++ b/src/main/java/org/esupportail/esupsignature/service/UserKeystoreService.java @@ -1,11 +1,11 @@ package org.esupportail.esupsignature.service; import eu.europa.esig.dss.model.x509.CertificateToken; +import eu.europa.esig.dss.spi.validation.CertificateVerifier; import eu.europa.esig.dss.token.DSSPrivateKeyEntry; import eu.europa.esig.dss.token.Pkcs12SignatureToken; import eu.europa.esig.dss.token.SignatureTokenConnection; import eu.europa.esig.dss.validation.CertificateValidator; -import eu.europa.esig.dss.validation.CertificateVerifier; import eu.europa.esig.dss.validation.reports.CertificateReports; import jakarta.annotation.Resource; import org.esupportail.esupsignature.entity.User; diff --git a/src/main/java/org/esupportail/esupsignature/service/UserService.java b/src/main/java/org/esupportail/esupsignature/service/UserService.java index 1e4f07816..ffe06ebf5 100644 --- a/src/main/java/org/esupportail/esupsignature/service/UserService.java +++ b/src/main/java/org/esupportail/esupsignature/service/UserService.java @@ -45,6 +45,8 @@ import java.time.DayOfWeek; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; @Service @@ -211,7 +213,7 @@ public String buildEppn(String uid) { @Transactional public User createUserWithEppn(String eppn) throws EsupSignatureUserException { - if(eppn.equals("system")) { + if(eppn == null || eppn.equals("system")) { return getSystemUser(); } User user = getByEppn(eppn); @@ -370,8 +372,14 @@ public User createUser(String eppn, String name, String firstName, String email, } @Transactional - public void updateUser(String authUserEppn, String signImageBase64, EmailAlertFrequency emailAlertFrequency, Integer emailAlertHour, DayOfWeek emailAlertDay, MultipartFile multipartKeystore, SignRequestParams signRequestParams, Boolean returnToHomeAfterSign) throws IOException { + public void updateUser(String authUserEppn, String name, String firstName, String signImageBase64, EmailAlertFrequency emailAlertFrequency, Integer emailAlertHour, DayOfWeek emailAlertDay, MultipartFile multipartKeystore, SignRequestParams signRequestParams, Boolean returnToHomeAfterSign) throws IOException { User authUser = getByEppn(authUserEppn); + if(StringUtils.hasText(name)) { + authUser.setName(name); + } + if(StringUtils.hasText(firstName)) { + authUser.setFirstname(firstName); + } if(signRequestParams != null) { signRequestParams.setxPos(0); signRequestParams.setyPos(0); @@ -767,11 +775,15 @@ public List getAllRoles() { } } if(ldapGroupService != null && webSecurityProperties.getGroupToRoleFilterPattern() != null) { - List prefixGroups = ldapGroupService.getAllPrefixGroups(webSecurityProperties.getGroupToRoleFilterPattern()); - for (String prefixGroup : prefixGroups) { - String prefixRole = "ROLE_" + prefixGroup.split("\\.")[prefixGroup.split("\\.").length - 1].toUpperCase(); - if(!roles.contains(prefixRole)) { - roles.add(prefixRole); + List groupsNames = ldapGroupService.getAllPrefixGroups(webSecurityProperties.getGroupToRoleFilterPattern()); + for (String groupName : groupsNames) { + Pattern pattern = Pattern.compile(webSecurityProperties.getGroupToRoleFilterPattern()); + Matcher matcher = pattern.matcher(groupName); + if(matcher.find()) { + String roleName = "ROLE_" + matcher.group(1).toUpperCase(); + if (!roles.contains(roleName)) { + roles.add(roleName); + } } } } diff --git a/src/main/java/org/esupportail/esupsignature/service/WorkflowService.java b/src/main/java/org/esupportail/esupsignature/service/WorkflowService.java index b072eb35c..7f3dd3f61 100644 --- a/src/main/java/org/esupportail/esupsignature/service/WorkflowService.java +++ b/src/main/java/org/esupportail/esupsignature/service/WorkflowService.java @@ -500,6 +500,8 @@ public Workflow update(Workflow workflow, User user, String[] types, Set workflowToUpdate.setUpdateBy(user.getEppn()); workflowToUpdate.setUpdateDate(new Date()); workflowToUpdate.setMessage(workflow.getMessage()); + workflowToUpdate.setMailFrom(workflow.getMailFrom()); + workflowToUpdate.setSignRequestParamsDetectionPattern(workflow.getSignRequestParamsDetectionPattern()); workflowRepository.save(workflowToUpdate); return workflowToUpdate; } diff --git a/src/main/java/org/esupportail/esupsignature/service/interfaces/listsearch/impl/SympaUserList.java b/src/main/java/org/esupportail/esupsignature/service/interfaces/listsearch/impl/SympaUserList.java index c1cc2d38b..bd0e7d959 100644 --- a/src/main/java/org/esupportail/esupsignature/service/interfaces/listsearch/impl/SympaUserList.java +++ b/src/main/java/org/esupportail/esupsignature/service/interfaces/listsearch/impl/SympaUserList.java @@ -1,6 +1,8 @@ package org.esupportail.esupsignature.service.interfaces.listsearch.impl; +import jakarta.annotation.PostConstruct; import org.apache.commons.lang.StringEscapeUtils; +import org.esupportail.esupsignature.config.GlobalProperties; import org.esupportail.esupsignature.exception.EsupSignatureRuntimeException; import org.esupportail.esupsignature.service.extdb.ExtDbService; import org.esupportail.esupsignature.service.interfaces.listsearch.UserList; @@ -9,8 +11,6 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; import java.sql.ResultSet; import java.util.AbstractMap; import java.util.ArrayList; @@ -23,8 +23,14 @@ public class SympaUserList implements UserList { private JdbcTemplate jdbcTemplate; - @Resource - private ExtDbService extDbService; + private final ExtDbService extDbService; + + private final GlobalProperties globalProperties; + + public SympaUserList(ExtDbService extDbService, GlobalProperties globalProperties) { + this.extDbService = extDbService; + this.globalProperties = globalProperties; + } @PostConstruct public void initJdbcTemplate() { @@ -39,13 +45,16 @@ public String getName() { @Override public List getUsersEmailFromList(String listName) throws DataAccessException { List userEmails = new ArrayList<>(); - jdbcTemplate.query("select user_subscriber from subscriber_table where list_subscriber=" + "'" + listName.split("@")[0] + "'", (ResultSet rs) -> { - userEmails.add(rs.getString("user_subscriber")); - while (rs.next()) { + if(listName.contains(globalProperties.getDomain())) { + jdbcTemplate.query("select user_subscriber from subscriber_table where list_subscriber=" + "'" + listName.split("@")[0] + "'", (ResultSet rs) -> { userEmails.add(rs.getString("user_subscriber")); - } - }); - return userEmails; + while (rs.next()) { + userEmails.add(rs.getString("user_subscriber")); + } + }); + return userEmails; + } + return new ArrayList<>(); } @Override diff --git a/src/main/java/org/esupportail/esupsignature/service/mail/MailService.java b/src/main/java/org/esupportail/esupsignature/service/mail/MailService.java index 07eb30b7e..3391cf052 100644 --- a/src/main/java/org/esupportail/esupsignature/service/mail/MailService.java +++ b/src/main/java/org/esupportail/esupsignature/service/mail/MailService.java @@ -134,10 +134,9 @@ public void sendCompletedMail(SignBook signBook, String userEppn) throws EsupSig String htmlContent = templateEngine.process("mail/email-completed.html", ctx); addInLineImages(mimeMessage, htmlContent); mimeMessage.setSubject("Votre demande de signature est terminée"); - mimeMessage.setFrom(mailConfig.getMailFrom()); mimeMessage.setTo(toEmails.toArray(String[]::new)); logger.info("send email completed to : " + StringUtils.join(toEmails.toArray(String[]::new), ";")); - sendMail(mimeMessage.getMimeMessage()); + sendMail(mimeMessage.getMimeMessage(), signBook.getLiveWorkflow().getWorkflow()); } catch (MailSendException | MessagingException e) { logger.error("unable to send COMPLETE email", e); throw new EsupSignatureMailException("Problème lors de l'envoi du mail", e); @@ -162,10 +161,9 @@ public void sendPostit(SignBook signBook, Comment comment) throws EsupSignatureM String htmlContent = templateEngine.process("mail/email-postit.html", ctx); addInLineImages(mimeMessage, htmlContent); mimeMessage.setSubject("Un postit a été déposé sur votre demande"); - mimeMessage.setFrom(mailConfig.getMailFrom()); mimeMessage.setTo(toEmails.toArray(String[]::new)); - logger.info("send email completed to : " + StringUtils.join(toEmails.toArray(String[]::new), ";")); - sendMail(mimeMessage.getMimeMessage()); + logger.info("send postit to : " + StringUtils.join(toEmails.toArray(String[]::new), ";")); + sendMail(mimeMessage.getMimeMessage(), signBook.getLiveWorkflow().getWorkflow()); } catch (MailSendException | MessagingException e) { logger.error("unable to send COMPLETE email", e); throw new EsupSignatureMailException("Problème lors de l'envoi du mail", e); @@ -188,7 +186,6 @@ public void sendCompletedCCMail(SignBook signBook) throws EsupSignatureMailExcep String htmlContent = templateEngine.process("mail/email-completed-cc.html", ctx); addInLineImages(mimeMessage, htmlContent); mimeMessage.setSubject("Une demande de signature que vous suivez est terminée"); - mimeMessage.setFrom(mailConfig.getMailFrom()); List viewersArray = getViewers(signBook); if (!viewersArray.isEmpty()) { String[] to = new String[viewersArray.size()]; @@ -199,7 +196,7 @@ public void sendCompletedCCMail(SignBook signBook) throws EsupSignatureMailExcep } mimeMessage.setTo(to); logger.info("send email completes cc for " + user.getEppn()); - sendMail(mimeMessage.getMimeMessage()); + sendMail(mimeMessage.getMimeMessage(), signBook.getLiveWorkflow().getWorkflow()); } else { logger.debug("no viewers to send mail"); } @@ -260,7 +257,6 @@ public void sendRefusedMail(SignBook signBook, String comment, String userEppn) String htmlContent = templateEngine.process("mail/email-refused.html", ctx); addInLineImages(mimeMessage, htmlContent); mimeMessage.setSubject("Votre demande de signature a été refusée"); - mimeMessage.setFrom(mailConfig.getMailFrom()); mimeMessage.setTo(toEmails.toArray(String[]::new)); String[] viewersArray = new String[signBook.getViewers().size()]; for (int i = 0 ; i < signBook.getViewers().size() ; i++) { @@ -268,7 +264,7 @@ public void sendRefusedMail(SignBook signBook, String comment, String userEppn) } mimeMessage.setCc(viewersArray); logger.info("send email refused to : " + StringUtils.join(toEmails.toArray(String[]::new), ";")); - sendMail(mimeMessage.getMimeMessage()); + sendMail(mimeMessage.getMimeMessage(), signBook.getLiveWorkflow().getWorkflow()); } catch (MessagingException e) { logger.error("unable to send REFUSE email", e); throw new EsupSignatureMailException("Problème lors de l'envoi du mail", e); @@ -295,11 +291,10 @@ public void sendSignRequestAlert(List recipientsEmails, SignBook signBoo String htmlContent = templateEngine.process("mail/email-alert.html", ctx); addInLineImages(mimeMessage, htmlContent); mimeMessage.setSubject("Vous avez une nouvelle demande de signature"); - mimeMessage.setFrom(mailConfig.getMailFrom()); mimeMessage.setTo(recipientsEmails.toArray(String[]::new)); logger.info("send email alert for " + recipientsEmails.get(0)); // sendMail(signMessage(mimeMessage.getMimeMessage())); - sendMail(mimeMessage.getMimeMessage()); + sendMail(mimeMessage.getMimeMessage(), signBook.getLiveWorkflow().getWorkflow()); signBook.setLastNotifDate(new Date()); } catch (Exception e) { logger.error("unable to send ALERT email", e); @@ -327,10 +322,9 @@ public void sendSignRequestReplayAlert(List recipientsEmails, SignBook s String htmlContent = templateEngine.process("mail/email-replay-alert.html", ctx); addInLineImages(mimeMessage, htmlContent); mimeMessage.setSubject("Relance pour la signature d'un document"); - mimeMessage.setFrom(mailConfig.getMailFrom()); mimeMessage.setTo(recipientsEmails.toArray(String[]::new)); logger.info("send email replay alert for " + recipientsEmails.get(0)); - sendMail(mimeMessage.getMimeMessage()); + sendMail(mimeMessage.getMimeMessage(), signBook.getLiveWorkflow().getWorkflow()); signBook.setLastNotifDate(new Date()); } catch (MessagingException e) { logger.error("unable to send ALERT email", e); @@ -363,10 +357,9 @@ public void sendCCAlert(SignBook signBook, List recipientsCCEmails) thro addInLineImages(mimeMessage, htmlContent); User creator = signBook.getCreateBy(); mimeMessage.setSubject("Vous êtes en copie d'une demande de signature crée par " + creator.getFirstname() + " " + creator.getName()); - mimeMessage.setFrom(mailConfig.getMailFrom()); mimeMessage.setTo(recipientsCCEmails.toArray(String[]::new)); logger.info("send email cc for " + String.join(";", recipientsCCEmails)); - sendMail(mimeMessage.getMimeMessage()); + sendMail(mimeMessage.getMimeMessage(), signBook.getLiveWorkflow().getWorkflow()); } catch (MessagingException e) { logger.error("unable to send CC ALERT email", e); throw new EsupSignatureMailException("Problème lors de l'envoi du mail", e); @@ -388,11 +381,10 @@ public void sendSignRequestSummaryAlert(List recipientsEmails, List recipientsEmails) throws MessagingException { return; } final Context ctx = new Context(Locale.FRENCH); - final MimeMessage mimeMessage = mailSender.createMimeMessage(); - MimeMessageHelper message; - message = new MimeMessageHelper(mimeMessage, true, "UTF-8"); - message.setSubject("esup-signature test mail"); - message.setFrom(mailConfig.getMailFrom()); - message.setTo(recipientsEmails.toArray(String[]::new)); + MimeMessageHelper mimeMessage = new MimeMessageHelper(getMailSender().createMimeMessage(), true, "UTF-8"); + mimeMessage.setSubject("esup-signature test mail"); + mimeMessage.setTo(recipientsEmails.toArray(String[]::new)); String htmlContent = templateEngine.process("mail/email-test.html", ctx); - message.setText(htmlContent, true); + mimeMessage.setText(htmlContent, true); logger.info("send test email for " + recipientsEmails.get(0)); - sendMail(mimeMessage); + sendMail(mimeMessage.getMimeMessage(), null); } - private void sendMail(MimeMessage mimeMessage) { + private void sendMail(MimeMessage mimeMessage, Workflow workflow) { try { + mimeMessage.setFrom(mailConfig.getMailFrom()); + if(workflow != null && org.springframework.util.StringUtils.hasText(workflow.getMailFrom())) { + mimeMessage.setFrom(workflow.getMailFrom()); + } String[] toHeader = mimeMessage.getHeader("To"); List tos = new ArrayList<>(); for(String to : toHeader) { diff --git a/src/main/java/org/esupportail/esupsignature/service/scheduler/ScheduledTaskService.java b/src/main/java/org/esupportail/esupsignature/service/scheduler/ScheduledTaskService.java index 6962177fa..950e40d63 100644 --- a/src/main/java/org/esupportail/esupsignature/service/scheduler/ScheduledTaskService.java +++ b/src/main/java/org/esupportail/esupsignature/service/scheduler/ScheduledTaskService.java @@ -13,10 +13,10 @@ import org.esupportail.esupsignature.service.SignBookService; import org.esupportail.esupsignature.service.UserService; import org.esupportail.esupsignature.service.WorkflowService; +import org.esupportail.esupsignature.service.security.otp.OtpService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Profile; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -27,7 +27,7 @@ import java.util.List; @EnableScheduling -@Profile("!dev") +//@Profile("!dev") @Component @EnableConfigurationProperties(GlobalProperties.class) public class ScheduledTaskService { @@ -48,7 +48,9 @@ public class ScheduledTaskService { private final SignRequestRepository signRequestRepository; - public ScheduledTaskService(GlobalProperties globalProperties, SignBookRepository signBookRepository, SignBookService signBookService, TaskService taskService, WorkflowService workflowService, UserService userService, SignRequestRepository signRequestRepository) { + private final OtpService otpService; + + public ScheduledTaskService(GlobalProperties globalProperties, SignBookRepository signBookRepository, SignBookService signBookService, TaskService taskService, WorkflowService workflowService, UserService userService, SignRequestRepository signRequestRepository, OtpService otpService) { this.globalProperties = globalProperties; this.signBookRepository = signBookRepository; this.signBookService = signBookService; @@ -56,10 +58,11 @@ public ScheduledTaskService(GlobalProperties globalProperties, SignBookRepositor this.workflowService = workflowService; this.userService = userService; this.signRequestRepository = signRequestRepository; - } + this.otpService = otpService; + } - @Scheduled(initialDelay = 12000, fixedRate = 300000) + //@Scheduled(initialDelay = 12000, fixedRate = 300000) @Transactional public void scanAllWorkflowsSources() { logger.debug("scan workflows sources"); @@ -87,7 +90,7 @@ public void scanAllSignbooksTargets() { } } - @Scheduled(initialDelay = 12000, fixedRate = 300000) + //@Scheduled(initialDelay = 12000, fixedRate = 300000) public void scanAllSignbooksToArchive() { if(globalProperties.getEnableScheduledCleanup()) { SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z"); @@ -101,7 +104,7 @@ public void scanAllSignbooksToArchive() { } } - @Scheduled(initialDelay = 12000, fixedRate = 300000) + //@Scheduled(initialDelay = 12000, fixedRate = 300000) public void scanAllSignbooksToClean() { if(globalProperties.getEnableScheduledCleanup()) { SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z"); @@ -114,7 +117,7 @@ public void scanAllSignbooksToClean() { } } - @Scheduled(initialDelay = 12000, fixedRate = 300000) + //@Scheduled(initialDelay = 12000, fixedRate = 300000) @Transactional public void sendAllEmailAlerts() throws EsupSignatureMailException { List users = userService.getAllUsers(); @@ -126,17 +129,17 @@ public void sendAllEmailAlerts() throws EsupSignatureMailException { } } - @Scheduled(cron="00 02 02 * * *") + //@Scheduled(cron="00 02 02 * * *") public void cleanUploadingSignBooks() { taskService.initCleanUploadingSignBooks(); } - @Scheduled(cron="0 0 * * * *") + //@Scheduled(cron="0 0 * * * *") public void refreshOJKeystore() { taskService.initDssRefresh(); } - @Scheduled(initialDelay = 12000, fixedRate = 300000) + //@Scheduled(initialDelay = 12000, fixedRate = 300000) @Transactional public void cleanWarningReadSignRequests() { if(globalProperties.getNbDaysBeforeDeleting() > -1) { @@ -147,4 +150,10 @@ public void cleanWarningReadSignRequests() { } } + //@Scheduled(initialDelay = 12000, fixedRate = 300000) + @Transactional + public void cleanOtps() { + otpService.cleanEndedOtp(); + } + } diff --git a/src/main/java/org/esupportail/esupsignature/service/security/otp/OtpService.java b/src/main/java/org/esupportail/esupsignature/service/security/otp/OtpService.java index 884451d44..2d1d9df5d 100644 --- a/src/main/java/org/esupportail/esupsignature/service/security/otp/OtpService.java +++ b/src/main/java/org/esupportail/esupsignature/service/security/otp/OtpService.java @@ -10,6 +10,7 @@ import org.esupportail.esupsignature.entity.Otp; import org.esupportail.esupsignature.entity.SignBook; import org.esupportail.esupsignature.entity.User; +import org.esupportail.esupsignature.entity.enums.SignRequestStatus; import org.esupportail.esupsignature.entity.enums.UserType; import org.esupportail.esupsignature.exception.EsupSignatureMailException; import org.esupportail.esupsignature.repository.OtpRepository; @@ -29,10 +30,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; -import java.util.Date; -import java.util.HashSet; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; @Service @@ -109,7 +107,7 @@ public void removeOtpFromCache(String searchString) { } } - public void deleteOtpBySignRequestId(Long id) { + public void deleteOtpBySignBookId(Long id) { for (Map.Entry otpEntry : otpCache.asMap().entrySet()) { if(otpEntry.getValue().getSignBook().getId().equals(id)) { clearOTP(otpEntry.getKey()); @@ -207,4 +205,18 @@ private String hashPassword(String password) { return new String(Hex.encode(hash)); } + @Transactional + public void cleanEndedOtp(){ + List otps = otpRepository.findBySignBookStatus(SignRequestStatus.completed); + otps.addAll(otpRepository.findBySignBookStatus(SignRequestStatus.deleted)); + otps.addAll(otpRepository.findBySignBookStatus(SignRequestStatus.refused)); + otps.addAll(otpRepository.findBySignBookStatus(SignRequestStatus.exported)); + otps.addAll(otpRepository.findBySignBookStatus(SignRequestStatus.archived)); + logger.info(otps.size() + " otps to clean"); + for(Otp otp : otps) { + clearOTP(otp.getUrlId()); + otpRepository.delete(otp); + } + } + } diff --git a/src/main/java/org/esupportail/esupsignature/service/utils/file/FileService.java b/src/main/java/org/esupportail/esupsignature/service/utils/file/FileService.java index 73cf63070..0b4f280ce 100644 --- a/src/main/java/org/esupportail/esupsignature/service/utils/file/FileService.java +++ b/src/main/java/org/esupportail/esupsignature/service/utils/file/FileService.java @@ -343,10 +343,14 @@ public InputStream getDefaultImage(String name, String firstname, String email, graphics2D.fillRect(0, 0, Math.round(600 / factor), Math.round(300 / factor)); setQualityParams(graphics2D); String word; - if (name.length() >= firstname.length()) { - word = name; + if(StringUtils.hasText(firstname) && StringUtils.hasText(name)) { + if (name.length() >= firstname.length()) { + word = name; + } else { + word = firstname; + } } else { - word = firstname; + word = email; } try { Font font; @@ -392,7 +396,10 @@ public InputStream getDefaultParaphe(String name, String firstname, String email rect.setRect(0, 0, 600 / factor, 300 / factor); graphics2D.fillRect(0, 0, Math.round(600 / factor), Math.round(300 / factor)); setQualityParams(graphics2D); - String word = (firstname.charAt(0) + "" + name.charAt(0)).toUpperCase(); + String word = email; + if(StringUtils.hasText(firstname) && StringUtils.hasText(name)) { + word = (firstname.charAt(0) + "" + name.charAt(0)).toUpperCase(); + } try { Font font = Font.createFont(Font.TRUETYPE_FONT, new ClassPathResource("/static/fonts/Signature.ttf").getInputStream()).deriveFont(Font.BOLD).deriveFont(12f); int fontSize = findFontSize(word, Math.round(250 / factor), font); diff --git a/src/main/java/org/esupportail/esupsignature/service/utils/pdf/PdfService.java b/src/main/java/org/esupportail/esupsignature/service/utils/pdf/PdfService.java index d785a6fe6..f68d12d75 100644 --- a/src/main/java/org/esupportail/esupsignature/service/utils/pdf/PdfService.java +++ b/src/main/java/org/esupportail/esupsignature/service/utils/pdf/PdfService.java @@ -20,8 +20,7 @@ import org.apache.pdfbox.pdmodel.common.PDMetadata; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.pdmodel.font.PDFont; -import org.apache.pdfbox.pdmodel.font.PDTrueTypeFont; -import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding; +import org.apache.pdfbox.pdmodel.font.PDType0Font; import org.apache.pdfbox.pdmodel.graphics.color.PDColor; import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; @@ -48,10 +47,7 @@ import org.apache.xmpbox.xml.XmpSerializer; import org.esupportail.esupsignature.config.GlobalProperties; import org.esupportail.esupsignature.config.pdf.PdfConfig; -import org.esupportail.esupsignature.entity.Log; -import org.esupportail.esupsignature.entity.SignRequest; -import org.esupportail.esupsignature.entity.SignRequestParams; -import org.esupportail.esupsignature.entity.User; +import org.esupportail.esupsignature.entity.*; import org.esupportail.esupsignature.entity.enums.SignType; import org.esupportail.esupsignature.exception.EsupSignatureRuntimeException; import org.esupportail.esupsignature.exception.EsupSignatureSignException; @@ -75,13 +71,17 @@ import javax.imageio.ImageIO; import javax.xml.transform.TransformerException; import java.awt.*; +import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.*; +import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.List; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; @Service @@ -115,7 +115,7 @@ public byte[] stampImage(byte[] inputStream, SignRequest signRequest, SignReques PDDocument pdDocument = PDDocument.load(inputStream); pdDocument.setAllSecurityToBeRemoved(true); pdfParameters = getPdfParameters(pdDocument, signRequestParams.getSignPageNumber()); - if(signRequestParams.getAllPages() != null && signRequestParams.getAllPages()) { + if(signRequestParams.getAllPages() != null && signRequestParams.getAllPages() && signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getMultiSign()) { int i = 1; for(PDPage pdPage : pdDocument.getPages()) { if(i != signRequestParams.getSignPageNumber() || signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getSignType().equals(SignType.pdfImageStamp)) { @@ -214,7 +214,7 @@ private void stampImageToPage(SignRequest signRequest, SignRequestParams signReq } } else if (StringUtils.hasText(signRequestParams.getTextPart())) { float fontSize = signRequestParams.getFontSize() * fixFactor; - PDFont pdFont = PDTrueTypeFont.load(pdDocument, new ClassPathResource("/static/fonts/LiberationSans-Regular.ttf").getInputStream(), WinAnsiEncoding.INSTANCE); + PDFont pdFont = PDType0Font.load(pdDocument, new ClassPathResource("/static/fonts/LiberationSans-Regular.ttf").getInputStream(), true); contentStream.beginText(); contentStream.setFont(pdFont, fontSize); String[] lines = signRequestParams.getTextPart().split("\n"); @@ -626,8 +626,7 @@ public byte[] fill(InputStream pdfFile, Map datas, boolean isLas PDDocument pdDocument = PDDocument.load(pdfFile); PDAcroForm pdAcroForm = pdDocument.getDocumentCatalog().getAcroForm(); if(pdAcroForm != null) { - byte[] ttfBytes = new ClassPathResource("/static/fonts/LiberationSans-Regular.ttf").getInputStream().readAllBytes(); - PDFont pdFont = PDTrueTypeFont.load(pdDocument, new ByteArrayInputStream(ttfBytes), WinAnsiEncoding.INSTANCE); + PDType0Font pdFont = PDType0Font.load(pdDocument, new ClassPathResource("/static/fonts/LiberationSans-Regular.ttf").getInputStream(), false); PDResources resources = pdAcroForm.getDefaultResources(); resources.put(COSName.getPDFName("LiberationSans"), pdFont); pdAcroForm.setDefaultResources(resources); @@ -737,35 +736,69 @@ public PDFieldTree getFields(PDDocument pdDocument) throws EsupSignatureRuntimeE return null; } - public InputStream removeSignField(InputStream pdfFile) { + public InputStream removeSignField(InputStream pdfFile, Workflow workflow) { try { PDDocument pdDocument = PDDocument.load(pdfFile); PDAcroForm pdAcroForm = pdDocument.getDocumentCatalog().getAcroForm(); if(pdAcroForm != null) { - PDFont pdFont = PDTrueTypeFont.load(pdDocument, new ClassPathResource("/static/fonts/LiberationSans-Regular.ttf").getInputStream(), WinAnsiEncoding.INSTANCE); + PDFont pdFont = PDType0Font.load(pdDocument, new ClassPathResource("/static/fonts/LiberationSans-Regular.ttf").getInputStream(), true); PDResources resources = pdAcroForm.getDefaultResources(); resources.put(COSName.getPDFName("LiberationSans"), pdFont); pdAcroForm.setDefaultResources(resources); List fields = pdAcroForm.getFields(); for(PDField pdField : fields) { - if(pdField instanceof PDSignatureField || (pdField instanceof PDPushButton && pdField.getPartialName().toLowerCase(Locale.ROOT).startsWith("signature"))) { - List widgets = pdField.getWidgets(); - for (PDAnnotationWidget widget : widgets) { - for(PDPage page : pdDocument.getPages()) { - List annotations = page.getAnnotations(); - boolean removed = false; - for (PDAnnotation annotation : annotations) { - if (annotation.getCOSObject().equals(widget.getCOSObject())) { - removed = annotations.remove(annotation); - break; + if(pdField instanceof PDSignatureField) { + removeField(pdField, pdDocument, pdAcroForm); + } else if(workflow != null && StringUtils.hasText(workflow.getSignRequestParamsDetectionPattern())) { + String className = "org.apache.pdfbox.pdmodel.interactive.form.PD" + extractTextInBrackets(workflow.getSignRequestParamsDetectionPattern()); + try { + Class pdFieldClass = Class.forName(className); + if (pdFieldClass.isInstance(pdField)) { + Method getPartialNameMethod = pdFieldClass.getMethod("getPartialName"); + String signFieldName = (String) getPartialNameMethod.invoke(pdField); + Pattern pattern = Pattern.compile(workflow.getSignRequestParamsDetectionPattern().split("]")[1], Pattern.CASE_INSENSITIVE); + if (pattern.matcher(signFieldName).find()) { + removeField(pdField, pdDocument, pdAcroForm); + } + } + } catch (ClassNotFoundException e) { + logger.warn("error on remove sign field", e); + } + } + } + } + if(workflow != null && StringUtils.hasText(workflow.getSignRequestParamsDetectionPattern()) && workflow.getSignRequestParamsDetectionPattern().contains("AnnotationLink")) { + try { + PDDocumentCatalog docCatalog = pdDocument.getDocumentCatalog(); + PDPageTree pdPages = docCatalog.getPages(); + for (PDPage pdPage : pdPages) { + List annotationsToRemove = new ArrayList<>(); + List pdAnnotations = pdPage.getAnnotations(); + for (PDAnnotation pdAnnotation : pdAnnotations) { + if (pdAnnotation instanceof PDAnnotationLink pdAnnotationLink) { + String signFieldName = ((PDActionURI) pdAnnotationLink.getAction()).getURI(); + Pattern pattern = Pattern.compile(workflow.getSignRequestParamsDetectionPattern().split("]")[1], Pattern.CASE_INSENSITIVE); + if(pattern.matcher(signFieldName).find()) { + annotationsToRemove.add(pdAnnotation); + PDRectangle linkPosition = pdAnnotationLink.getRectangle(); + Rectangle2D.Float rect = new Rectangle2D.Float( + linkPosition.getLowerLeftX(), + linkPosition.getLowerLeftY(), + linkPosition.getWidth(), + linkPosition.getHeight() + ); + try (PDPageContentStream contentStream = new PDPageContentStream(pdDocument, pdPage, AppendMode.APPEND, true, true)) { + contentStream.setNonStrokingColor(1f, 1f, 1f); + contentStream.addRect(rect.x-1, rect.y-1, rect.width+1, rect.height+1); + contentStream.fill(); } } - if (!removed) - System.out.println("Inconsistent annotation definition: Page annotations do not include the target widget."); } } - pdAcroForm.getFields().remove(pdField); + pdAnnotations.removeAll(annotationsToRemove); } + } catch (IOException e) { + logger.warn("error on remove sign field fake link", e); } } ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -773,12 +806,40 @@ public InputStream removeSignField(InputStream pdfFile) { pdDocument.save(out); pdDocument.close(); return new ByteArrayInputStream(out.toByteArray()); - } catch (IOException e) { + } catch (Exception e) { logger.error("file read error", e); } return null; } + private static void removeField(PDField pdField, PDDocument pdDocument, PDAcroForm pdAcroForm) throws IOException { + List widgets = pdField.getWidgets(); + for (PDAnnotationWidget widget : widgets) { + for(PDPage page : pdDocument.getPages()) { + List annotations = page.getAnnotations(); + boolean removed = false; + for (PDAnnotation annotation : annotations) { + if (annotation.getCOSObject().equals(widget.getCOSObject())) { + removed = annotations.remove(annotation); + break; + } + } + if (!removed) + logger.debug("Inconsistent annotation definition: Page annotations do not include the target widget."); + } + } + pdAcroForm.getFields().remove(pdField); + } + + private String extractTextInBrackets(String input) { + Pattern pattern = Pattern.compile("\\[(.*?)\\]"); + Matcher matcher = pattern.matcher(input); + if (matcher.find()) { + return matcher.group(1); + } + return null; + } + public PdfParameters getPdfParameters(InputStream pdfFile, int pageNumber) { PDDocument pdDocument = null; try { diff --git a/src/main/java/org/esupportail/esupsignature/service/utils/sign/NexuService.java b/src/main/java/org/esupportail/esupsignature/service/utils/sign/NexuService.java index 2f1666303..11230dbd4 100644 --- a/src/main/java/org/esupportail/esupsignature/service/utils/sign/NexuService.java +++ b/src/main/java/org/esupportail/esupsignature/service/utils/sign/NexuService.java @@ -1,12 +1,12 @@ package org.esupportail.esupsignature.service.utils.sign; -import eu.europa.esig.dss.AbstractSignatureParameters; import eu.europa.esig.dss.cades.CAdESSignatureParameters; import eu.europa.esig.dss.enumerations.ASiCContainerType; import eu.europa.esig.dss.enumerations.SignatureAlgorithm; import eu.europa.esig.dss.enumerations.SignatureForm; import eu.europa.esig.dss.model.*; import eu.europa.esig.dss.pades.PAdESSignatureParameters; +import eu.europa.esig.dss.signature.AbstractSignatureParameters; import eu.europa.esig.dss.signature.DocumentSignatureService; import eu.europa.esig.dss.signature.MultipleDocumentsSignatureService; import eu.europa.esig.dss.spi.DSSUtils; diff --git a/src/main/java/org/esupportail/esupsignature/service/utils/sign/SignService.java b/src/main/java/org/esupportail/esupsignature/service/utils/sign/SignService.java index de41b7704..0895ace1b 100644 --- a/src/main/java/org/esupportail/esupsignature/service/utils/sign/SignService.java +++ b/src/main/java/org/esupportail/esupsignature/service/utils/sign/SignService.java @@ -1,6 +1,5 @@ package org.esupportail.esupsignature.service.utils.sign; -import eu.europa.esig.dss.AbstractSignatureParameters; import eu.europa.esig.dss.asic.cades.ASiCWithCAdESSignatureParameters; import eu.europa.esig.dss.asic.cades.signature.ASiCWithCAdESService; import eu.europa.esig.dss.asic.xades.ASiCWithXAdESSignatureParameters; @@ -16,6 +15,7 @@ import eu.europa.esig.dss.pades.SignatureFieldParameters; import eu.europa.esig.dss.pades.SignatureImageParameters; import eu.europa.esig.dss.pades.signature.PAdESService; +import eu.europa.esig.dss.signature.AbstractSignatureParameters; import eu.europa.esig.dss.signature.DocumentSignatureService; import eu.europa.esig.dss.signature.MultipleDocumentsSignatureService; import eu.europa.esig.dss.spi.DSSUtils; diff --git a/src/main/java/org/esupportail/esupsignature/service/utils/sign/ValidationService.java b/src/main/java/org/esupportail/esupsignature/service/utils/sign/ValidationService.java index 8999b8282..2497a0a2d 100644 --- a/src/main/java/org/esupportail/esupsignature/service/utils/sign/ValidationService.java +++ b/src/main/java/org/esupportail/esupsignature/service/utils/sign/ValidationService.java @@ -1,17 +1,17 @@ package org.esupportail.esupsignature.service.utils.sign; -import eu.europa.esig.dss.AbstractSignatureParameters; import eu.europa.esig.dss.enumerations.Indication; import eu.europa.esig.dss.enumerations.SignatureLevel; import eu.europa.esig.dss.enumerations.TokenExtractionStrategy; +import eu.europa.esig.dss.enumerations.ValidationLevel; import eu.europa.esig.dss.model.DSSDocument; import eu.europa.esig.dss.model.x509.CertificateToken; import eu.europa.esig.dss.model.x509.revocation.ocsp.OCSP; +import eu.europa.esig.dss.signature.AbstractSignatureParameters; +import eu.europa.esig.dss.spi.policy.SignaturePolicyProvider; +import eu.europa.esig.dss.spi.validation.CertificateVerifier; import eu.europa.esig.dss.spi.x509.revocation.RevocationToken; -import eu.europa.esig.dss.validation.CertificateVerifier; -import eu.europa.esig.dss.validation.SignaturePolicyProvider; import eu.europa.esig.dss.validation.SignedDocumentValidator; -import eu.europa.esig.dss.validation.executor.ValidationLevel; import eu.europa.esig.dss.validation.reports.Reports; import jakarta.annotation.Resource; import org.esupportail.esupsignature.dss.DssUtilsService; diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/CurrentSessionsController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/CurrentSessionsController.java index 25adf002f..7d2a5e2a7 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/admin/CurrentSessionsController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/CurrentSessionsController.java @@ -77,10 +77,14 @@ public String getCurrentSessions(Model model) { } } sessions.sort((s1, s2) -> s2.getLastRequest().compareTo(s1.getLastRequest())); - model.addAttribute("httpSessions", - allSessions.values().stream() - .sorted(Comparator.comparing(HttpSession::getLastRequest, Comparator.nullsLast(Comparator.naturalOrder())).reversed()) - .toList()); + try { + model.addAttribute("httpSessions", + allSessions.values().stream() + .sorted(Comparator.comparing(HttpSession::getLastRequest, Comparator.nullsLast(Comparator.naturalOrder())).reversed()) + .toList()); + } catch (Exception e) { + model.addAttribute("httpSessions", allSessions.values()); + } model.addAttribute("active", "sessions"); return "admin/currentsessions"; } diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/DSSController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/DSSController.java index 480f79a8f..f3b084bec 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/admin/DSSController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/DSSController.java @@ -1,6 +1,10 @@ package org.esupportail.esupsignature.web.controller.admin; -import eu.europa.esig.dss.spi.tsl.*; +import eu.europa.esig.dss.model.tsl.LOTLInfo; +import eu.europa.esig.dss.model.tsl.ParsingInfoRecord; +import eu.europa.esig.dss.model.tsl.TLInfo; +import eu.europa.esig.dss.model.tsl.TLValidationJobSummary; +import eu.europa.esig.dss.spi.tsl.TrustedListsCertificateSource; import eu.europa.esig.dss.tsl.function.OfficialJournalSchemeInformationURI; import eu.europa.esig.dss.tsl.job.TLValidationJob; import eu.europa.esig.dss.tsl.source.LOTLSource; diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/admin/WorkflowAdminController.java b/src/main/java/org/esupportail/esupsignature/web/controller/admin/WorkflowAdminController.java index 98b93cee0..997af2777 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/admin/WorkflowAdminController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/admin/WorkflowAdminController.java @@ -250,7 +250,7 @@ public String addStep(@ModelAttribute("authUserEppn") String authUserEppn, @GetMapping(value = "/get-files-from-source/{id}") @PreAuthorize("@preAuthorizeService.workflowManager(#id, #authUserEppn) || hasRole('ROLE_ADMIN')") - public String getFileFromSource(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, Model model, RedirectAttributes redirectAttributes) throws EsupSignatureRuntimeException { + public String getFileFromSource(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("id") Long id, RedirectAttributes redirectAttributes) throws EsupSignatureRuntimeException { User user = userService.getByEppn(authUserEppn); int nbImportedFiles = signBookService.importFilesFromSource(id, user, user); if (nbImportedFiles == 0) { @@ -258,7 +258,7 @@ public String getFileFromSource(@ModelAttribute("authUserEppn") String authUserE } else { redirectAttributes.addFlashAttribute("message", new JsMessage("info", nbImportedFiles + " ficher(s) importé(s)")); } - return "redirect:/admin/workflows/steps/" + id; + return "redirect:/admin/workflows"; } @PostMapping(value = "/add-target/{id}") diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/user/ManageController.java b/src/main/java/org/esupportail/esupsignature/web/controller/user/ManageController.java index 92a0734b6..6e88cc9c7 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/user/ManageController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/user/ManageController.java @@ -69,7 +69,7 @@ public String index(@ModelAttribute("authUserEppn") String authUserEppn, Model m } @PreAuthorize("@preAuthorizeService.workflowManage(#id, #authUserEppn)") - @GetMapping(value = "/workflow/{id}", produces="text/csv") + @GetMapping(value = "/workflow/{id}/signbooks", produces="text/csv") public String list(@ModelAttribute("userEppn") String userEppn, @ModelAttribute("authUserEppn") String authUserEppn, @RequestParam(value = "statusFilter", required = false) String statusFilter, @RequestParam(value = "recipientsFilter", required = false) String recipientsFilter, @@ -81,11 +81,11 @@ public String list(@ModelAttribute("userEppn") String userEppn, @ModelAttribute( if(creatorFilter == null || creatorFilter.isEmpty() || creatorFilter.equals("all")) { creatorFilter = "%"; } - if(docTitleFilter == null || docTitleFilter.isEmpty() || docTitleFilter.equals("all")) { - docTitleFilter = "%"; + if(docTitleFilter != null && (docTitleFilter.isEmpty() || docTitleFilter.equals("all"))) { + docTitleFilter = null; } - if(recipientsFilter == null || recipientsFilter.isEmpty() || recipientsFilter.equals("all")) { - recipientsFilter = "%"; + if(recipientsFilter != null && (recipientsFilter.isEmpty() || recipientsFilter.equals("all"))) { + recipientsFilter = null; } Workflow workflow = workflowService.getById(id); model.addAttribute("statuses", SignRequestStatus.values()); @@ -95,10 +95,11 @@ public String list(@ModelAttribute("userEppn") String userEppn, @ModelAttribute( model.addAttribute("creatorFilter", creatorFilter); model.addAttribute("statusFilter", statusFilter); model.addAttribute("workflow", workflow); - Page signBooks = signBookService.getSignBookByWorkflow(workflow, statusFilter, recipientsFilter, creatorFilter, dateFilter, pageable); - model.addAttribute("listManagedSignBooks", signBooks); - model.addAttribute("creators", signBooks.stream().map(SignBook::getCreateBy).distinct().collect(Collectors.toList())); - model.addAttribute("signRequestRecipients", signBookService.getRecipientsNames(userEppn).stream().filter(Objects::nonNull).collect(Collectors.toList())); + Page signBooks = signBookService.getSignBooksForManagers(userEppn, authUserEppn, statusFilter, recipientsFilter, workflow.getDescription(), docTitleFilter, creatorFilter, dateFilter, pageable); + model.addAttribute("signBooks", signBooks); + model.addAttribute("docTitles", signBookService.getSignBooksForManagersSubjects(workflow.getDescription())); + model.addAttribute("creators", signBookService.getSignBooksForManagersCreators(workflow.getDescription())); + model.addAttribute("signRequestRecipients", signBookService.getSignBooksForManagersRecipientsUsers(workflow.getDescription())); return "user/manage/details"; } diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/user/SignRequestController.java b/src/main/java/org/esupportail/esupsignature/web/controller/user/SignRequestController.java index 5557c3258..f7f58f859 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/user/SignRequestController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/user/SignRequestController.java @@ -127,6 +127,8 @@ public String show(@ModelAttribute("userEppn") String userEppn, @ModelAttribute( if(signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep() != null && signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getWorkflowStep() != null) { model.addAttribute("currentStepId", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getWorkflowStep().getId()); model.addAttribute("currentStepMultiSign", signRequest.getParentSignBook().getLiveWorkflow().getCurrentStep().getMultiSign()); + } else { + model.addAttribute("currentStepMultiSign", true); } model.addAttribute("nbSignRequestInSignBookParent", signRequest.getParentSignBook().getSignRequests().size()); List toSignDocuments = signService.getToSignDocuments(signRequest.getId()); diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/user/UserController.java b/src/main/java/org/esupportail/esupsignature/web/controller/user/UserController.java index cf40d5e3e..e9df3fb6d 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/user/UserController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/user/UserController.java @@ -93,7 +93,7 @@ public String update(@ModelAttribute("authUserEppn") String authUserEppn, @Reque if(saveSignRequestParams == null || !saveSignRequestParams) { signRequestParams = signRequestParamsService.getSignRequestParamsFromJson(signRequestParamsJsonString); } - userService.updateUser(authUserEppn, signImageBase64, emailAlertFrequency, emailAlertHour, emailAlertDay, multipartKeystore, signRequestParams, returnToHomeAfterSign); + userService.updateUser(authUserEppn, null, null, signImageBase64, emailAlertFrequency, emailAlertHour, emailAlertDay, multipartKeystore, signRequestParams, returnToHomeAfterSign); redirectAttributes.addFlashAttribute("message", new JsMessage("success", "Vos paramètres ont été enregistrés")); String referer = httpServletRequest.getHeader(HttpHeaders.REFERER); return "redirect:" + referer; diff --git a/src/main/java/org/esupportail/esupsignature/web/controller/user/ValidationController.java b/src/main/java/org/esupportail/esupsignature/web/controller/user/ValidationController.java index 9dbb5a222..4ad15f32b 100644 --- a/src/main/java/org/esupportail/esupsignature/web/controller/user/ValidationController.java +++ b/src/main/java/org/esupportail/esupsignature/web/controller/user/ValidationController.java @@ -8,10 +8,13 @@ import eu.europa.esig.dss.enumerations.MimeTypeEnum; import eu.europa.esig.dss.enumerations.RevocationType; import eu.europa.esig.dss.enumerations.TimestampType; +import eu.europa.esig.dss.enumerations.ValidationLevel; import eu.europa.esig.dss.utils.Utils; -import eu.europa.esig.dss.validation.executor.ValidationLevel; import eu.europa.esig.dss.validation.reports.Reports; import eu.europa.esig.validationreport.jaxb.ValidationReportType; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import org.esupportail.esupsignature.dss.service.FOPService; import org.esupportail.esupsignature.dss.service.XSLTService; import org.esupportail.esupsignature.exception.EsupSignatureRuntimeException; @@ -30,9 +33,6 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.servlet.http.HttpSession; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/org/esupportail/esupsignature/web/otp/OtpUserController.java b/src/main/java/org/esupportail/esupsignature/web/otp/OtpUserController.java index 0b0c344ec..2efd1404d 100644 --- a/src/main/java/org/esupportail/esupsignature/web/otp/OtpUserController.java +++ b/src/main/java/org/esupportail/esupsignature/web/otp/OtpUserController.java @@ -48,11 +48,14 @@ public String updateForm(@ModelAttribute("authUserEppn") String authUserEppn, Mo @PostMapping public String update(@ModelAttribute("authUserEppn") String authUserEppn, @RequestParam(value = "signImageBase64", required=false) String signImageBase64, + @RequestParam(value = "name") String name, + @RequestParam(value = "firstname") String firstname, @RequestParam(value = "emailAlertFrequency", required=false) EmailAlertFrequency emailAlertFrequency, @RequestParam(value = "emailAlertHour", required=false) Integer emailAlertHour, @RequestParam(value = "emailAlertDay", required=false) DayOfWeek emailAlertDay, - @RequestParam(value = "multipartKeystore", required=false) MultipartFile multipartKeystore, RedirectAttributes redirectAttributes, HttpServletRequest httpServletRequest) throws Exception { - userService.updateUser(authUserEppn, signImageBase64, emailAlertFrequency, emailAlertHour, emailAlertDay, multipartKeystore, null, false); + @RequestParam(value = "multipartKeystore", required=false) MultipartFile multipartKeystore, + RedirectAttributes redirectAttributes, HttpServletRequest httpServletRequest) throws Exception { + userService.updateUser(authUserEppn, name, firstname, signImageBase64, emailAlertFrequency, emailAlertHour, emailAlertDay, multipartKeystore, null, false); redirectAttributes.addFlashAttribute("message", new JsMessage("success", "Vos paramètres ont été enregistrés")); String referer = httpServletRequest.getHeader(HttpHeaders.REFERER); return "redirect:" + referer; diff --git a/src/main/java/org/esupportail/esupsignature/web/wssecure/GlobalWsSecureController.java b/src/main/java/org/esupportail/esupsignature/web/wssecure/GlobalWsSecureController.java index 9f3aef63c..ee86d2028 100644 --- a/src/main/java/org/esupportail/esupsignature/web/wssecure/GlobalWsSecureController.java +++ b/src/main/java/org/esupportail/esupsignature/web/wssecure/GlobalWsSecureController.java @@ -15,8 +15,6 @@ import org.esupportail.esupsignature.service.*; import org.esupportail.esupsignature.service.export.SedaExportService; import org.esupportail.esupsignature.service.utils.StepStatus; -import org.json.JSONException; -import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; @@ -169,12 +167,12 @@ public ResponseEntity getLastFiles(@ModelAttribute("userEppn") String user @PreAuthorize("@preAuthorizeService.documentCreator(#documentId, #authUserEppn)") @ResponseBody @PostMapping(value = "/remove-doc/{documentId}", produces = MediaType.APPLICATION_JSON_VALUE) - public String removeDocument(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("documentId") Long documentId) throws JSONException { + public String removeDocument(@ModelAttribute("authUserEppn") String authUserEppn, @PathVariable("documentId") Long documentId) { logger.info("remove document " + documentId); Document document = documentService.getById(documentId); SignRequest signRequest = signRequestService.getById(document.getParentId()); signRequest.getOriginalDocuments().remove(document); - return new JSONObject().toString(); + return "{}"; } @PreAuthorize("@preAuthorizeService.signRequestView(#id, #userEppn, #authUserEppn)") diff --git a/src/main/resources/static/css/overrides.css b/src/main/resources/static/css/overrides.css index e2d0ec436..13960c6dd 100644 --- a/src/main/resources/static/css/overrides.css +++ b/src/main/resources/static/css/overrides.css @@ -349,6 +349,10 @@ textarea:invalid { display: none; } +.textWidgetAnnotation * { + font-size: calc(10px* var(--scale-factor)) !important; +} + /*.textWidgetAnnotation textarea {*/ /* !*border: 1px solid black !important;*!*/ /* overflow: hidden;*/ diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css index 5c7774238..1244e122c 100644 --- a/src/main/resources/static/css/style.css +++ b/src/main/resources/static/css/style.css @@ -142,9 +142,9 @@ td { #sidebar { background: white; - -moz-box-shadow: 0 0 4px 4px rgba(0, 0, 0, 0.3); - -webkit-box-shadow: 0 0 4px 4px rgba(0, 0, 0, 0.3); - box-shadow: 0 0 4px 4px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 5px 4px 4px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0 5px 4px 4px rgba(0, 0, 0, 0.3); + box-shadow: 0 5px 4px 4px rgba(0, 0, 0, 0.3); } .nav-tabs { diff --git a/src/main/resources/static/fonts/LiberationSans-Regular.ttf b/src/main/resources/static/fonts/LiberationSans-Regular.ttf index 59d2e251b..e6339859d 100644 Binary files a/src/main/resources/static/fonts/LiberationSans-Regular.ttf and b/src/main/resources/static/fonts/LiberationSans-Regular.ttf differ diff --git a/src/main/resources/static/js/modules/ui/signrequests/SignPosition.js b/src/main/resources/static/js/modules/ui/signrequests/SignPosition.js index 7e094dd5f..8c809bb0f 100644 --- a/src/main/resources/static/js/modules/ui/signrequests/SignPosition.js +++ b/src/main/resources/static/js/modules/ui/signrequests/SignPosition.js @@ -1,5 +1,6 @@ import {SignRequestParams} from "../../../prototypes/SignRequestParams.js?version=@version@"; import {EventFactory} from "../../utils/EventFactory.js?version=@version@"; +import {UserUi} from '../users/UserUi.js?version=@version@'; export class SignPosition extends EventFactory { @@ -44,6 +45,11 @@ export class SignPosition extends EventFactory { $(window).on('scroll', function(e) { self.scrollTop = $(this).scrollTop(); }); + $(document).ready(function() { + if(self.signImages.length === 1) { + self.popUserUi(); + } + }); } removeSign(id) { @@ -84,7 +90,18 @@ export class SignPosition extends EventFactory { } } + popUserUi() { + if (this.userUI == null) { + this.userUI = new UserUi(); + } + $("#add-sign-image").modal("show"); + } + addSign(page, restore, signImageNumber, forceSignNumber) { + if(this.signImages.length === 1) { + this.popUserUi(); + return; + } this.disableForwardButton(); $(window).bind("beforeunload",function(event) { return "You have some unsaved changes"; diff --git a/src/main/resources/static/js/modules/ui/signrequests/WorkspacePdf.js b/src/main/resources/static/js/modules/ui/signrequests/WorkspacePdf.js index 3b93b6019..67d88d018 100644 --- a/src/main/resources/static/js/modules/ui/signrequests/WorkspacePdf.js +++ b/src/main/resources/static/js/modules/ui/signrequests/WorkspacePdf.js @@ -1,7 +1,6 @@ import {PdfViewer} from "../../utils/PdfViewer.js?version=@version@"; import {SignPosition} from "./SignPosition.js?version=@version@"; import {WheelDetector} from "../../utils/WheelDetector.js?version=@version@"; -import {UserUi} from '../users/UserUi.js?version=@version@'; export class WorkspacePdf { @@ -16,6 +15,7 @@ export class WorkspacePdf { this.action = action; this.dataId = dataId; this.formId = formId; + this.workflow = workflow; this.signImageNumber = signImageNumber; this.restore = restore; this.postits = postits; @@ -147,13 +147,11 @@ export class WorkspacePdf { $("#addMinus").on("click", e => this.signPosition.addMinusImage(this.pdfViewer.pageNum)); $("#addText").on("click ", e => this.signPosition.addText(this.pdfViewer.pageNum)); - let signImageBtn = $("#signImage"); + let signImageBtn = $("#signImageBtn"); signImageBtn.unbind(); + let self = this; signImageBtn.on('click', function () { - if (this.userUI == null) { - this.userUI = new UserUi(); - } - $("#add-sign-image").modal("show"); + self.signPosition.popUserUi(); }); this.notviewedAnim(); } @@ -290,6 +288,7 @@ export class WorkspacePdf { this.refreshAfterPageChange(); this.initForm(); this.pdfViewer.pdfDiv.on('mousedown', e => this.clickAction(e)); + } initForm() { @@ -387,7 +386,7 @@ export class WorkspacePdf { let testSign = Array.from(this.signPosition.signRequestParamses.values()); if(testSign.filter(s => s.signImageNumber >= 0 && s.isSign).length > 0) { for (let i = 0; i < this.currentSignRequestParamses.length; i++) { - if ((this.currentSignRequestParamses[i].ready == null || !this.currentSignRequestParamses[i].ready) && (this.formId != null || this.dataId != null)) { + if ((this.currentSignRequestParamses[i].ready == null || !this.currentSignRequestParamses[i].ready) && (this.formId != null || this.dataId != null || this.workflow === true)) { return i; } } diff --git a/src/main/resources/static/js/modules/ui/users/UserUi.js b/src/main/resources/static/js/modules/ui/users/UserUi.js index 1fd47a232..262a743da 100644 --- a/src/main/resources/static/js/modules/ui/users/UserUi.js +++ b/src/main/resources/static/js/modules/ui/users/UserUi.js @@ -35,7 +35,9 @@ export class UserUi { e.preventDefault(); let target = e.currentTarget; bootbox.confirm("Voulez-vous vraiment supprimer cette signature ?", function(result){ - if(result) $('#deleteForm-' + $(target).attr("data-es-id")).submit(); + if(result) { + $('#deleteForm-' + $(target).attr("data-es-id")).submit(); + } }); }); }); @@ -71,6 +73,10 @@ export class UserUi { if(!this.saveSignRequestParams) { $("#sign-request-params").val(JSON.stringify(this.signRequestParams)); } + if($("#name").val() === "" || $("#firstname").val() === "") { + $("#submitUserParamsForm").click(); + return; + } $("#userParamsForm").submit(); } diff --git a/src/main/resources/static/js/modules/utils/PdfViewer.js b/src/main/resources/static/js/modules/utils/PdfViewer.js index 883d7cfa9..c08869773 100644 --- a/src/main/resources/static/js/modules/utils/PdfViewer.js +++ b/src/main/resources/static/js/modules/utils/PdfViewer.js @@ -44,15 +44,15 @@ export class PdfViewer extends EventFactory { let self = this; $(document).ready(function() { if (!globalThis.pdfjsLib || !Promise.withResolvers) { - bootbox.alert("Votre navigateur ne support pas pdfJs pour l'affichage des PDF.
Version minimales : Firefox 121, Chrome 119, Safari 17.4", function () { + bootbox.alert("Votre navigateur ne support pas pdfJs pour l’affichage des PDF.
Version minimales : Firefox 121, Chrome 119, Safari 17.4", function () { document.location = "https://www.mozilla.org/fr/firefox/new/" }); } else { - pdfjsLib.GlobalWorkerOptions.workerSrc = new URL( - '/webjars/pdfjs-dist/4.2.67/legacy/build/pdf.worker.min.mjs', + globalThis.pdfjsLib.GlobalWorkerOptions.workerSrc = new URL( + '/webjars/pdfjs-dist/4.6.82/legacy/build/pdf.worker.min.mjs', import.meta.url - ).toString() - pdfjsLib.getDocument(self.url).promise.then(pdf => self.startRender(pdf)); + ).toString(); + globalThis.pdfjsLib.getDocument(self.url).promise.then(pdf => self.startRender(pdf)); } }); diff --git a/src/main/resources/templates/admin/currentsessions.html b/src/main/resources/templates/admin/currentsessions.html index 87b215d55..0c6be3930 100644 --- a/src/main/resources/templates/admin/currentsessions.html +++ b/src/main/resources/templates/admin/currentsessions.html @@ -17,7 +17,7 @@
Utilisateurs connectés
- +
diff --git a/src/main/resources/templates/admin/workflows/update.html b/src/main/resources/templates/admin/workflows/update.html index 6e2e1db13..24e4e5275 100644 --- a/src/main/resources/templates/admin/workflows/update.html +++ b/src/main/resources/templates/admin/workflows/update.html @@ -45,17 +45,13 @@

WORKFLOW ID : Titre

-
- - -
-
- - -
-
- - -
-
- - -
- +
@@ -151,6 +135,19 @@

WORKFLOW ID :

+ Options +
+ + +
+
+ + +
+
+ + +
@@ -174,6 +171,37 @@

WORKFLOW ID :

+
+ +
+
+ Le modèle est construit à l’aide du type d’élément entre crochets suivi d’une regex pour le nom de l’attribut. + Voici la liste des éléments pris en charge : +
    +
  • [TextField]
  • +
  • [PushButton]
  • +
  • [AnnotationLink]
  • +
+ Exemples : +
    +
  • [TextField]^(SIG_SIGNATURE|SIG_CACHET)$ : pour détecter les champs de type TextField avec les attributs SIG_SIGNATURE ou SIG_CACHET
  • +
  • [AnnotationLink]^signature : pour détecter les champs de type AnnotationLink commençant par "signature"
  • +
+ +
+
+ +
+
+ + +
@@ -184,14 +212,14 @@

WORKFLOW ID :

- + + class="form-control" type="text" + th:value="${workflow.documentsSourceUri}" + autocomplete="on">
- + @@ -224,24 +252,53 @@

WORKFLOW ID :
+
+
+ Le modèle est construit à l'aide d'attributs entre crochets. + Si vide, se réfere à l'attribut namingTemplate de la configuration générale + Les attributs disponibles sont : +
    +
  • [originalFileName] : nom original du document
  • +
  • [signedFileName] : nom original du document
  • +
  • [fileNameOnly] : nom document sans extension
  • +
  • [fileExtension] : extension du document
  • +
  • [title] : titre du parapheur
  • +
  • [id] : identifiant du parapheur
  • +
  • [worflowName] : nom du circuit
  • +
  • [user.name] : nom prénom de l'utilisateur courant
  • +
  • [user.eppn] : eppn de l'utilisateur courant
  • +
  • [user.initials] : initiales de l'utilisateur courant
  • +
  • [UUID] : un identifiant unique
  • +
  • [order] : le numéro d'ordre de création pour un même circuit
  • +
  • [timestamp] : timestamp sous forme de long
  • +
  • [date-fr] : date dd/MM/yyyy hh:mm
  • +
  • [date-en] : date yyyy-MM-dd hh:mm
  • +
+
+
- +
+
+ +
- +
- + Exporter le circuit diff --git a/src/main/resources/templates/fragments/head-lite.html b/src/main/resources/templates/fragments/head-lite.html index 17b4c2609..027923708 100644 --- a/src/main/resources/templates/fragments/head-lite.html +++ b/src/main/resources/templates/fragments/head-lite.html @@ -11,7 +11,6 @@ - diff --git a/src/main/resources/templates/fragments/head.html b/src/main/resources/templates/fragments/head.html index 787be4248..c69683a3a 100644 --- a/src/main/resources/templates/fragments/head.html +++ b/src/main/resources/templates/fragments/head.html @@ -20,7 +20,6 @@ - @@ -54,7 +53,6 @@ -
@@ -14,7 +18,7 @@
@@ -76,7 +80,8 @@ - + + @@ -102,7 +107,7 @@

- + @@ -110,7 +115,7 @@ - + - +
@@ -118,8 +123,10 @@
+ + +
diff --git a/src/main/resources/templates/user/manage/list.html b/src/main/resources/templates/user/manage/list.html index 4c0e5557f..be854c60e 100644 --- a/src/main/resources/templates/user/manage/list.html +++ b/src/main/resources/templates/user/manage/list.html @@ -34,8 +34,7 @@
- Liste des demandes + Liste des demandes Export SEDA - + Contrôler le document diff --git a/src/main/resources/templates/user/signrequests/includes/tools.html b/src/main/resources/templates/user/signrequests/includes/tools.html index 35e45ea38..ef01a74bf 100644 --- a/src/main/resources/templates/user/signrequests/includes/tools.html +++ b/src/main/resources/templates/user/signrequests/includes/tools.html @@ -59,8 +59,8 @@ data-bs-target="#addCommentModal"> Post-it -
diff --git a/src/main/resources/templates/user/signrequests/includes/workspace.html b/src/main/resources/templates/user/signrequests/includes/workspace.html index 73e3d0748..86f9b3610 100644 --- a/src/main/resources/templates/user/signrequests/includes/workspace.html +++ b/src/main/resources/templates/user/signrequests/includes/workspace.html @@ -21,8 +21,8 @@ -
- Avant l’import, le document comportait au moins une police de caractère susceptible de poser un problème d’affichage. Merci de contrôler le document avant la signature. +
+ Avant l’import, le document comportait au moins une police de caractère susceptible de poser un problème d’affichage. Merci de bien lire le document avant de le signer.