├── .gitignore ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── LICENSE.txt ├── README.md ├── docs ├── PEPPOL practical.pptx ├── doctypeid-mapping.xml └── processid-mapping.xml ├── findbugs-exclude.xml ├── pom.xml └── src ├── etc ├── javadoc.css └── license-template.txt ├── main ├── java │ └── com │ │ └── helger │ │ └── peppol │ │ ├── app │ │ ├── AppConfig.java │ │ ├── AppInternalErrorHandler.java │ │ ├── AppSecurity.java │ │ ├── CPPApp.java │ │ ├── ajax │ │ │ ├── AjaxExecutorCommentAdd.java │ │ │ ├── AjaxExecutorCommentCreateThread.java │ │ │ ├── AjaxExecutorCommentDelete.java │ │ │ ├── AjaxExecutorCommentShowInput.java │ │ │ ├── AjaxExecutorPublicLogin.java │ │ │ ├── AjaxExecutorPublicUpdateMenuView.java │ │ │ ├── AjaxExecutorSecureUpdateMenuView.java │ │ │ └── CAjax.java │ │ ├── config │ │ │ └── AppMicroTypeConverterRegistarSPI.java │ │ └── mgr │ │ │ └── PPMetaManager.java │ │ ├── comment │ │ ├── domain │ │ │ ├── Comment.java │ │ │ ├── CommentMicroTypeConverter.java │ │ │ ├── CommentThread.java │ │ │ ├── CommentThreadManager.java │ │ │ ├── CommentThreadMicroTypeConverter.java │ │ │ ├── CommentThreadObjectTypeManager.java │ │ │ ├── ECommentState.java │ │ │ ├── ECommentStateText.java │ │ │ ├── IComment.java │ │ │ ├── ICommentIterationCallback.java │ │ │ └── ICommentThread.java │ │ └── ui │ │ │ ├── CCommentCSS.java │ │ │ ├── CommentAction.java │ │ │ ├── CommentFormErrors.java │ │ │ ├── CommentSecurity.java │ │ │ ├── CommentUI.java │ │ │ ├── ECommentAction.java │ │ │ └── ECommentText.java │ │ ├── crm │ │ ├── CRMGroup.java │ │ ├── CRMGroupManager.java │ │ ├── CRMGroupMicroTypeConverter.java │ │ ├── CRMSubscriber.java │ │ ├── CRMSubscriberManager.java │ │ ├── CRMSubscriberMicroTypeConverter.java │ │ ├── ICRMGroup.java │ │ └── ICRMSubscriber.java │ │ ├── pub │ │ ├── CMenuPublic.java │ │ ├── LayoutAreaContentProviderPublic.java │ │ ├── MenuPublic.java │ │ ├── PagePublicLogin.java │ │ ├── PagePublicNewsletterSubscribe.java │ │ ├── PagePublicNewsletterUnsubscribe.java │ │ ├── PagePublicSignUp.java │ │ ├── PagePublicToolsDocumentValidation.java │ │ ├── PagePublicToolsSMPSML.java │ │ └── PagePublicToolsTestEndpoints.java │ │ ├── rest │ │ ├── APIConvertCIIToUBL.java │ │ ├── APIGetAllVESIDs.java │ │ ├── APIQueryParticipantExistence.java │ │ ├── APISMPQueryGetBusinessCard.java │ │ ├── APISMPQueryGetDocTypes.java │ │ ├── APISMPQueryGetServiceInformation.java │ │ ├── AbstractJsonBasedAPIExecutor.java │ │ ├── AbstractPPAPIExecutor.java │ │ └── PPAPI.java │ │ ├── secure │ │ ├── CMenuSecure.java │ │ ├── LayoutAreaContentProviderSecure.java │ │ ├── MenuSecure.java │ │ ├── PageSecureAdminAddons.java │ │ ├── PageSecureCRMGroup.java │ │ ├── PageSecureCRMSubscriber.java │ │ ├── PageSecureCommentAdmin.java │ │ └── PageSecureSchematronTools.java │ │ ├── servlet │ │ ├── AppRootServlet.java │ │ ├── AppWebAppListener.java │ │ ├── PublicApplicationServlet.java │ │ ├── SecureApplicationServlet.java │ │ └── SecureLoginFilter.java │ │ ├── testendpoint │ │ ├── TestEndpoint.java │ │ ├── TestEndpointManager.java │ │ └── TestEndpointMicroTypeConverter.java │ │ ├── ui │ │ ├── AppCommonUI.java │ │ ├── AppLayoutHTMLProvider.java │ │ ├── PPLoginManager.java │ │ └── page │ │ │ └── AppPageViewExternal.java │ │ └── ws │ │ └── WSDVS.java ├── jaxb │ └── peppol-commons.episode ├── resources │ ├── LICENSE │ ├── META-INF │ │ └── services │ │ │ └── com.helger.xml.microdom.convert.IMicroTypeConverterRegistrarSPI │ ├── NOTICE │ ├── application.properties │ ├── html │ │ ├── css.xml │ │ ├── js.xml │ │ └── metatags.xml │ ├── log4j2.prod.xml │ ├── log4j2.xml │ ├── truststore │ │ └── full-truststore.jks │ └── viewpages │ │ └── en │ │ ├── country_de.xml │ │ ├── docs_document_exchange.xml │ │ ├── docs_peppol_cert_update.xml │ │ ├── docs_peppol_dict.xml │ │ ├── docs_peppol_firewall.xml │ │ ├── docs_peppol_mlr.xml │ │ ├── docs_peppol_pki.xml │ │ ├── docs_setup_ap.xml │ │ ├── docs_setup_smp_phoss.xml │ │ ├── docs_sml_support.xml │ │ ├── docs_smp_sml_interplay.xml │ │ ├── docs_software_vendors.xml │ │ ├── en16931.xml │ │ ├── index.xml │ │ ├── invisible │ │ ├── docs_setup_smp_cipa.xml │ │ └── docs_sml_migration.xml │ │ ├── news.xml │ │ ├── rest_api.xml │ │ └── validation_dvs.xml └── webapp │ ├── WEB-INF │ ├── sun-jaxws.xml │ ├── web.xml │ └── wsdl │ │ └── pp-dvs.wsdl │ ├── css │ ├── default.css │ └── default.min.css │ ├── error404.jsp │ ├── files │ ├── peppol-ws-test-client.zip │ ├── peppol │ │ ├── OpenPEPPOL Newsletter 2018-04-11.pdf │ │ ├── PEPPOL-Compliance-Policy_v1.0_PUBLISHED.pdf │ │ └── PEPPOL_Certificates_Change_V1.2.pdf │ └── validation │ │ ├── BIS2.0-VA-Spring2018.20180508.zip │ │ ├── BIS2.0-VA-V3.5.0.zip │ │ ├── BIS2.0-VA-V3.5.0_RC1.zip │ │ └── Release_pkg_spring2017.zip │ ├── google9aa227895f65ee21.html │ ├── imgs │ ├── as4-message-structure.png │ ├── entry.png │ ├── entry_add.png │ ├── entry_delete.png │ ├── entry_edit.png │ ├── pki-structure-v3.png │ └── pki-structure.png │ └── js │ ├── default.js │ └── default.min.js └── test ├── java └── com │ └── helger │ └── peppol │ ├── SPITest.java │ ├── comment │ └── domain │ │ ├── CommentTest.java │ │ ├── CommentThreadObjectTypeManagerTest.java │ │ └── CommentThreadTest.java │ ├── crm │ └── CRMGroupTest.java │ ├── jetty │ ├── JettyStopPP.java │ └── RunInJettyPP.java │ ├── phive │ └── MainCheckDDDConsistency.java │ ├── supplementary │ └── tools │ │ ├── MainCreateNiceNameMappingXML.java │ │ └── MainListVESIDs.java │ └── ws │ └── MainWSDVSClient.java └── resources ├── example-ws-request.xml ├── example-ws-response.xml └── ws ├── example-request-1.xml ├── example-response-1.xml └── invoice1.xml /.gitignore: -------------------------------------------------------------------------------- 1 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 2 | hs_err_pid* 3 | 4 | .settings/ 5 | bin/ 6 | generated/ 7 | target/ 8 | 9 | .classpath 10 | .pmd 11 | .project 12 | zz 13 | 14 | *.iml 15 | *.p12 16 | private-*.properties 17 | google*.html 18 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at codeofconduct@helger.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | # philip[at]helger[dot]com 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # Stage 1 19 | 20 | FROM ubuntu:latest as build 21 | 22 | # Install wget and unzip 23 | RUN apt-get update \ 24 | && apt-get install -y unzip \ 25 | && rm -rf /var/lib/apt/lists/* 26 | 27 | COPY target/*.war app.war 28 | RUN unzip app.war -d /app 29 | 30 | # Stage 2 31 | 32 | FROM tomcat:10.1-jdk17 33 | 34 | ENV CATALINS_OPTS="$CATALINA_OPTS -Djava.security.egd=file:/dev/urandom" 35 | 36 | WORKDIR $CATALINA_HOME/webapps 37 | 38 | COPY --from=build /app $CATALINA_HOME/webapps/ROOT 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # peppol-practical 2 | The source code of the [peppol.helger.com](http://peppol.helger.com) website. 3 | This project requires Java 11+ for building and running. 4 | 5 | This project is licensed under the Apache 2.0 License. 6 | 7 | ## Running 8 | 9 | To run this application locally either clone it or download it. 10 | Load the project into Eclipse (best to use "Import | Maven | Import existing Maven project..."). 11 | Run `com.helger.peppol.jetty.RunInJettyPP` from within Eclipse - that launches a Jetty. 12 | Open `http://localhost:8080/` in your browser. 13 | 14 | --- 15 | 16 | My personal [Coding Styleguide](https://github.com/phax/meta/blob/master/CodingStyleguide.md) | 17 | It is appreciated if you star the GitHub project if you like it. -------------------------------------------------------------------------------- /docs/PEPPOL practical.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/docs/PEPPOL practical.pptx -------------------------------------------------------------------------------- /findbugs-exclude.xml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/etc/license-template.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014-2025 Philip Helger (www.helger.com) 2 | philip[at]helger[dot]com 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/AppConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import com.helger.commons.annotation.UsedViaReflection; 22 | import com.helger.config.IConfig; 23 | import com.helger.peppol.sharedui.config.SharedUIConfig; 24 | import com.helger.scope.singleton.AbstractGlobalSingleton; 25 | 26 | /** 27 | * This class provides access to the settings as contained in the 28 | * application.properties file. 29 | * 30 | * @author Philip Helger 31 | */ 32 | public final class AppConfig extends AbstractGlobalSingleton 33 | { 34 | @Deprecated 35 | @UsedViaReflection 36 | private AppConfig () 37 | {} 38 | 39 | @Nonnull 40 | public static IConfig getConfig () 41 | { 42 | return SharedUIConfig.getConfig (); 43 | } 44 | 45 | public static boolean isWebPageCommentingEnabled () 46 | { 47 | return getConfig ().getAsBoolean ("webapp.pagecomments.enabled", false); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/AppInternalErrorHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app; 18 | 19 | import java.util.Map; 20 | 21 | import javax.annotation.Nonnull; 22 | import javax.annotation.Nullable; 23 | 24 | import com.helger.commons.annotation.Nonempty; 25 | import com.helger.commons.email.EmailAddress; 26 | import com.helger.photon.core.interror.InternalErrorBuilder; 27 | import com.helger.photon.core.interror.InternalErrorSettings; 28 | import com.helger.photon.core.interror.callback.AbstractErrorCallback; 29 | import com.helger.photon.core.mgr.PhotonCoreManager; 30 | import com.helger.photon.core.smtp.CNamedSMTPSettings; 31 | import com.helger.photon.core.smtp.NamedSMTPSettings; 32 | import com.helger.smtp.settings.ISMTPSettings; 33 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 34 | 35 | public final class AppInternalErrorHandler extends AbstractErrorCallback 36 | { 37 | @Override 38 | protected void onError (@Nonnull final Throwable t, 39 | @Nullable final IRequestWebScopeWithoutResponse aRequestScope, 40 | @Nonnull @Nonempty final String sErrorCode, 41 | @Nullable final Map aCustomAttrs) 42 | { 43 | new InternalErrorBuilder ().setThrowable (t) 44 | .setRequestScope (aRequestScope) 45 | .addErrorMessage (sErrorCode) 46 | .addCustomData (aCustomAttrs) 47 | .handle (); 48 | } 49 | 50 | public static void doSetup () 51 | { 52 | // Set global internal error handlers 53 | new AppInternalErrorHandler ().install (); 54 | 55 | final NamedSMTPSettings aNamedSettings = PhotonCoreManager.getSMTPSettingsMgr () 56 | .getSettings (CNamedSMTPSettings.NAMED_SMTP_SETTINGS_DEFAULT_ID); 57 | final ISMTPSettings aSMTPSettings = aNamedSettings == null ? null : aNamedSettings.getSMTPSettings (); 58 | InternalErrorSettings.setSMTPSenderAddress (new EmailAddress ("peppol@helger.com", "peppol.helger.com application")); 59 | InternalErrorSettings.setSMTPReceiverAddress (new EmailAddress ("philip@helger.com", "Philip")); 60 | InternalErrorSettings.setSMTPSettings (aSMTPSettings); 61 | InternalErrorSettings.setFallbackLocale (CPPApp.DEFAULT_LOCALE); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/CPPApp.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app; 18 | 19 | import java.util.List; 20 | import java.util.Locale; 21 | 22 | import javax.annotation.concurrent.Immutable; 23 | 24 | import com.helger.commons.annotation.CodingStyleguideUnaware; 25 | import com.helger.commons.collection.impl.CommonsArrayList; 26 | import com.helger.commons.collection.impl.ICommonsMap; 27 | import com.helger.commons.type.ObjectType; 28 | import com.helger.peppol.sharedui.CSharedUI; 29 | import com.helger.photon.security.CSecurity; 30 | 31 | /** 32 | * Contains application wide constants. 33 | * 34 | * @author Philip Helger 35 | */ 36 | @Immutable 37 | public final class CPPApp 38 | { 39 | public static final Locale DEFAULT_LOCALE = CSharedUI.LOCALE_EN; 40 | 41 | // Security roles 42 | public static final String ROLE_VIEW_ID = "view"; 43 | public static final String ROLE_VIEW_NAME = "View user"; 44 | public static final String ROLE_VIEW_DESCRIPTION = null; 45 | public static final ICommonsMap ROLE_VIEW_CUSTOMATTRS = null; 46 | public static final String ROLE_COMMENT_MODERATOR_ID = "commentmod"; 47 | public static final String ROLE_COMMENT_MODERATOR_NAME = "Comment moderator"; 48 | public static final String ROLE_COMMENT_MODERATOR_DESCRIPTION = null; 49 | public static final ICommonsMap ROLE_COMMENT_MODERATOR_CUSTOMATTRS = null; 50 | public static final String ROLE_PEPPOL_SENDERS_ID = "peppolsenders"; 51 | public static final String ROLE_PEPPOL_SENDERS_NAME = "Peppol Sender"; 52 | public static final String ROLE_PEPPOL_SENDERS_DESCRIPTION = null; 53 | public static final ICommonsMap ROLE_PEPPOL_SENDERS_CUSTOMATTRS = null; 54 | 55 | @CodingStyleguideUnaware 56 | public static final List REQUIRED_ROLE_IDS_VIEW = new CommonsArrayList <> (ROLE_VIEW_ID).getAsUnmodifiable (); 57 | 58 | // User groups 59 | public static final String USERGROUP_ADMINISTRATORS_ID = CSecurity.USERGROUP_ADMINISTRATORS_ID; 60 | public static final String USERGROUP_ADMINISTRATORS_NAME = CSecurity.USERGROUP_ADMINISTRATORS_NAME; 61 | public static final String USERGROUP_ADMINISTRATORS_DESCRIPTION = null; 62 | public static final ICommonsMap USERGROUP_ADMINISTRATORS_CUSTOMATTRS = null; 63 | public static final String USERGROUP_CONFIG_ID = "ugconfig"; 64 | public static final String USERGROUP_CONFIG_NAME = "Config user"; 65 | public static final String USERGROUP_CONFIG_DESCRIPTION = null; 66 | public static final ICommonsMap USERGROUP_CONFIG_CUSTOMATTRS = null; 67 | public static final String USERGROUP_VIEW_ID = "ugview"; 68 | public static final String USERGROUP_VIEW_NAME = "View user"; 69 | public static final String USERGROUP_VIEW_DESCRIPTION = null; 70 | public static final ICommonsMap USERGROUP_VIEW_CUSTOMATTRS = null; 71 | 72 | // User ID 73 | public static final String USER_ADMINISTRATOR_ID = CSecurity.USER_ADMINISTRATOR_ID; 74 | public static final String USER_ADMINISTRATOR_LOGINNAME = CSecurity.USER_ADMINISTRATOR_EMAIL; 75 | public static final String USER_ADMINISTRATOR_EMAIL = CSecurity.USER_ADMINISTRATOR_EMAIL; 76 | public static final String USER_ADMINISTRATOR_PASSWORD = CSecurity.USER_ADMINISTRATOR_PASSWORD; 77 | public static final String USER_ADMINISTRATOR_FIRSTNAME = null; 78 | public static final String USER_ADMINISTRATOR_LASTNAME = CSecurity.USER_ADMINISTRATOR_NAME; 79 | public static final String USER_ADMINISTRATOR_DESCRIPTION = null; 80 | public static final Locale USER_ADMINISTRATOR_LOCALE = CPPApp.DEFAULT_LOCALE; 81 | public static final ICommonsMap USER_ADMINISTRATOR_CUSTOMATTRS = null; 82 | 83 | public static final ObjectType OT_PAGE = new ObjectType ("webpage"); 84 | 85 | private CPPApp () 86 | {} 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/ajax/AjaxExecutorCommentShowInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app.ajax; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import com.helger.commons.string.StringHelper; 25 | import com.helger.commons.type.ITypedObject; 26 | import com.helger.commons.type.ObjectType; 27 | import com.helger.commons.type.TypedObject; 28 | import com.helger.html.hc.IHCNode; 29 | import com.helger.peppol.comment.domain.CommentThreadManager; 30 | import com.helger.peppol.comment.domain.IComment; 31 | import com.helger.peppol.comment.domain.ICommentThread; 32 | import com.helger.peppol.comment.ui.CommentSecurity; 33 | import com.helger.peppol.comment.ui.CommentUI; 34 | import com.helger.photon.ajax.executor.IAjaxExecutor; 35 | import com.helger.photon.app.PhotonUnifiedResponse; 36 | import com.helger.photon.core.execcontext.LayoutExecutionContext; 37 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 38 | 39 | /** 40 | * AJAX handler for deleting a single comment 41 | * 42 | * @author Philip Helger 43 | */ 44 | public final class AjaxExecutorCommentShowInput implements IAjaxExecutor 45 | { 46 | public static final String PARAM_OBJECT_TYPE = "objectType"; 47 | public static final String PARAM_OBJECT_ID = "objectID"; 48 | public static final String PARAM_COMMENT_THREAD_ID = "commentThreadID"; 49 | public static final String PARAM_COMMENT_ID = "commentID"; 50 | public static final String PARAM_RESULT_DIV_ID = "resultDivID"; 51 | private static final Logger LOGGER = LoggerFactory.getLogger (AjaxExecutorCommentShowInput.class); 52 | 53 | public void handleRequest (@Nonnull final IRequestWebScopeWithoutResponse aRequestScope, 54 | @Nonnull final PhotonUnifiedResponse aAjaxResponse) throws Exception 55 | { 56 | final LayoutExecutionContext aLEC = LayoutExecutionContext.createForAjaxOrAction (aRequestScope); 57 | final String sObjectType = aRequestScope.params ().getAsString (PARAM_OBJECT_TYPE); 58 | final String sObjectID = aRequestScope.params ().getAsString (PARAM_OBJECT_ID); 59 | final String sCommentThreadID = aRequestScope.params ().getAsString (PARAM_COMMENT_THREAD_ID); 60 | final String sCommentID = aRequestScope.params ().getAsString (PARAM_COMMENT_ID); 61 | final String sResultDivID = aRequestScope.params ().getAsString (PARAM_RESULT_DIV_ID); 62 | 63 | if (StringHelper.hasText (sObjectType) && 64 | StringHelper.hasText (sObjectID) && 65 | StringHelper.hasText (sCommentThreadID) && 66 | StringHelper.hasText (sCommentID) && 67 | CommentSecurity.canCurrentUserPostComments ()) 68 | { 69 | // Create a dummy object 70 | final ITypedObject aOwner = TypedObject.create (new ObjectType (sObjectType), sObjectID); 71 | 72 | final ICommentThread aCommentThread = CommentThreadManager.getInstance ().getCommentThreadOfID (aOwner, sCommentThreadID); 73 | if (aCommentThread != null) 74 | { 75 | final IComment aParentComment = aCommentThread.getCommentOfID (sCommentID); 76 | if (aParentComment != null) 77 | { 78 | // response 79 | final IHCNode aNode = CommentUI.getCreateComment (aLEC, sResultDivID, aOwner, aCommentThread, aParentComment, null, null); 80 | aAjaxResponse.html (aNode); 81 | return; 82 | } 83 | } 84 | } 85 | 86 | // Somebody played around with the API 87 | LOGGER.warn ("Failed to resolve comment object type '" + 88 | sObjectType + 89 | "' and/or object ID '" + 90 | sObjectID + 91 | "' for showing input of comment '" + 92 | sCommentID + 93 | "' in thread '" + 94 | sCommentThreadID + 95 | "'"); 96 | aAjaxResponse.createNotFound (); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/ajax/AjaxExecutorPublicLogin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app.ajax; 18 | 19 | import java.util.Locale; 20 | 21 | import javax.annotation.Nonnull; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import com.helger.commons.debug.GlobalDebug; 27 | import com.helger.html.hc.render.HCRenderer; 28 | import com.helger.json.JsonObject; 29 | import com.helger.photon.ajax.executor.IAjaxExecutor; 30 | import com.helger.photon.app.PhotonUnifiedResponse; 31 | import com.helger.photon.bootstrap4.alert.BootstrapErrorBox; 32 | import com.helger.photon.bootstrap4.traits.IHCBootstrap4Trait; 33 | import com.helger.photon.core.EPhotonCoreText; 34 | import com.helger.photon.core.execcontext.LayoutExecutionContext; 35 | import com.helger.photon.core.login.CLogin; 36 | import com.helger.photon.security.login.ELoginResult; 37 | import com.helger.photon.security.login.LoggedInUserManager; 38 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 39 | 40 | /** 41 | * Ajax executor to login a user from public application. 42 | * 43 | * @author Philip Helger 44 | */ 45 | public final class AjaxExecutorPublicLogin implements IAjaxExecutor, IHCBootstrap4Trait 46 | { 47 | public static final String JSON_LOGGEDIN = "loggedin"; 48 | public static final String JSON_HTML = "html"; 49 | private static final Logger LOGGER = LoggerFactory.getLogger (AjaxExecutorPublicLogin.class); 50 | 51 | public void handleRequest (@Nonnull final IRequestWebScopeWithoutResponse aRequestScope, 52 | @Nonnull final PhotonUnifiedResponse aAjaxResponse) throws Exception 53 | { 54 | final LayoutExecutionContext aLEC = LayoutExecutionContext.createForAjaxOrAction (aRequestScope); 55 | final String sLoginName = aRequestScope.params ().getAsString (CLogin.REQUEST_ATTR_USERID); 56 | final String sPassword = aRequestScope.params ().getAsString (CLogin.REQUEST_ATTR_PASSWORD); 57 | 58 | // Main login 59 | final ELoginResult eLoginResult = LoggedInUserManager.getInstance ().loginUser (sLoginName, sPassword); 60 | if (eLoginResult.isSuccess ()) 61 | { 62 | aAjaxResponse.json (new JsonObject ().add (JSON_LOGGEDIN, true)); 63 | } 64 | else 65 | { 66 | // Get the rendered content of the menu area 67 | if (GlobalDebug.isDebugMode ()) 68 | LOGGER.warn ("Login of '" + sLoginName + "' failed because " + eLoginResult); 69 | 70 | final Locale aDisplayLocale = aLEC.getDisplayLocale (); 71 | final BootstrapErrorBox aRoot = error (EPhotonCoreText.LOGIN_ERROR_MSG.getDisplayText (aDisplayLocale) + 72 | " " + 73 | eLoginResult.getDisplayText (aDisplayLocale)); 74 | 75 | // Set as result property 76 | aAjaxResponse.json (new JsonObject ().add (JSON_LOGGEDIN, false) 77 | .add (JSON_HTML, HCRenderer.getAsHTMLStringWithoutNamespaces (aRoot))); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/ajax/AjaxExecutorPublicUpdateMenuView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app.ajax; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import com.helger.html.hc.IHCNode; 22 | import com.helger.peppol.pub.LayoutAreaContentProviderPublic; 23 | import com.helger.photon.ajax.executor.IAjaxExecutor; 24 | import com.helger.photon.app.PhotonUnifiedResponse; 25 | import com.helger.photon.core.execcontext.LayoutExecutionContext; 26 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 27 | 28 | /** 29 | * Ajax executor to get the update content the public application's menu. 30 | * 31 | * @author Philip Helger 32 | */ 33 | public final class AjaxExecutorPublicUpdateMenuView implements IAjaxExecutor 34 | { 35 | public void handleRequest (@Nonnull final IRequestWebScopeWithoutResponse aRequestScope, 36 | @Nonnull final PhotonUnifiedResponse aAjaxResponse) throws Exception 37 | { 38 | final LayoutExecutionContext aLEC = LayoutExecutionContext.createForAjaxOrAction (aRequestScope); 39 | 40 | // Get the rendered content of the menu area 41 | final IHCNode aRoot = LayoutAreaContentProviderPublic.getMenuContent (aLEC); 42 | 43 | // Set as result property 44 | aAjaxResponse.html (aRoot); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/ajax/AjaxExecutorSecureUpdateMenuView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app.ajax; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import com.helger.html.hc.IHCNode; 22 | import com.helger.peppol.secure.LayoutAreaContentProviderSecure; 23 | import com.helger.photon.ajax.executor.IAjaxExecutor; 24 | import com.helger.photon.app.PhotonUnifiedResponse; 25 | import com.helger.photon.core.execcontext.LayoutExecutionContext; 26 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 27 | 28 | /** 29 | * Ajax executor to get the update content the secure application's menu. 30 | * 31 | * @author Philip Helger 32 | */ 33 | public final class AjaxExecutorSecureUpdateMenuView implements IAjaxExecutor 34 | { 35 | public void handleRequest (@Nonnull final IRequestWebScopeWithoutResponse aRequestScope, 36 | @Nonnull final PhotonUnifiedResponse aAjaxResponse) throws Exception 37 | { 38 | final LayoutExecutionContext aLEC = LayoutExecutionContext.createForAjaxOrAction (aRequestScope); 39 | 40 | // Get the rendered content of the menu area 41 | final IHCNode aRoot = LayoutAreaContentProviderSecure.getMenuContent (aLEC); 42 | 43 | // Set as result property 44 | aAjaxResponse.html (aRoot); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/ajax/CAjax.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app.ajax; 18 | 19 | import javax.annotation.concurrent.Immutable; 20 | 21 | import com.helger.peppol.sharedui.api.CSharedUIAjax; 22 | import com.helger.photon.ajax.decl.AjaxFunctionDeclaration; 23 | import com.helger.photon.ajax.decl.IAjaxFunctionDeclaration; 24 | 25 | /** 26 | * This class defines the available ajax functions for the view application. 27 | * 28 | * @author Philip Helger 29 | */ 30 | @Immutable 31 | public final class CAjax 32 | { 33 | public static final IAjaxFunctionDeclaration LOGIN = AjaxFunctionDeclaration.builder ("login") 34 | .executor (AjaxExecutorPublicLogin.class) 35 | .build (); 36 | public static final IAjaxFunctionDeclaration UPDATE_MENU_VIEW_PUB = AjaxFunctionDeclaration.builder ("updateMenuViewPub") 37 | .executor (AjaxExecutorPublicUpdateMenuView.class) 38 | .build (); 39 | public static final IAjaxFunctionDeclaration UPDATE_MENU_VIEW_SEC = AjaxFunctionDeclaration.builder ("updateMenuViewSec") 40 | .executor (AjaxExecutorSecureUpdateMenuView.class) 41 | .filter (CSharedUIAjax.FILTER_LOGIN) 42 | .build (); 43 | public static final IAjaxFunctionDeclaration COMMENT_ADD = AjaxFunctionDeclaration.builder ("addComment") 44 | .executor (AjaxExecutorCommentAdd.class) 45 | .filter (CSharedUIAjax.FILTER_LOGIN) 46 | .build (); 47 | public static final IAjaxFunctionDeclaration COMMENT_CREATE_THREAD = AjaxFunctionDeclaration.builder ("createThread") 48 | .executor (AjaxExecutorCommentCreateThread.class) 49 | .filter (CSharedUIAjax.FILTER_LOGIN) 50 | .build (); 51 | public static final IAjaxFunctionDeclaration COMMENT_DELETE = AjaxFunctionDeclaration.builder ("deleteComment") 52 | .executor (AjaxExecutorCommentDelete.class) 53 | .filter (CSharedUIAjax.FILTER_LOGIN) 54 | .build (); 55 | public static final IAjaxFunctionDeclaration COMMENT_SHOW_INPUT = AjaxFunctionDeclaration.builder ("showInputForm") 56 | .executor (AjaxExecutorCommentShowInput.class) 57 | .filter (CSharedUIAjax.FILTER_LOGIN) 58 | .build (); 59 | 60 | private CAjax () 61 | {} 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/config/AppMicroTypeConverterRegistarSPI.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app.config; 18 | 19 | import com.helger.commons.annotation.IsSPIImplementation; 20 | import com.helger.peppol.comment.domain.Comment; 21 | import com.helger.peppol.comment.domain.CommentMicroTypeConverter; 22 | import com.helger.peppol.comment.domain.CommentThread; 23 | import com.helger.peppol.comment.domain.CommentThreadMicroTypeConverter; 24 | import com.helger.peppol.crm.CRMGroup; 25 | import com.helger.peppol.crm.CRMGroupMicroTypeConverter; 26 | import com.helger.peppol.crm.CRMSubscriber; 27 | import com.helger.peppol.crm.CRMSubscriberMicroTypeConverter; 28 | import com.helger.peppol.testendpoint.TestEndpoint; 29 | import com.helger.peppol.testendpoint.TestEndpointMicroTypeConverter; 30 | import com.helger.xml.microdom.convert.IMicroTypeConverterRegistrarSPI; 31 | import com.helger.xml.microdom.convert.IMicroTypeConverterRegistry; 32 | 33 | /** 34 | * SPI implementation to register all micro type converters of this application. 35 | * 36 | * @author Philip Helger 37 | */ 38 | @IsSPIImplementation 39 | public final class AppMicroTypeConverterRegistarSPI implements IMicroTypeConverterRegistrarSPI 40 | { 41 | public void registerMicroTypeConverter (final IMicroTypeConverterRegistry aRegistry) 42 | { 43 | // CRM stuff 44 | aRegistry.registerMicroElementTypeConverter (CRMGroup.class, new CRMGroupMicroTypeConverter ()); 45 | aRegistry.registerMicroElementTypeConverter (CRMSubscriber.class, new CRMSubscriberMicroTypeConverter ()); 46 | // Comment stuff 47 | aRegistry.registerMicroElementTypeConverter (Comment.class, new CommentMicroTypeConverter ()); 48 | aRegistry.registerMicroElementTypeConverter (CommentThread.class, new CommentThreadMicroTypeConverter ()); 49 | // Test Endpoint 50 | aRegistry.registerMicroElementTypeConverter (TestEndpoint.class, new TestEndpointMicroTypeConverter ()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/app/mgr/PPMetaManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.app.mgr; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import com.helger.commons.annotation.UsedViaReflection; 25 | import com.helger.commons.exception.InitializationException; 26 | import com.helger.dao.DAOException; 27 | import com.helger.peppol.crm.CRMGroupManager; 28 | import com.helger.peppol.crm.CRMSubscriberManager; 29 | import com.helger.peppol.testendpoint.TestEndpointManager; 30 | import com.helger.scope.IScope; 31 | import com.helger.scope.singleton.AbstractGlobalSingleton; 32 | 33 | /** 34 | * Central manager for all sub managers 35 | * 36 | * @author Philip Helger 37 | */ 38 | public final class PPMetaManager extends AbstractGlobalSingleton 39 | { 40 | public static final String CRMGROUP_XML = "crm/group.xml"; 41 | public static final String CRMSUBSCRIBER_XML = "crm/subscriber.xml"; 42 | public static final String TEST_ENDPOINT_XML = "test-endpoint.xml"; 43 | 44 | private static final Logger LOGGER = LoggerFactory.getLogger (PPMetaManager.class); 45 | 46 | private CRMGroupManager m_aCRMGroupMgr; 47 | private CRMSubscriberManager m_aCRMSubscriberMgr; 48 | private TestEndpointManager m_aTestEndpointMgr; 49 | 50 | @Deprecated 51 | @UsedViaReflection 52 | public PPMetaManager () 53 | {} 54 | 55 | @Override 56 | protected void onAfterInstantiation (@Nonnull final IScope aScope) 57 | { 58 | try 59 | { 60 | m_aCRMGroupMgr = new CRMGroupManager (CRMGROUP_XML); 61 | m_aCRMSubscriberMgr = new CRMSubscriberManager (CRMSUBSCRIBER_XML); 62 | m_aTestEndpointMgr = new TestEndpointManager (TEST_ENDPOINT_XML); 63 | 64 | LOGGER.info (getClass ().getName () + " was initialized"); 65 | } 66 | catch (final DAOException ex) 67 | { 68 | throw new InitializationException ("Failed to init " + getClass ().getName (), ex); 69 | } 70 | } 71 | 72 | @Nonnull 73 | public static PPMetaManager getInstance () 74 | { 75 | return getGlobalSingleton (PPMetaManager.class); 76 | } 77 | 78 | @Nonnull 79 | public static CRMGroupManager getCRMGroupMgr () 80 | { 81 | return getInstance ().m_aCRMGroupMgr; 82 | } 83 | 84 | @Nonnull 85 | public static CRMSubscriberManager getCRMSubscriberMgr () 86 | { 87 | return getInstance ().m_aCRMSubscriberMgr; 88 | } 89 | 90 | @Nonnull 91 | public static TestEndpointManager getTestEndpointMgr () 92 | { 93 | return getInstance ().m_aTestEndpointMgr; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/domain/CommentThreadMicroTypeConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | import javax.annotation.concurrent.Immutable; 22 | 23 | import com.helger.tree.withid.unique.DefaultTreeWithGlobalUniqueID; 24 | import com.helger.tree.xml.IConverterTreeXML; 25 | import com.helger.tree.xml.MicroTypeConverterTreeXML; 26 | import com.helger.tree.xml.TreeXMLConverter; 27 | import com.helger.xml.microdom.IMicroElement; 28 | import com.helger.xml.microdom.MicroElement; 29 | import com.helger.xml.microdom.convert.IMicroTypeConverter; 30 | 31 | @Immutable 32 | public final class CommentThreadMicroTypeConverter implements IMicroTypeConverter 33 | { 34 | private static final String ELEMENT_COMMENT = "comment"; 35 | 36 | @Nonnull 37 | public IMicroElement convertToMicroElement (@Nonnull final CommentThread aValue, 38 | @Nullable final String sNamespaceURI, 39 | @Nonnull final String sTagName) 40 | { 41 | final IMicroElement eCommentThread = new MicroElement (sNamespaceURI, sTagName); 42 | 43 | final IConverterTreeXML aXMLConverter = new MicroTypeConverterTreeXML <> (sNamespaceURI, ELEMENT_COMMENT, Comment.class); 44 | eCommentThread.appendChild (TreeXMLConverter.getTreeWithStringIDAsXML (aValue.getTree (), aXMLConverter)); 45 | return eCommentThread; 46 | } 47 | 48 | @Nonnull 49 | public CommentThread convertToNative (@Nonnull final IMicroElement eCommentThread) 50 | { 51 | final IConverterTreeXML aXMLConverter = new MicroTypeConverterTreeXML <> (eCommentThread.getNamespaceURI (), 52 | ELEMENT_COMMENT, 53 | Comment.class); 54 | final DefaultTreeWithGlobalUniqueID aTree = TreeXMLConverter.getXMLAsTreeWithUniqueStringID (eCommentThread.getFirstChildElement (), 55 | aXMLConverter); 56 | 57 | // Main add 58 | return new CommentThread (aTree); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/domain/ECommentState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import java.util.Locale; 20 | 21 | import javax.annotation.Nonnull; 22 | import javax.annotation.Nullable; 23 | 24 | import com.helger.commons.annotation.Nonempty; 25 | import com.helger.commons.id.IHasID; 26 | import com.helger.commons.lang.EnumHelper; 27 | import com.helger.commons.text.display.IHasDisplayText; 28 | 29 | /** 30 | * Represents the different comment states. 31 | * 32 | * @author Philip Helger 33 | */ 34 | public enum ECommentState implements IHasID , IHasDisplayText 35 | { 36 | /** Moderation is enabled, and this comment needs approval. */ 37 | TO_BE_APPROVED ("tobeapproved", ECommentStateText.TO_BE_APPROVED), 38 | /** This comment is already approved, or moderation is disabled. */ 39 | APPROVED ("approved", ECommentStateText.APPROVED), 40 | /** This comment was rejected by the moderator. */ 41 | REJECTED ("rejected", ECommentStateText.REJECTED), 42 | /** This comment was deleted by the user itself. */ 43 | DELETED_BY_USER ("deletedbyuser", ECommentStateText.DELETED_BY_USER), 44 | /** This comment was deleted by a moderator. */ 45 | DELETED_BY_MODERATOR ("deletedbymoderator", ECommentStateText.DELETED_BY_MODERATOR); 46 | 47 | private final String m_sID; 48 | private final ECommentStateText m_aDisplayText; 49 | 50 | private ECommentState (@Nonnull @Nonempty final String sID, @Nonnull final ECommentStateText aDisplayText) 51 | { 52 | m_sID = sID; 53 | m_aDisplayText = aDisplayText; 54 | } 55 | 56 | @Nonnull 57 | @Nonempty 58 | public String getID () 59 | { 60 | return m_sID; 61 | } 62 | 63 | @Nonnull 64 | @Nonempty 65 | public String getShortcut () 66 | { 67 | return m_sID; 68 | } 69 | 70 | @Nullable 71 | public String getDisplayText (@Nonnull final Locale aContentLocale) 72 | { 73 | return m_aDisplayText.getDisplayText (aContentLocale); 74 | } 75 | 76 | public boolean isSuitableForCreation () 77 | { 78 | return this == TO_BE_APPROVED || this == APPROVED; 79 | } 80 | 81 | public boolean isApproved () 82 | { 83 | return this == APPROVED; 84 | } 85 | 86 | public boolean isDeleted () 87 | { 88 | return this == DELETED_BY_USER || this == DELETED_BY_MODERATOR; 89 | } 90 | 91 | @Nullable 92 | public static ECommentState getFromIDOrNull (@Nullable final String sID) 93 | { 94 | return EnumHelper.getFromIDOrNull (ECommentState.class, sID); 95 | } 96 | 97 | @Nullable 98 | public static ECommentState getFromIDOrDefault (@Nullable final String sID, @Nullable final ECommentState eDefault) 99 | { 100 | return EnumHelper.getFromIDOrDefault (ECommentState.class, sID, eDefault); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/domain/ECommentStateText.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import java.util.Locale; 20 | 21 | import javax.annotation.Nonnull; 22 | import javax.annotation.Nullable; 23 | 24 | import com.helger.commons.annotation.Translatable; 25 | import com.helger.commons.text.IMultilingualText; 26 | import com.helger.commons.text.display.IHasDisplayText; 27 | import com.helger.commons.text.resolve.DefaultTextResolver; 28 | import com.helger.commons.text.util.TextHelper; 29 | 30 | @Translatable 31 | public enum ECommentStateText implements IHasDisplayText 32 | { 33 | TO_BE_APPROVED ("erwartet Freigabe", "to be approved"), 34 | APPROVED ("freigegeben", "approved"), 35 | REJECTED ("abgelehnt", "rejected"), 36 | DELETED_BY_USER ("vom Benutzer gelöscht", "deleted by user"), 37 | DELETED_BY_MODERATOR ("vom Moderator gelöscht", "deleted by moderator"); 38 | 39 | private final IMultilingualText m_aTP; 40 | 41 | private ECommentStateText (@Nonnull final String sDE, @Nonnull final String sEN) 42 | { 43 | m_aTP = TextHelper.create_DE_EN (sDE, sEN); 44 | } 45 | 46 | @Nullable 47 | public String getDisplayText (@Nonnull final Locale aContentLocale) 48 | { 49 | return DefaultTextResolver.getTextStatic (this, m_aTP, aContentLocale); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/domain/IComment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import java.io.Serializable; 20 | import java.time.LocalDateTime; 21 | 22 | import javax.annotation.Nonnegative; 23 | import javax.annotation.Nonnull; 24 | import javax.annotation.Nullable; 25 | 26 | import com.helger.commons.annotation.MustImplementEqualsAndHashcode; 27 | import com.helger.commons.annotation.Nonempty; 28 | import com.helger.commons.state.EChange; 29 | import com.helger.commons.type.ITypedObject; 30 | import com.helger.datetime.domain.IHasCreationDateTime; 31 | import com.helger.datetime.domain.IHasLastModificationDateTime; 32 | import com.helger.security.authentication.subject.user.IHasUserID; 33 | 34 | /** 35 | * Interface for a single comment object. It is not directly linked to the 36 | * object to which the comment is attached. Each comment belongs to an 37 | * {@link ICommentThread}. 38 | * 39 | * @author Philip Helger 40 | */ 41 | @MustImplementEqualsAndHashcode 42 | public interface IComment extends ITypedObject , IHasCreationDateTime, IHasLastModificationDateTime, Serializable, IHasUserID 43 | { 44 | // status vars 45 | 46 | /** 47 | * @return The IP address or host from which the comment was triggered. This 48 | * is used to identify spammers and block IP addresses. 49 | */ 50 | @Nonnull 51 | @Nonempty 52 | String getHost (); 53 | 54 | /** 55 | * @return The state of this comment. 56 | */ 57 | @Nonnull 58 | ECommentState getState (); 59 | 60 | /** 61 | * Change the state of the comment. 62 | * 63 | * @param eState 64 | * The new state. May not be null. 65 | * @return {@link EChange} 66 | */ 67 | @Nonnull 68 | EChange setState (@Nonnull ECommentState eState); 69 | 70 | /** 71 | * @return true if this comment was deleted 72 | */ 73 | boolean isDeleted (); 74 | 75 | /** 76 | * @return How often was this commented edited. This is 0 if the comment was 77 | * just created and never edited. 78 | */ 79 | @Nonnegative 80 | int getEditCount (); 81 | 82 | /** 83 | * Increment the edit count and set the last modification date time to now. 84 | */ 85 | void onCommentEdited (); 86 | 87 | /** 88 | * @return How often was the entry reported as spam. Always ≥ 0. 89 | */ 90 | @Nonnegative 91 | int getSpamReportCount (); 92 | 93 | /** 94 | * Increment the spam report count. 95 | */ 96 | void onCommentSpamReport (); 97 | 98 | // content vars 99 | 100 | /** 101 | * @return The last modification date time or if not present the creation date 102 | * time. 103 | */ 104 | @Nonnull 105 | LocalDateTime getLastChangeDateTime (); 106 | 107 | /** 108 | * @return The user who created the comment. May be null for 109 | * public comments. One of userID or creator name must be present. 110 | */ 111 | @Nullable 112 | String getUserID (); 113 | 114 | /** 115 | * @return The name of the person who created the comment. May be 116 | * null for restricted comments. One of userID or creator 117 | * name must be present. 118 | */ 119 | @Nullable 120 | String getCreatorName (); 121 | 122 | /** 123 | * @return The comment title. May be null. 124 | */ 125 | @Nullable 126 | String getTitle (); 127 | 128 | /** 129 | * @return The main comment text. May not be null. 130 | */ 131 | @Nonnull 132 | String getText (); 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/domain/ICommentIterationCallback.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import javax.annotation.Nonnegative; 20 | import javax.annotation.Nonnull; 21 | import javax.annotation.Nullable; 22 | 23 | /** 24 | * Callback interface for iterating all comments within a comment thread 25 | * 26 | * @author Philip Helger 27 | */ 28 | public interface ICommentIterationCallback 29 | { 30 | /** 31 | * Called for each comment within a comment thread 32 | * 33 | * @param nLevel 34 | * Current nesting level 35 | * @param aParentComment 36 | * The parent comment - is null for the top-level entry 37 | * @param aComment 38 | * The current comment 39 | */ 40 | default void onCommentStart (@Nonnegative final int nLevel, @Nullable final IComment aParentComment, @Nonnull final IComment aComment) 41 | {} 42 | 43 | /** 44 | * Called for each comment within a comment thread 45 | * 46 | * @param nLevel 47 | * Current nesting level 48 | * @param aParentComment 49 | * The parent comment - is null for the top-level entry 50 | * @param aComment 51 | * The current comment 52 | */ 53 | default void onCommentEnd (@Nonnegative final int nLevel, @Nullable final IComment aParentComment, @Nonnull final IComment aComment) 54 | {} 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/domain/ICommentThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import java.time.LocalDateTime; 20 | import java.util.Collection; 21 | 22 | import javax.annotation.Nonnegative; 23 | import javax.annotation.Nonnull; 24 | import javax.annotation.Nullable; 25 | 26 | import com.helger.commons.annotation.MustImplementEqualsAndHashcode; 27 | import com.helger.commons.annotation.ReturnsMutableCopy; 28 | import com.helger.commons.state.EChange; 29 | import com.helger.commons.type.ITypedObject; 30 | import com.helger.tree.withid.unique.DefaultTreeWithGlobalUniqueID; 31 | 32 | /** 33 | * Interface for a single comment thread. It holds {@link IComment} objects in a 34 | * tree structured way. 35 | * 36 | * @author Philip Helger 37 | */ 38 | @MustImplementEqualsAndHashcode 39 | public interface ICommentThread extends ITypedObject 40 | { 41 | @Nonnull 42 | DefaultTreeWithGlobalUniqueID getTree (); 43 | 44 | /** 45 | * @return The comment that started this thread. Never null. 46 | */ 47 | @Nonnull 48 | IComment getInitialComment (); 49 | 50 | /** 51 | * @return The creation date time of the first comment that started this 52 | * thread. Never null. 53 | */ 54 | @Nonnull 55 | default LocalDateTime getInitialCommentCreationDateTime () 56 | { 57 | return getInitialComment ().getCreationDateTime (); 58 | } 59 | 60 | /** 61 | * Add a comment to this thread. 62 | * 63 | * @param aParentComment 64 | * The non-null parent comment 65 | * @param aNewComment 66 | * The comment to be added as an answer to the the parent comment 67 | * @return the added comment 68 | */ 69 | @Nonnull 70 | IComment addComment (@Nonnull IComment aParentComment, @Nonnull IComment aNewComment); 71 | 72 | /** 73 | * Delete a comment FROM this thread. 74 | * 75 | * @param sCommentID 76 | * The ID of the comment to be removed. May be null. 77 | * @param eNewState 78 | * The new state to be set. May not be null. 79 | * @return {@link EChange} 80 | */ 81 | @Nonnull 82 | EChange updateCommentState (@Nullable String sCommentID, @Nonnull ECommentState eNewState); 83 | 84 | /** 85 | * @return The total comment count. Always ≥ 0. 86 | */ 87 | @Nonnegative 88 | int getTotalCommentCount (); 89 | 90 | /** 91 | * @return A list of all comments in this thread 92 | */ 93 | @Nonnull 94 | @ReturnsMutableCopy 95 | Collection getAllComments (); 96 | 97 | /** 98 | * @return The total active (not deleted) comment count. Always ≥ 0. 99 | */ 100 | @Nonnegative 101 | int getTotalActiveCommentCount (); 102 | 103 | /** 104 | * @return A list of all active (not deleted) comments in this thread 105 | */ 106 | @Nonnull 107 | @ReturnsMutableCopy 108 | Collection getAllActiveComments (); 109 | 110 | /** 111 | * Get the comment with the passed ID within this thread 112 | * 113 | * @param sCommentID 114 | * The ID to search 115 | * @return null if no such comment exists 116 | */ 117 | @Nullable 118 | IComment getCommentOfID (@Nullable String sCommentID); 119 | 120 | /** 121 | * Iterate the comment tree in this thread 122 | * 123 | * @param aCallback 124 | * The callback handler to invoke. May not be null. 125 | */ 126 | void iterateAllComments (@Nonnull ICommentIterationCallback aCallback); 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/ui/CCommentCSS.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.ui; 18 | 19 | import javax.annotation.concurrent.Immutable; 20 | 21 | import com.helger.html.css.DefaultCSSClassProvider; 22 | import com.helger.html.css.ICSSClassProvider; 23 | 24 | /** 25 | * CSS classes for comments 26 | * 27 | * @author Philip Helger 28 | */ 29 | @Immutable 30 | public final class CCommentCSS 31 | { 32 | // Viewing 33 | public static final ICSSClassProvider CSS_CLASS_COMMENT_CONTAINER = DefaultCSSClassProvider.create ("comment-container"); 34 | public static final ICSSClassProvider CSS_CLASS_COMMENT_THREAD = DefaultCSSClassProvider.create ("comment-thread"); 35 | public static final ICSSClassProvider CSS_CLASS_SINGLE_COMMENT = DefaultCSSClassProvider.create ("comment-single-comment"); 36 | public static final ICSSClassProvider CSS_CLASS_COMMENT_REGISTERED_USER = DefaultCSSClassProvider.create ("comment-registered-user"); 37 | public static final ICSSClassProvider CSS_CLASS_COMMENT_TOOLBAR = DefaultCSSClassProvider.create ("comment-toolbar"); 38 | public static final ICSSClassProvider CSS_CLASS_COMMENT_TITLE = DefaultCSSClassProvider.create ("comment-title"); 39 | public static final ICSSClassProvider CSS_CLASS_COMMENT_TEXT = DefaultCSSClassProvider.create ("comment-text"); 40 | public static final ICSSClassProvider CSS_CLASS_COMMENT_AUTHOR = DefaultCSSClassProvider.create ("comment-author"); 41 | public static final ICSSClassProvider CSS_CLASS_COMMENT_CREATIONDT = DefaultCSSClassProvider.create ("comment-creation-datetime"); 42 | public static final ICSSClassProvider CSS_CLASS_COMMENT_LAST_MODIFICATION = DefaultCSSClassProvider.create ("comment-last-modification"); 43 | 44 | // Creation 45 | public static final ICSSClassProvider CSS_CLASS_COMMENT_CREATE = DefaultCSSClassProvider.create ("comment-create"); 46 | 47 | private CCommentCSS () 48 | {} 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/ui/CommentAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.ui; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | import com.helger.commons.ValueEnforcer; 23 | import com.helger.peppol.comment.domain.IComment; 24 | import com.helger.peppol.comment.domain.ICommentThread; 25 | import com.helger.photon.core.form.FormErrorList; 26 | 27 | public final class CommentAction extends FormErrorList 28 | { 29 | private final ECommentAction m_eCommentAction; 30 | private final ICommentThread m_aCommentThread; 31 | private final IComment m_aParentComment; 32 | 33 | private CommentAction (@Nonnull final ECommentAction eCommentAction, 34 | @Nullable final ICommentThread aCommentThread, 35 | @Nullable final IComment aParentComment) 36 | { 37 | ValueEnforcer.notNull (eCommentAction, "CommentAction"); 38 | m_eCommentAction = eCommentAction; 39 | m_aCommentThread = aCommentThread; 40 | m_aParentComment = aParentComment; 41 | } 42 | 43 | public boolean isMatching (@Nonnull final ECommentAction eAction) 44 | { 45 | return m_eCommentAction.equals (eAction); 46 | } 47 | 48 | public boolean isMatching (@Nullable final ICommentThread aCommentThread, @Nullable final IComment aComment) 49 | { 50 | return m_aCommentThread != null && 51 | m_aCommentThread.equals (aCommentThread) && 52 | m_aParentComment != null && 53 | m_aParentComment.equals (aComment); 54 | } 55 | 56 | public boolean isMatching (@Nonnull final ECommentAction eAction, 57 | @Nullable final ICommentThread aCommentThread, 58 | @Nullable final IComment aComment) 59 | { 60 | return isMatching (eAction) && isMatching (aCommentThread, aComment); 61 | } 62 | 63 | @Nonnull 64 | public ECommentAction getAction () 65 | { 66 | return m_eCommentAction; 67 | } 68 | 69 | @Nullable 70 | public ICommentThread getCommentThread () 71 | { 72 | return m_aCommentThread; 73 | } 74 | 75 | @Nullable 76 | public IComment getParentComment () 77 | { 78 | return m_aParentComment; 79 | } 80 | 81 | @Nonnull 82 | public static CommentAction createGeneric (@Nonnull final ECommentAction eCommentAction) 83 | { 84 | return new CommentAction (eCommentAction, null, null); 85 | } 86 | 87 | @Nonnull 88 | public static CommentAction createForComment (@Nonnull final ECommentAction eCommentAction, 89 | @Nonnull final ICommentThread aCommentThread, 90 | @Nonnull final IComment aParentComment) 91 | { 92 | ValueEnforcer.notNull (aCommentThread, "CommentThread"); 93 | ValueEnforcer.notNull (aParentComment, "ParentComment"); 94 | return new CommentAction (eCommentAction, aCommentThread, aParentComment); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/ui/CommentFormErrors.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.ui; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | import com.helger.commons.ValueEnforcer; 23 | import com.helger.peppol.comment.domain.IComment; 24 | import com.helger.peppol.comment.domain.ICommentThread; 25 | import com.helger.photon.core.form.FormErrorList; 26 | 27 | public final class CommentFormErrors extends FormErrorList 28 | { 29 | private final ICommentThread m_aCommentThread; 30 | private final IComment m_aParentComment; 31 | 32 | private CommentFormErrors (@Nullable final ICommentThread aCommentThread, @Nullable final IComment aParentComment) 33 | { 34 | m_aCommentThread = aCommentThread; 35 | m_aParentComment = aParentComment; 36 | } 37 | 38 | public boolean isForNewThread () 39 | { 40 | return m_aCommentThread == null; 41 | } 42 | 43 | public boolean isReplyTo (@Nullable final ICommentThread aCommentThread, @Nullable final IComment aComment) 44 | { 45 | return m_aCommentThread != null && 46 | m_aCommentThread.equals (aCommentThread) && 47 | m_aParentComment != null && 48 | m_aParentComment.equals (aComment); 49 | } 50 | 51 | @Nullable 52 | public ICommentThread getCommentThread () 53 | { 54 | return m_aCommentThread; 55 | } 56 | 57 | @Nullable 58 | public IComment getParentComment () 59 | { 60 | return m_aParentComment; 61 | } 62 | 63 | @Nonnull 64 | public static CommentFormErrors createForNewThread () 65 | { 66 | return new CommentFormErrors (null, null); 67 | } 68 | 69 | @Nonnull 70 | public static CommentFormErrors createForReply (@Nonnull final ICommentThread aCommentThread, @Nonnull final IComment aParentComment) 71 | { 72 | ValueEnforcer.notNull (aCommentThread, "CommentThread"); 73 | ValueEnforcer.notNull (aParentComment, "ParentComment"); 74 | return new CommentFormErrors (aCommentThread, aParentComment); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/ui/CommentSecurity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.ui; 18 | 19 | import javax.annotation.concurrent.Immutable; 20 | 21 | import com.helger.peppol.app.CPPApp; 22 | import com.helger.photon.security.login.LoggedInUserManager; 23 | import com.helger.photon.security.util.SecurityHelper; 24 | 25 | @Immutable 26 | public final class CommentSecurity 27 | { 28 | private CommentSecurity () 29 | {} 30 | 31 | public static boolean canCurrentUserPostComments () 32 | { 33 | return LoggedInUserManager.getInstance ().isUserLoggedInInCurrentSession (); 34 | } 35 | 36 | public static boolean isCurrentUserCommentModerator () 37 | { 38 | return SecurityHelper.hasCurrentUserRole (CPPApp.ROLE_COMMENT_MODERATOR_ID); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/ui/ECommentAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.ui; 18 | 19 | public enum ECommentAction 20 | { 21 | NONE, 22 | CREATE_THREAD, 23 | ADD_COMMENT, 24 | DELETE_COMMENT; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/comment/ui/ECommentText.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.ui; 18 | 19 | import java.util.Locale; 20 | 21 | import javax.annotation.Nonnull; 22 | import javax.annotation.Nullable; 23 | 24 | import com.helger.commons.annotation.Translatable; 25 | import com.helger.commons.text.IMultilingualText; 26 | import com.helger.commons.text.display.IHasDisplayTextWithArgs; 27 | import com.helger.commons.text.resolve.DefaultTextResolver; 28 | import com.helger.commons.text.util.TextHelper; 29 | 30 | @Translatable 31 | public enum ECommentText implements IHasDisplayTextWithArgs 32 | { 33 | MSG_IS_DELETED ("[gelöscht] ", "[deleted] "), 34 | MSG_BY (" von ", " by "), 35 | MSG_SEPARATOR_AUTHOR_TITLE (" - ", " - "), 36 | TOOLTIP_RESPONSE ("Auf diesen Kommentar antworten", "Reply to this comment"), 37 | TOOLTIP_DELETE ("Diesen Kommentar löschen", "Delete this comment"), 38 | TOOLTIP_HOST ("Quell-Host: {0}", "Original host: {0}"), 39 | MSG_LAST_MODIFICATION ("Letzte Änderung: {0}", "Last modification: {0}"), 40 | MSG_EDITED_AND_LAST_MODIFICATION ("{0} mal bearbeitet. Zuletzt: {1}", "Edited {0} times. Last modification: {1}"), 41 | MSG_CREATE_COMMENT ("Neuen Kommentar erstellen", "Create new comment"), 42 | MSG_LOGIN_TO_COMMENT ("Sie müssen angemeldet sein, um einen Kommentar zu verfassen!", "You must be logged in to post a comment!"), 43 | 44 | MSG_FIELD_AUTHOR ("Ihr Name", "Your name"), 45 | DESC_FIELD_AUTHOR ("Geben Sie Ihren Namen an. Ohne den Namen kann der Kommentar nicht gespeichert werden", 46 | "Provide your name here. The comment cannot be saved without a name"), 47 | MSG_FIELD_TITLE ("Titel", "Title"), 48 | DESC_FIELD_TITLE ("Geben Sie den Titel des Kommentars an. Dieser kann auch leer bleiben", 49 | "Provide the title/subject of your comment. The title is optional and you're not required to insert any text here"), 50 | MSG_FIELD_TEXT ("Ihr Kommentar", "Your comment"), 51 | DESC_FIELD_TEXT ("Geben Sie Ihren Kommentar in diesem Feld an. Es können mehrere Zeilen verwendet werden, HTML Code wird jedoch nicht interpretiert", 52 | "Provide your comment here. It can have multiple lines but HTML code is not interpreted at all!"), 53 | 54 | MSG_COMMENT_SAVE_SUCCESS ("Ihr Kommentar wurde erfolgreich gespeichert!", "Your comment was successfully saved!"), 55 | MSG_COMMENT_SAVE_FAILURE ("Ihr Kommentar konnte nicht gespeichert werden!", "Your comment could not be saved!"), 56 | MSG_ERR_COMMENT_NO_TEXT ("Der Text darf nicht leer sein. Geben Sie einen Text an!", 57 | "The comment text may not be empty. Provide a comment text!"), 58 | MSG_ERR_COMMENT_NO_AUTHOR ("Ihr Name darf nicht leer sein. Geben Sie Ihre Namen an!", "Your name may not be empty. Provide your name!"), 59 | 60 | MSG_COMMENT_DELETE_SUCCESS ("Der Kommentar wurde erfolgreich gelöscht!", "The comment was successfully deleted!"), 61 | MSG_COMMENT_DELETE_FAILURE ("Der Kommentar konnte nicht gelöscht werden!", "The comment could not be deleted!"); 62 | 63 | private final IMultilingualText m_aTP; 64 | 65 | private ECommentText (@Nonnull final String sDE, @Nonnull final String sEN) 66 | { 67 | m_aTP = TextHelper.create_DE_EN (sDE, sEN); 68 | } 69 | 70 | @Nullable 71 | public String getDisplayText (@Nonnull final Locale aContentLocale) 72 | { 73 | return DefaultTextResolver.getTextStatic (this, m_aTP, aContentLocale); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/crm/CRMGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.crm; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import com.helger.commons.ValueEnforcer; 22 | import com.helger.commons.annotation.Nonempty; 23 | import com.helger.commons.state.EChange; 24 | import com.helger.commons.string.ToStringGenerator; 25 | import com.helger.commons.type.ObjectType; 26 | import com.helger.photon.security.object.StubObject; 27 | import com.helger.tenancy.AbstractBusinessObject; 28 | 29 | public class CRMGroup extends AbstractBusinessObject implements ICRMGroup 30 | { 31 | public static final ObjectType OT_CRM_GROUP = new ObjectType ("crm-group"); 32 | 33 | private String m_sDisplayName; 34 | private String m_sSenderEmailAddress; 35 | 36 | public CRMGroup (@Nonnull @Nonempty final String sDisplayName, @Nonnull @Nonempty final String sSenderEmailAddress) 37 | { 38 | this (StubObject.createForCurrentUser (), sDisplayName, sSenderEmailAddress); 39 | } 40 | 41 | CRMGroup (@Nonnull @Nonempty final StubObject aStubObject, 42 | @Nonnull @Nonempty final String sDisplayName, 43 | @Nonnull @Nonempty final String sSenderEmailAddress) 44 | { 45 | super (aStubObject); 46 | setDisplayName (sDisplayName); 47 | setSenderEmailAddress (sSenderEmailAddress); 48 | } 49 | 50 | @Nonnull 51 | public ObjectType getObjectType () 52 | { 53 | return OT_CRM_GROUP; 54 | } 55 | 56 | @Nonnull 57 | @Nonempty 58 | public String getDisplayName () 59 | { 60 | return m_sDisplayName; 61 | } 62 | 63 | @Nonnull 64 | public EChange setDisplayName (@Nonnull @Nonempty final String sDisplayName) 65 | { 66 | ValueEnforcer.notEmpty (sDisplayName, "DisplayName"); 67 | if (sDisplayName.equals (m_sDisplayName)) 68 | return EChange.UNCHANGED; 69 | m_sDisplayName = sDisplayName; 70 | return EChange.CHANGED; 71 | } 72 | 73 | @Nonnull 74 | @Nonempty 75 | public String getSenderEmailAddress () 76 | { 77 | return m_sSenderEmailAddress; 78 | } 79 | 80 | @Nonnull 81 | public EChange setSenderEmailAddress (@Nonnull @Nonempty final String sSenderEmailAddress) 82 | { 83 | ValueEnforcer.notEmpty (sSenderEmailAddress, "SenderEmailAddress"); 84 | if (sSenderEmailAddress.equals (m_sSenderEmailAddress)) 85 | return EChange.UNCHANGED; 86 | m_sSenderEmailAddress = sSenderEmailAddress; 87 | return EChange.CHANGED; 88 | } 89 | 90 | @Override 91 | public String toString () 92 | { 93 | return ToStringGenerator.getDerived (super.toString ()) 94 | .append ("DisplayName", m_sDisplayName) 95 | .append ("SenderEmailAddress", m_sSenderEmailAddress) 96 | .getToString (); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/crm/CRMGroupManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.crm; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | import javax.annotation.concurrent.ThreadSafe; 22 | 23 | import com.helger.commons.annotation.Nonempty; 24 | import com.helger.commons.state.EChange; 25 | import com.helger.dao.DAOException; 26 | import com.helger.photon.audit.AuditHelper; 27 | import com.helger.photon.io.dao.AbstractPhotonMapBasedWALDAO; 28 | import com.helger.photon.security.object.BusinessObjectHelper; 29 | 30 | /** 31 | * Manager for {@link CRMGroup} instances. 32 | * 33 | * @author Philip Helger 34 | * @see com.helger.peppol.app.mgr.PPMetaManager 35 | */ 36 | @ThreadSafe 37 | public final class CRMGroupManager extends AbstractPhotonMapBasedWALDAO 38 | { 39 | public CRMGroupManager (@Nonnull @Nonempty final String sFilename) throws DAOException 40 | { 41 | super (CRMGroup.class, sFilename); 42 | } 43 | 44 | @Nonnull 45 | public ICRMGroup createCRMGroup (@Nonnull @Nonempty final String sDisplayName, @Nonnull @Nonempty final String sSenderEmailAddress) 46 | { 47 | final CRMGroup aCRMGroup = new CRMGroup (sDisplayName, sSenderEmailAddress); 48 | 49 | m_aRWLock.writeLocked ( () -> { 50 | internalCreateItem (aCRMGroup); 51 | }); 52 | AuditHelper.onAuditCreateSuccess (CRMGroup.OT_CRM_GROUP, aCRMGroup.getID (), sDisplayName, sSenderEmailAddress); 53 | return aCRMGroup; 54 | } 55 | 56 | @Nonnull 57 | public EChange updateCRMGroup (@Nullable final String sCRMGroupID, 58 | @Nonnull @Nonempty final String sDisplayName, 59 | @Nonnull @Nonempty final String sSenderEmailAddress) 60 | { 61 | final CRMGroup aCRMGroup = getOfID (sCRMGroupID); 62 | if (aCRMGroup == null) 63 | { 64 | AuditHelper.onAuditModifyFailure (CRMGroup.OT_CRM_GROUP, sCRMGroupID, "no-such-id"); 65 | return EChange.UNCHANGED; 66 | } 67 | 68 | m_aRWLock.writeLock ().lock (); 69 | try 70 | { 71 | EChange eChange = EChange.UNCHANGED; 72 | // ID cannot be changed! 73 | eChange = eChange.or (aCRMGroup.setDisplayName (sDisplayName)); 74 | eChange = eChange.or (aCRMGroup.setSenderEmailAddress (sSenderEmailAddress)); 75 | if (eChange.isUnchanged ()) 76 | return EChange.UNCHANGED; 77 | 78 | BusinessObjectHelper.setLastModificationNow (aCRMGroup); 79 | internalUpdateItem (aCRMGroup); 80 | } 81 | finally 82 | { 83 | m_aRWLock.writeLock ().unlock (); 84 | } 85 | AuditHelper.onAuditModifySuccess (CRMGroup.OT_CRM_GROUP, "all", sCRMGroupID, sDisplayName, sSenderEmailAddress); 86 | return EChange.CHANGED; 87 | } 88 | 89 | @Nullable 90 | public ICRMGroup getCRMGroupOfID (@Nullable final String sID) 91 | { 92 | return getOfID (sID); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/crm/CRMGroupMicroTypeConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.crm; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | import com.helger.photon.security.object.AbstractBusinessObjectMicroTypeConverter; 23 | import com.helger.xml.microdom.IMicroElement; 24 | import com.helger.xml.microdom.MicroElement; 25 | 26 | public class CRMGroupMicroTypeConverter extends AbstractBusinessObjectMicroTypeConverter 27 | { 28 | private static final String ATTR_DISPLAY_NAME = "displayname"; 29 | private static final String ATTR_SENDER_EMAIL_ADDRESS = "senderemailaddress"; 30 | 31 | @Nullable 32 | public IMicroElement convertToMicroElement (@Nonnull final CRMGroup aValue, 33 | @Nullable final String sNamespaceURI, 34 | @Nonnull final String sTagName) 35 | { 36 | final MicroElement aElement = new MicroElement (sNamespaceURI, sTagName); 37 | setObjectFields (aValue, aElement); 38 | aElement.setAttribute (ATTR_DISPLAY_NAME, aValue.getDisplayName ()); 39 | aElement.setAttribute (ATTR_SENDER_EMAIL_ADDRESS, aValue.getSenderEmailAddress ()); 40 | return aElement; 41 | } 42 | 43 | @Nullable 44 | public CRMGroup convertToNative (@Nonnull final IMicroElement aElement) 45 | { 46 | final String sDisplayName = aElement.getAttributeValue (ATTR_DISPLAY_NAME); 47 | final String sSenderEmailAddress = aElement.getAttributeValue (ATTR_SENDER_EMAIL_ADDRESS); 48 | return new CRMGroup (getStubObject (aElement), sDisplayName, sSenderEmailAddress); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/crm/CRMSubscriberMicroTypeConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.crm; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | import com.helger.commons.collection.CollectionHelper; 23 | import com.helger.commons.collection.impl.CommonsHashSet; 24 | import com.helger.commons.collection.impl.ICommonsSet; 25 | import com.helger.commons.id.IHasID; 26 | import com.helger.commons.string.StringHelper; 27 | import com.helger.masterdata.person.ESalutation; 28 | import com.helger.peppol.app.mgr.PPMetaManager; 29 | import com.helger.photon.security.object.AbstractBusinessObjectMicroTypeConverter; 30 | import com.helger.xml.microdom.IMicroElement; 31 | import com.helger.xml.microdom.MicroElement; 32 | 33 | public class CRMSubscriberMicroTypeConverter extends AbstractBusinessObjectMicroTypeConverter 34 | { 35 | private static final String ATTR_SALUTATION = "salutation"; 36 | private static final String ATTR_NAME = "name"; 37 | private static final String ATTR_EMAIL_ADDRESS = "emailaddress"; 38 | private static final String ELEMENT_ASSIGNED_GROUP = "assignedgroup"; 39 | 40 | @Nullable 41 | public IMicroElement convertToMicroElement (@Nonnull final CRMSubscriber aValue, 42 | @Nullable final String sNamespaceURI, 43 | @Nonnull final String sTagName) 44 | { 45 | final MicroElement aElement = new MicroElement (sNamespaceURI, sTagName); 46 | setObjectFields (aValue, aElement); 47 | aElement.setAttribute (ATTR_SALUTATION, aValue.getSalutationID ()); 48 | aElement.setAttribute (ATTR_NAME, aValue.getName ()); 49 | aElement.setAttribute (ATTR_EMAIL_ADDRESS, aValue.getEmailAddress ()); 50 | for (final ICRMGroup aGroup : CollectionHelper.getSorted (aValue.getAllAssignedGroups (), IHasID.getComparatorID ())) 51 | aElement.appendElement (sNamespaceURI, ELEMENT_ASSIGNED_GROUP).setAttribute (ATTR_ID, aGroup.getID ()); 52 | return aElement; 53 | } 54 | 55 | @Nullable 56 | public CRMSubscriber convertToNative (@Nonnull final IMicroElement aElement) 57 | { 58 | final CRMGroupManager aCRMGroupMgr = PPMetaManager.getCRMGroupMgr (); 59 | 60 | final String sSalutationID = aElement.getAttributeValue (ATTR_SALUTATION); 61 | final ESalutation eSalutation = ESalutation.getFromIDOrNull (sSalutationID); 62 | if (eSalutation == null && StringHelper.hasText (sSalutationID)) 63 | throw new IllegalStateException ("Failed to resolve salutation ID '" + sSalutationID + "'"); 64 | 65 | final String sName = aElement.getAttributeValue (ATTR_NAME); 66 | final String sEmailAddress = aElement.getAttributeValue (ATTR_EMAIL_ADDRESS); 67 | 68 | final ICommonsSet aGroups = new CommonsHashSet <> (); 69 | for (final IMicroElement eGroup : aElement.getAllChildElements (ELEMENT_ASSIGNED_GROUP)) 70 | { 71 | final String sCRMGroupID = eGroup.getAttributeValue (ATTR_ID); 72 | final ICRMGroup aCRMGroup = aCRMGroupMgr.getCRMGroupOfID (sCRMGroupID); 73 | if (aCRMGroup == null) 74 | throw new IllegalStateException ("Failed to resolve CRM group with ID '" + sCRMGroupID + "'"); 75 | aGroups.add (aCRMGroup); 76 | } 77 | 78 | return new CRMSubscriber (getStubObject (aElement), eSalutation, sName, sEmailAddress, aGroups); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/crm/ICRMGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.crm; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import com.helger.commons.annotation.Nonempty; 22 | import com.helger.commons.name.IHasDisplayName; 23 | import com.helger.tenancy.IBusinessObject; 24 | 25 | /** 26 | * The read-only interface for a single CRM group. 27 | * 28 | * @author Philip Helger 29 | */ 30 | public interface ICRMGroup extends IBusinessObject, IHasDisplayName 31 | { 32 | /** 33 | * @return The default sender email address for this group. 34 | */ 35 | @Nonnull 36 | @Nonempty 37 | String getSenderEmailAddress (); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/crm/ICRMSubscriber.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.crm; 18 | 19 | import java.util.Locale; 20 | 21 | import javax.annotation.Nonnegative; 22 | import javax.annotation.Nonnull; 23 | import javax.annotation.Nullable; 24 | 25 | import com.helger.commons.annotation.Nonempty; 26 | import com.helger.commons.annotation.ReturnsMutableCopy; 27 | import com.helger.commons.collection.impl.ICommonsSet; 28 | import com.helger.commons.text.display.IHasDisplayText; 29 | import com.helger.masterdata.person.ESalutation; 30 | import com.helger.tenancy.IBusinessObject; 31 | 32 | /** 33 | * The read-only interface for a single CRM subscriber, that is subscribed to 34 | * multiple CRM groups. 35 | * 36 | * @author Philip Helger 37 | */ 38 | public interface ICRMSubscriber extends IBusinessObject, IHasDisplayText 39 | { 40 | /** 41 | * Create a unified, all lowercase email address for easy comparison 42 | * 43 | * @param sEmailAddress 44 | * Source email address. May not be null. 45 | * @return Unified email address. 46 | */ 47 | @Nonnull 48 | static String getUnifiedEmailAddress (@Nonnull final String sEmailAddress) 49 | { 50 | return sEmailAddress.trim ().toLowerCase (Locale.US); 51 | } 52 | 53 | @Nullable 54 | ESalutation getSalutation (); 55 | 56 | @Nullable 57 | String getSalutationID (); 58 | 59 | @Nullable 60 | String getSalutationDisplayName (@Nonnull Locale aContentLocale); 61 | 62 | @Nonnull 63 | @Nonempty 64 | String getName (); 65 | 66 | @Nonnull 67 | @Nonempty 68 | String getEmailAddress (); 69 | 70 | @Nonnull 71 | @ReturnsMutableCopy 72 | ICommonsSet getAllAssignedGroups (); 73 | 74 | @Nonnegative 75 | int getAssignedGroupCount (); 76 | 77 | boolean isAssignedToGroup (@Nullable ICRMGroup aCRMGroup); 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/pub/CMenuPublic.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.pub; 18 | 19 | import javax.annotation.concurrent.Immutable; 20 | 21 | /** 22 | * Menu items for the public application 23 | * 24 | * @author Philip Helger 25 | */ 26 | @Immutable 27 | public final class CMenuPublic 28 | { 29 | public static final String MENU_INDEX = "index"; 30 | public static final String MENU_DOCS = "docs"; 31 | public static final String MENU_DOCS_SETUP_AP_PH = "docs-setup-ap"; 32 | public static final String MENU_DOCS_SETUP_SMP_CIPA = "docs-setup-smp"; 33 | public static final String MENU_DOCS_SETUP_SMP_PHOSS = "docs-setup-smp-ph"; 34 | public static final String MENU_DOCS_SMP_SML_INTERPLAY = "docs-smp-sml-interplay"; 35 | public static final String MENU_DOCS_SML_SUPPORT = "docs-sml-support"; 36 | public static final String MENU_DOCS_DOC_EXCHANGE = "docs-doc-exchange"; 37 | public static final String MENU_DOCS_PEPPOL_PKI = "docs-peppol-pki"; 38 | public static final String MENU_DOCS_PEPPOL_CERT_UPDATE = "docs-peppol-cert-update"; 39 | public static final String MENU_DOCS_PEPPOL_MLR = "docs-peppol-mlr"; 40 | public static final String MENU_DOCS_PEPPOL_DICT = "docs-peppol-dict"; 41 | public static final String MENU_DOCS_PEPPOL_FIREWALL = "docs-peppol-firewall"; 42 | public static final String MENU_DOCS_SOFTWARE_VENDORS = "docs-software-vendors"; 43 | public static final String MENU_NEWS = "news"; 44 | public static final String MENU_TOOLS = "tools"; 45 | public static final String MENU_TOOLS_SMP_SML = "tools-smp-sml"; 46 | public static final String MENU_TOOLS_TEST_ENDPOINTS = "tools-test-endpoints"; 47 | public static final String MENU_TOOLS_REST_API = "tools-rest-api"; 48 | public static final String MENU_VALIDATION = "validation"; 49 | public static final String MENU_VALIDATION_UPLOAD = "validation-upload"; 50 | public static final String MENU_VALIDATION_DVS = "validation-ws2"; 51 | public static final String MENU_EN16931 = "en16931"; 52 | public static final String MENU_COUNTRIES = "countries"; 53 | public static final String MENU_COUNTRY_DE = "country-de"; 54 | public static final String MENU_GITHUB_PEPPOL = "github-peppol"; 55 | public static final String MENU_LOGIN = "login"; 56 | public static final String MENU_SIGN_UP = "signup"; 57 | public static final String MENU_CHANGE_PASSWORD = "changepassword"; 58 | public static final String MENU_NEWSLETTER_SUBSCRIBE = "newsletter-subscribe"; 59 | public static final String MENU_CONTACT = "contact"; 60 | public static final String MENU_PEPPOL_SERVICE_DESK = "peppol-service-desk"; 61 | public static final String MENU_THE_INVOICING_HUB = "theinvoicinghub"; 62 | 63 | // footer 64 | public static final String MENU_NEWSLETTER_UNSUBSCRIBE = "newsletter-unsubscribe"; 65 | 66 | // flags 67 | public static final String FLAG_FOOTER_COL1 = "footercol1"; 68 | public static final String FLAG_FOOTER_COL2 = "footercol2"; 69 | public static final String FLAG_FOOTER_COL3 = "footercol3"; 70 | 71 | private CMenuPublic () 72 | {} 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/pub/PagePublicLogin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.pub; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | import com.helger.commons.annotation.Nonempty; 23 | import com.helger.html.hc.impl.HCNodeList; 24 | import com.helger.peppol.sharedui.page.AbstractAppWebPage; 25 | import com.helger.peppol.ui.AppCommonUI; 26 | import com.helger.photon.uicore.page.WebPageExecutionContext; 27 | 28 | public final class PagePublicLogin extends AbstractAppWebPage 29 | { 30 | public PagePublicLogin (@Nonnull @Nonempty final String sID) 31 | { 32 | super (sID, "Login"); 33 | } 34 | 35 | @Override 36 | @Nullable 37 | public String getHeaderText (@Nonnull final WebPageExecutionContext aWPEC) 38 | { 39 | return super.getHeaderText (aWPEC); 40 | } 41 | 42 | @Override 43 | protected void fillContent (final WebPageExecutionContext aWPEC) 44 | { 45 | final HCNodeList aNodeList = aWPEC.getNodeList (); 46 | 47 | aNodeList.addChild (AppCommonUI.createViewLoginForm (aWPEC, null, true)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/pub/PagePublicNewsletterUnsubscribe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.pub; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import com.helger.commons.annotation.Nonempty; 22 | import com.helger.commons.email.EmailAddressHelper; 23 | import com.helger.commons.string.StringHelper; 24 | import com.helger.html.hc.html.forms.HCEdit; 25 | import com.helger.html.hc.impl.HCNodeList; 26 | import com.helger.peppol.app.mgr.PPMetaManager; 27 | import com.helger.peppol.crm.CRMSubscriberManager; 28 | import com.helger.peppol.crm.ICRMSubscriber; 29 | import com.helger.peppol.sharedui.page.AbstractAppWebPage; 30 | import com.helger.photon.bootstrap4.buttongroup.BootstrapButtonToolbar; 31 | import com.helger.photon.bootstrap4.form.BootstrapForm; 32 | import com.helger.photon.bootstrap4.form.BootstrapFormGroup; 33 | import com.helger.photon.core.form.FormErrorList; 34 | import com.helger.photon.core.form.RequestField; 35 | import com.helger.photon.uicore.css.CPageParam; 36 | import com.helger.photon.uicore.icon.EDefaultIcon; 37 | import com.helger.photon.uicore.page.WebPageExecutionContext; 38 | 39 | public final class PagePublicNewsletterUnsubscribe extends AbstractAppWebPage 40 | { 41 | private static final String FIELD_EMAIL_ADDRESS = "emailaddress"; 42 | 43 | public PagePublicNewsletterUnsubscribe (@Nonnull @Nonempty final String sID) 44 | { 45 | super (sID, "Unsubscribe from newsletter"); 46 | } 47 | 48 | @Override 49 | protected void fillContent (final WebPageExecutionContext aWPEC) 50 | { 51 | final HCNodeList aNodeList = aWPEC.getNodeList (); 52 | final CRMSubscriberManager aCRMSubscriberMgr = PPMetaManager.getCRMSubscriberMgr (); 53 | final FormErrorList aFormErrors = new FormErrorList (); 54 | 55 | if (aWPEC.hasAction (CPageParam.ACTION_SAVE)) 56 | { 57 | final String sEmailAddress = aWPEC.params ().getAsString (FIELD_EMAIL_ADDRESS); 58 | ICRMSubscriber aCRMSubscriber = null; 59 | 60 | if (StringHelper.hasNoText (sEmailAddress)) 61 | aFormErrors.addFieldError (FIELD_EMAIL_ADDRESS, "You must provide your email address!"); 62 | else 63 | if (!EmailAddressHelper.isValid (sEmailAddress)) 64 | aFormErrors.addFieldError (FIELD_EMAIL_ADDRESS, "The provided email address is invalid!"); 65 | else 66 | { 67 | aCRMSubscriber = aCRMSubscriberMgr.getCRMSubscriberOfEmailAddress (sEmailAddress); 68 | if (aCRMSubscriber == null) 69 | aFormErrors.addFieldError (FIELD_EMAIL_ADDRESS, "The provided email address is not registered to any mailing list!"); 70 | } 71 | 72 | if (aFormErrors.isEmpty ()) 73 | { 74 | // Update an existing one 75 | aCRMSubscriberMgr.updateCRMSubscriberGroupAssignments (aCRMSubscriber.getID (), null); 76 | aNodeList.addChild (success ("Successfully unsubscribed '" + sEmailAddress + "' from all mailing lists")); 77 | } 78 | else 79 | { 80 | aNodeList.addChild (getUIHandler ().createIncorrectInputBox (aWPEC)); 81 | } 82 | } 83 | 84 | final BootstrapForm aForm = getUIHandler ().createFormSelf (aWPEC); 85 | aForm.setLeft (3); 86 | aForm.addFormGroup (new BootstrapFormGroup ().setLabelMandatory ("Your email address") 87 | .setCtrl (new HCEdit (new RequestField (FIELD_EMAIL_ADDRESS))) 88 | .setErrorList (aFormErrors.getListOfField (FIELD_EMAIL_ADDRESS))); 89 | 90 | // Toolbar 91 | final BootstrapButtonToolbar aToolbar = aForm.addAndReturnChild (new BootstrapButtonToolbar (aWPEC)); 92 | aToolbar.addHiddenField (CPageParam.PARAM_ACTION, CPageParam.ACTION_SAVE); 93 | aToolbar.addSubmitButton ("Unsubscribe", EDefaultIcon.YES); 94 | 95 | aNodeList.addChild (aForm); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/pub/PagePublicToolsDocumentValidation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.pub; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import com.helger.commons.annotation.Nonempty; 22 | import com.helger.html.hc.html.textlevel.HCA; 23 | import com.helger.html.hc.impl.HCNodeList; 24 | import com.helger.peppol.sharedui.page.AbstractAppWebPage; 25 | import com.helger.photon.uicore.page.WebPageExecutionContext; 26 | 27 | public class PagePublicToolsDocumentValidation extends AbstractAppWebPage 28 | { 29 | public PagePublicToolsDocumentValidation (@Nonnull @Nonempty final String sID) 30 | { 31 | super (sID, "Document Validation (Upload)"); 32 | } 33 | 34 | @Override 35 | protected void fillContent (@Nonnull final WebPageExecutionContext aWPEC) 36 | { 37 | final HCNodeList aNodeList = aWPEC.getNodeList (); 38 | 39 | aNodeList.addChild (warn (div ("This page was moved.")).addChild (div ("The new home of the validation per upload is at my friends of ecosio: ").addChild (HCA.createLinkedWebsite ("https://ecosio.com/en/peppol-and-xml-document-validator/"))) 40 | .addChild (div ("They are using my validation engine and helping me to save some server resources :)")) 41 | .addChild (div (strong ("Note: ")).addChild ("the validation web service is currently not affected by this change and new validation rules will be added as usual."))); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/rest/APIGetAllVESIDs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.rest; 18 | 19 | import java.nio.charset.StandardCharsets; 20 | import java.util.Map; 21 | 22 | import javax.annotation.Nonnull; 23 | 24 | import com.helger.commons.CGlobal; 25 | import com.helger.commons.annotation.Nonempty; 26 | import com.helger.commons.mime.CMimeType; 27 | import com.helger.json.IJsonArray; 28 | import com.helger.json.serialize.JsonWriter; 29 | import com.helger.json.serialize.JsonWriterSettings; 30 | import com.helger.peppol.sharedui.validate.VESRegistry; 31 | import com.helger.photon.api.IAPIDescriptor; 32 | import com.helger.servlet.response.UnifiedResponse; 33 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 34 | 35 | public final class APIGetAllVESIDs extends AbstractPPAPIExecutor 36 | { 37 | @Override 38 | protected void rateLimitedInvokeAPI (@Nonnull final IAPIDescriptor aAPIDescriptor, 39 | @Nonnull @Nonempty final String sPath, 40 | @Nonnull final Map aPathVariables, 41 | @Nonnull final IRequestWebScopeWithoutResponse aRequestScope, 42 | @Nonnull final UnifiedResponse aUnifiedResponse) throws Exception 43 | { 44 | final IJsonArray aJson = VESRegistry.getAllAsJson (); 45 | 46 | final String sRet = new JsonWriter (JsonWriterSettings.DEFAULT_SETTINGS_FORMATTED).writeAsString (aJson); 47 | aUnifiedResponse.setContentAndCharset (sRet, StandardCharsets.UTF_8) 48 | .setMimeType (CMimeType.APPLICATION_JSON) 49 | .enableCaching (1 * CGlobal.SECONDS_PER_HOUR); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/rest/AbstractJsonBasedAPIExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.rest; 18 | 19 | import java.util.Locale; 20 | 21 | import javax.annotation.Nonnull; 22 | import javax.annotation.Nullable; 23 | 24 | import com.helger.commons.error.IError; 25 | import com.helger.commons.error.level.EErrorLevel; 26 | import com.helger.commons.error.level.IErrorLevel; 27 | import com.helger.commons.lang.StackTraceHelper; 28 | import com.helger.commons.state.ETriState; 29 | import com.helger.json.IJsonObject; 30 | import com.helger.json.JsonObject; 31 | 32 | public abstract class AbstractJsonBasedAPIExecutor extends AbstractPPAPIExecutor 33 | { 34 | @Nonnull 35 | protected static String getErrorLevel (@Nonnull final IErrorLevel aErrorLevel) 36 | { 37 | if (aErrorLevel.isGE (EErrorLevel.ERROR)) 38 | return "ERROR"; 39 | if (aErrorLevel.isGE (EErrorLevel.WARN)) 40 | return "WARN"; 41 | return "SUCCESS"; 42 | } 43 | 44 | @Nonnull 45 | protected static String getTriState (@Nonnull final ETriState eTriState) 46 | { 47 | if (eTriState.isTrue ()) 48 | return "TRUE"; 49 | if (eTriState.isFalse ()) 50 | return "FALSE"; 51 | return "UNDEFINED"; 52 | } 53 | 54 | @Nullable 55 | protected static IJsonObject getStackTrace (@Nullable final Throwable t) 56 | { 57 | if (t == null) 58 | return null; 59 | return new JsonObject ().add ("class", t.getClass ().getName ()) 60 | .addIfNotNull ("message", t.getMessage ()) 61 | .add ("stackTrace", StackTraceHelper.getStackAsString (t)); 62 | } 63 | 64 | @Nonnull 65 | protected static IJsonObject createItem (@Nonnull final IErrorLevel aErrorLevel, 66 | @Nullable final String sErrorID, 67 | @Nullable final String sErrorFieldName, 68 | @Nullable final String sErrorLocation, 69 | @Nonnull final String sErrorText, 70 | @Nullable final Throwable t) 71 | { 72 | return new JsonObject ().add ("errorLevel", getErrorLevel (aErrorLevel)) 73 | .addIfNotNull ("errorID", sErrorID) 74 | .addIfNotNull ("errorFieldName", sErrorFieldName) 75 | .addIfNotNull ("errorLocation", sErrorLocation) 76 | .add ("errorText", sErrorText) 77 | .addIfNotNull ("exception", getStackTrace (t)); 78 | } 79 | 80 | @Nonnull 81 | protected static IJsonObject createItem (@Nonnull final IError aError, @Nonnull final Locale aDisplayLocale) 82 | { 83 | return createItem (aError.getErrorLevel (), 84 | aError.getErrorID (), 85 | aError.getErrorFieldName (), 86 | aError.hasErrorLocation () ? aError.getErrorLocation ().getAsString () : null, 87 | aError.getErrorText (aDisplayLocale), 88 | aError.getLinkedException ()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/rest/AbstractPPAPIExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.rest; 18 | 19 | import com.helger.peppol.sharedui.api.AbstractRateLimitingAPIExecutor; 20 | 21 | public abstract class AbstractPPAPIExecutor extends AbstractRateLimitingAPIExecutor 22 | { 23 | public static final String DEFAULT_USER_AGENT = "Peppol-Practical/1.0"; 24 | 25 | protected AbstractPPAPIExecutor () 26 | { 27 | super (DEFAULT_USER_AGENT); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/secure/CMenuSecure.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.secure; 18 | 19 | import javax.annotation.concurrent.Immutable; 20 | 21 | /** 22 | * Menu items for the secure application 23 | * 24 | * @author Philip Helger 25 | */ 26 | @Immutable 27 | public final class CMenuSecure 28 | { 29 | // Menu item IDs 30 | public static final String MENU_CRM = "crm"; 31 | public static final String MENU_CRM_GROUPS = "crm-groups"; 32 | public static final String MENU_CRM_SUBSCRIBERS = "crm-subscribers"; 33 | 34 | public static final String MENU_PEPPOL = "peppol"; 35 | public static final String MENU_PEPPOL_SEND_AS4 = "peppol-send-as4"; 36 | 37 | public static final String MENU_COMMENTS = "comments"; 38 | public static final String MENU_SCH_TOOLS = "schematron-tools"; 39 | 40 | public static final String MENU_ADMIN = "admin"; 41 | public static final String MENU_ADMIN_CHANGE_PASSWORD = "admin_change_password"; 42 | public static final String MENU_ADMIN_ADDONS = "admin-addons"; 43 | public static final String MENU_SML_CONFIGURATION = "sml_configuration"; 44 | 45 | private CMenuSecure () 46 | {} 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/secure/MenuSecure.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.secure; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.concurrent.Immutable; 21 | 22 | import com.helger.peppol.app.CPPApp; 23 | import com.helger.peppol.sharedui.page.secure.PageSecurePeppolSendAS4; 24 | import com.helger.peppol.sharedui.page.secure.PageSecureSMLConfiguration; 25 | import com.helger.photon.bootstrap4.pages.BootstrapPagesMenuConfigurator; 26 | import com.helger.photon.bootstrap4.pages.security.BasePageSecurityChangePassword; 27 | import com.helger.photon.core.menu.IMenuItemPage; 28 | import com.helger.photon.core.menu.IMenuTree; 29 | import com.helger.photon.core.menu.filter.MenuObjectFilterUserAssignedToUserGroup; 30 | import com.helger.photon.core.menu.filter.MenuObjectFilterUserHasRole; 31 | import com.helger.photon.uicore.page.system.BasePageShowChildren; 32 | 33 | @Immutable 34 | public final class MenuSecure 35 | { 36 | private MenuSecure () 37 | {} 38 | 39 | public static void init (@Nonnull final IMenuTree aMenuTree) 40 | { 41 | // We need this additional indirection layer, as the pages are initialized 42 | // statically! 43 | final MenuObjectFilterUserAssignedToUserGroup aFilterAdministrators = new MenuObjectFilterUserAssignedToUserGroup (CPPApp.USERGROUP_ADMINISTRATORS_ID); 44 | final MenuObjectFilterUserHasRole aFilterPeppolSenders = new MenuObjectFilterUserHasRole (CPPApp.ROLE_PEPPOL_SENDERS_ID); 45 | 46 | // CRM 47 | { 48 | final IMenuItemPage aCRM = aMenuTree.createRootItem (new BasePageShowChildren <> (CMenuSecure.MENU_CRM, 49 | "CRM", 50 | aMenuTree)) 51 | .setDisplayFilter (aFilterAdministrators); 52 | aMenuTree.createItem (aCRM, new PageSecureCRMGroup (CMenuSecure.MENU_CRM_GROUPS)) 53 | .setDisplayFilter (aFilterAdministrators); 54 | aMenuTree.createItem (aCRM, new PageSecureCRMSubscriber (CMenuSecure.MENU_CRM_SUBSCRIBERS)) 55 | .setDisplayFilter (aFilterAdministrators); 56 | } 57 | 58 | // Peppol 59 | { 60 | final IMenuItemPage aPeppol = aMenuTree.createRootItem (new BasePageShowChildren <> (CMenuSecure.MENU_PEPPOL, 61 | "Peppol", 62 | aMenuTree)); 63 | aMenuTree.createItem (aPeppol, new PageSecurePeppolSendAS4 (CMenuSecure.MENU_PEPPOL_SEND_AS4)) 64 | .setDisplayFilter (aFilterPeppolSenders); 65 | } 66 | 67 | // Comments 68 | { 69 | aMenuTree.createRootItem (new PageSecureCommentAdmin (CMenuSecure.MENU_COMMENTS)) 70 | .setDisplayFilter (aFilterAdministrators); 71 | } 72 | 73 | // Schematron tools 74 | { 75 | aMenuTree.createRootItem (new PageSecureSchematronTools (CMenuSecure.MENU_SCH_TOOLS)) 76 | .setDisplayFilter (aFilterAdministrators); 77 | } 78 | 79 | // Administrator 80 | { 81 | final IMenuItemPage aAdmin = aMenuTree.createRootItem (new BasePageShowChildren <> (CMenuSecure.MENU_ADMIN, 82 | "Administration", 83 | aMenuTree)); 84 | // Must be accessible for all Config users 85 | aMenuTree.createItem (aAdmin, new BasePageSecurityChangePassword <> (CMenuSecure.MENU_ADMIN_CHANGE_PASSWORD)); 86 | 87 | // Admins only 88 | aMenuTree.createItem (aAdmin, new PageSecureAdminAddons (CMenuSecure.MENU_ADMIN_ADDONS)) 89 | .setDisplayFilter (aFilterAdministrators); 90 | aMenuTree.createItem (aAdmin, new PageSecureSMLConfiguration (CMenuSecure.MENU_SML_CONFIGURATION)) 91 | .setDisplayFilter (aFilterAdministrators); 92 | BootstrapPagesMenuConfigurator.addAllItems (aMenuTree, aAdmin, aFilterAdministrators, CPPApp.DEFAULT_LOCALE); 93 | } 94 | 95 | // Default menu item 96 | aMenuTree.setDefaultMenuItemID (CMenuSecure.MENU_COMMENTS); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/secure/PageSecureAdminAddons.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.secure; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import com.helger.commons.annotation.Nonempty; 26 | import com.helger.commons.mutable.MutableInt; 27 | import com.helger.html.hc.IHCNode; 28 | import com.helger.html.hc.impl.HCNodeList; 29 | import com.helger.photon.audit.AuditHelper; 30 | import com.helger.photon.bootstrap4.button.BootstrapButton; 31 | import com.helger.photon.bootstrap4.pages.AbstractBootstrapWebPage; 32 | import com.helger.photon.core.appid.CApplicationID; 33 | import com.helger.photon.core.appid.PhotonGlobalState; 34 | import com.helger.photon.core.menu.IMenuItemPage; 35 | import com.helger.photon.core.menu.IMenuTree; 36 | import com.helger.photon.uicore.css.CPageParam; 37 | import com.helger.photon.uicore.page.WebPageExecutionContext; 38 | import com.helger.photon.uicore.page.external.IWebPageResourceContent; 39 | 40 | public final class PageSecureAdminAddons extends AbstractBootstrapWebPage 41 | { 42 | private static final Logger LOGGER = LoggerFactory.getLogger (PageSecureAdminAddons.class); 43 | 44 | private static final String ACTION_EXPIRE_PAGE_CACHE = "expirePageCache"; 45 | 46 | public PageSecureAdminAddons (@Nonnull @Nonempty final String sID) 47 | { 48 | super (sID, "Additional administration"); 49 | } 50 | 51 | @Nullable 52 | private IHCNode _handleAction (@Nullable final String sAction) 53 | { 54 | if (ACTION_EXPIRE_PAGE_CACHE.equals (sAction)) 55 | { 56 | final IMenuTree aPublicMenuTree = PhotonGlobalState.state (CApplicationID.APP_ID_PUBLIC).getMenuTree (); 57 | 58 | // Bulk modify 59 | final MutableInt aCounterUpdated = new MutableInt (0); 60 | final MutableInt aCounterNoNeed = new MutableInt (0); 61 | aPublicMenuTree.iterateAllMenuObjects (aMenuObj -> { 62 | if (aMenuObj instanceof IMenuItemPage) 63 | { 64 | final IMenuItemPage aMenuItemPage = (IMenuItemPage) aMenuObj; 65 | if (aMenuItemPage.getPage () instanceof IWebPageResourceContent) 66 | { 67 | final IWebPageResourceContent aPageViewExternal = (IWebPageResourceContent) aMenuItemPage.getPage (); 68 | if (aPageViewExternal.isReadEveryTime ()) 69 | aCounterNoNeed.inc (); 70 | else 71 | { 72 | aPageViewExternal.updateFromResource (); 73 | aCounterUpdated.inc (); 74 | } 75 | } 76 | } 77 | }); 78 | final String sMsg = aCounterUpdated.intValue () + 79 | " pages were reloaded." + 80 | (aCounterNoNeed.isGT0 () ? " On " + 81 | aCounterNoNeed.intValue () + 82 | " pages no action was necessary because they are set to reload every time." 83 | : ""); 84 | LOGGER.info (sMsg); 85 | AuditHelper.onAuditExecuteSuccess ("page-reload", aCounterUpdated.getAsInteger (), aCounterNoNeed.getAsInteger ()); 86 | return success (sMsg); 87 | } 88 | 89 | return null; 90 | } 91 | 92 | @Override 93 | public void fillContent (@Nonnull final WebPageExecutionContext aWPEC) 94 | { 95 | final HCNodeList aNodeList = aWPEC.getNodeList (); 96 | 97 | // Perform 98 | aNodeList.addChild (_handleAction (aWPEC.getAction ())); 99 | 100 | aNodeList.addChild (h2 ("Cache handling")); 101 | aNodeList.addChild (div (new BootstrapButton ().setOnClick (aWPEC.getSelfHref () 102 | .add (CPageParam.PARAM_ACTION, ACTION_EXPIRE_PAGE_CACHE)) 103 | .addChild ("Expire static page cache"))); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/servlet/AppRootServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.servlet; 18 | 19 | import com.helger.commons.http.EHttpMethod; 20 | import com.helger.photon.core.servlet.AbstractPublicApplicationServlet; 21 | import com.helger.photon.core.servlet.RootXServletHandler; 22 | import com.helger.xservlet.AbstractXServlet; 23 | 24 | public class AppRootServlet extends AbstractXServlet 25 | { 26 | public AppRootServlet () 27 | { 28 | handlerRegistry ().registerHandler (EHttpMethod.GET, new RootXServletHandler (AbstractPublicApplicationServlet.SERVLET_DEFAULT_PATH)); 29 | handlerRegistry ().copyHandlerToAll (EHttpMethod.GET); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/servlet/PublicApplicationServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.servlet; 18 | 19 | import com.helger.peppol.pub.LayoutAreaContentProviderPublic; 20 | import com.helger.peppol.ui.AppLayoutHTMLProvider; 21 | import com.helger.photon.app.html.IHTMLProvider; 22 | import com.helger.photon.core.servlet.AbstractApplicationXServletHandler; 23 | import com.helger.photon.core.servlet.AbstractPublicApplicationServlet; 24 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 25 | 26 | public class PublicApplicationServlet extends AbstractPublicApplicationServlet 27 | { 28 | public PublicApplicationServlet () 29 | { 30 | super (new AbstractApplicationXServletHandler () 31 | { 32 | @Override 33 | protected IHTMLProvider createHTMLProvider (final IRequestWebScopeWithoutResponse aRequestScope) 34 | { 35 | return new AppLayoutHTMLProvider (LayoutAreaContentProviderPublic::getContent); 36 | } 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/servlet/SecureApplicationServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.servlet; 18 | 19 | import com.helger.peppol.secure.LayoutAreaContentProviderSecure; 20 | import com.helger.peppol.ui.AppLayoutHTMLProvider; 21 | import com.helger.photon.app.html.IHTMLProvider; 22 | import com.helger.photon.core.servlet.AbstractApplicationXServletHandler; 23 | import com.helger.photon.core.servlet.AbstractSecureApplicationServlet; 24 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 25 | 26 | /** 27 | * The servlet to show the secure application 28 | * 29 | * @author Philip Helger 30 | */ 31 | public class SecureApplicationServlet extends AbstractSecureApplicationServlet 32 | { 33 | public SecureApplicationServlet () 34 | { 35 | super (new AbstractApplicationXServletHandler () 36 | { 37 | @Override 38 | protected IHTMLProvider createHTMLProvider (final IRequestWebScopeWithoutResponse aRequestScope) 39 | { 40 | return new AppLayoutHTMLProvider (LayoutAreaContentProviderSecure::getContent); 41 | } 42 | }); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/servlet/SecureLoginFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.servlet; 18 | 19 | import javax.annotation.Nonnull; 20 | 21 | import com.helger.commons.state.EContinue; 22 | import com.helger.peppol.sharedui.CSharedUI; 23 | import com.helger.peppol.ui.PPLoginManager; 24 | import com.helger.photon.core.servlet.AbstractUnifiedResponseFilter; 25 | import com.helger.photon.security.login.LoggedInUserManager; 26 | import com.helger.photon.security.util.SecurityHelper; 27 | import com.helger.servlet.response.UnifiedResponse; 28 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 29 | 30 | import jakarta.servlet.ServletException; 31 | import jakarta.servlet.http.HttpServletResponse; 32 | 33 | /** 34 | * A special servlet filter that checks that a user can only access the config application after 35 | * authenticating. 36 | * 37 | * @author Philip Helger 38 | */ 39 | public final class SecureLoginFilter extends AbstractUnifiedResponseFilter 40 | { 41 | private PPLoginManager m_aLogin; 42 | 43 | @Override 44 | public void init () throws ServletException 45 | { 46 | super.init (); 47 | // Make the application login configurable if you like 48 | m_aLogin = new PPLoginManager (); 49 | } 50 | 51 | @Override 52 | @Nonnull 53 | protected EContinue handleRequest (@Nonnull final IRequestWebScopeWithoutResponse aRequestScope, 54 | @Nonnull final UnifiedResponse aUnifiedResponse) throws ServletException 55 | { 56 | if (m_aLogin.checkUserAndShowLogin (aRequestScope, aUnifiedResponse).isBreak ()) 57 | { 58 | // Show login screen 59 | return EContinue.BREAK; 60 | } 61 | 62 | // Check if the currently logged in user has the required roles 63 | final String sCurrentUserID = LoggedInUserManager.getInstance ().getCurrentUserID (); 64 | if (!SecurityHelper.hasUserAllRoles (sCurrentUserID, CSharedUI.REQUIRED_ROLE_IDS_CONFIG)) 65 | { 66 | aUnifiedResponse.setStatus (HttpServletResponse.SC_FORBIDDEN); 67 | return EContinue.BREAK; 68 | } 69 | 70 | return EContinue.CONTINUE; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/testendpoint/TestEndpointMicroTypeConverter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.testendpoint; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | import javax.annotation.concurrent.Immutable; 22 | 23 | import com.helger.peppol.sharedui.domain.ISMLConfiguration; 24 | import com.helger.peppol.sharedui.mgr.SharedUIMetaManager; 25 | import com.helger.peppol.smp.ESMPTransportProfile; 26 | import com.helger.photon.security.object.AbstractBusinessObjectMicroTypeConverter; 27 | import com.helger.photon.security.object.StubObject; 28 | import com.helger.xml.microdom.IMicroElement; 29 | import com.helger.xml.microdom.MicroElement; 30 | 31 | @Immutable 32 | public final class TestEndpointMicroTypeConverter extends AbstractBusinessObjectMicroTypeConverter 33 | { 34 | private static final String ATTR_COMPANY_NAME = "companyname"; 35 | private static final String ATTR_CONTACT_PERSON = "contactperson"; 36 | // Legacy name 37 | private static final String ATTR_PARTICIPANT_ID_ISSUER = "participantidscheme"; 38 | private static final String ATTR_PARTICIPANT_ID_VALUE = "participantidvalue"; 39 | private static final String ATTR_TRANSPORT_PROFILE = "transportprofile"; 40 | private static final String ATTR_SML = "sml"; 41 | 42 | @Nonnull 43 | public IMicroElement convertToMicroElement (@Nonnull final TestEndpoint aValue, 44 | @Nullable final String sNamespaceURI, 45 | @Nonnull final String sTagName) 46 | { 47 | final IMicroElement eValue = new MicroElement (sNamespaceURI, sTagName); 48 | setObjectFields (aValue, eValue); 49 | eValue.setAttribute (ATTR_COMPANY_NAME, aValue.getCompanyName ()); 50 | eValue.setAttribute (ATTR_CONTACT_PERSON, aValue.getContactPerson ()); 51 | eValue.setAttribute (ATTR_PARTICIPANT_ID_ISSUER, aValue.getParticipantIDIssuer ()); 52 | eValue.setAttribute (ATTR_PARTICIPANT_ID_VALUE, aValue.getParticipantIDValue ()); 53 | eValue.setAttribute (ATTR_TRANSPORT_PROFILE, aValue.getTransportProfile ().getID ()); 54 | eValue.setAttribute (ATTR_SML, aValue.getSML ().getID ()); 55 | return eValue; 56 | } 57 | 58 | @Nonnull 59 | public TestEndpoint convertToNative (@Nonnull final IMicroElement eValue) 60 | { 61 | final StubObject aStubObject = getStubObject (eValue); 62 | 63 | final String sCompanyName = eValue.getAttributeValue (ATTR_COMPANY_NAME); 64 | final String sContactPerson = eValue.getAttributeValue (ATTR_CONTACT_PERSON); 65 | final String sParticipantIDScheme = eValue.getAttributeValue (ATTR_PARTICIPANT_ID_ISSUER); 66 | final String sParticipantIDValue = eValue.getAttributeValue (ATTR_PARTICIPANT_ID_VALUE); 67 | 68 | final String sTransportProfile = eValue.getAttributeValue (ATTR_TRANSPORT_PROFILE); 69 | final ESMPTransportProfile eTransportProfile = ESMPTransportProfile.getFromIDOrNull (sTransportProfile); 70 | 71 | final String sSMLID = eValue.getAttributeValue (ATTR_SML); 72 | final ISMLConfiguration aSMLInfo = SharedUIMetaManager.getSMLConfigurationMgr ().getSMLInfoOfID (sSMLID); 73 | if (aSMLInfo == null) 74 | throw new IllegalStateException ("Failed to resolve SML with ID '" + sSMLID + "'"); 75 | 76 | // Create object 77 | return new TestEndpoint (aStubObject, 78 | sCompanyName, 79 | sContactPerson, 80 | sParticipantIDScheme, 81 | sParticipantIDValue, 82 | eTransportProfile, 83 | aSMLInfo); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/ui/AppLayoutHTMLProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.ui; 18 | 19 | import java.util.Locale; 20 | import java.util.function.Function; 21 | 22 | import javax.annotation.Nonnull; 23 | 24 | import com.helger.commons.string.StringHelper; 25 | import com.helger.html.hc.IHCNode; 26 | import com.helger.html.hc.html.metadata.HCHead; 27 | import com.helger.html.hc.html.root.HCHtml; 28 | import com.helger.html.hc.html.sections.HCBody; 29 | import com.helger.peppol.sharedui.SharedUIHelper; 30 | import com.helger.photon.core.appid.RequestSettings; 31 | import com.helger.photon.core.execcontext.ISimpleWebExecutionContext; 32 | import com.helger.photon.core.execcontext.LayoutExecutionContext; 33 | import com.helger.photon.core.html.AbstractSWECHTMLProvider; 34 | import com.helger.photon.core.menu.IMenuItemPage; 35 | import com.helger.web.scope.IRequestWebScopeWithoutResponse; 36 | import com.helger.xservlet.forcedredirect.ForcedRedirectException; 37 | 38 | /** 39 | * Main class for creating HTML output 40 | * 41 | * @author Philip Helger 42 | */ 43 | public class AppLayoutHTMLProvider extends AbstractSWECHTMLProvider 44 | { 45 | private final Function m_aFactory; 46 | 47 | public AppLayoutHTMLProvider (@Nonnull final Function aFactory) 48 | { 49 | m_aFactory = aFactory; 50 | } 51 | 52 | @Override 53 | protected void fillBody (@Nonnull final ISimpleWebExecutionContext aSWEC, @Nonnull final HCHtml aHtml) 54 | throws ForcedRedirectException 55 | { 56 | final IRequestWebScopeWithoutResponse aRequestScope = aSWEC.getRequestScope (); 57 | final Locale aDisplayLocale = aSWEC.getDisplayLocale (); 58 | final IMenuItemPage aMenuItem = RequestSettings.getMenuItem (aRequestScope); 59 | final LayoutExecutionContext aLEC = new LayoutExecutionContext (aSWEC, aMenuItem); 60 | final HCHead aHead = aHtml.head (); 61 | final HCBody aBody = aHtml.body (); 62 | 63 | // Add menu item in page title 64 | aHead.setPageTitle (StringHelper.getConcatenatedOnDemand (SharedUIHelper.getApplicationTitle (), 65 | " - ", 66 | aMenuItem.getDisplayText (aDisplayLocale))); 67 | 68 | final IHCNode aNode = m_aFactory.apply (aLEC); 69 | aBody.addChild (aNode); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/ui/PPLoginManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.ui; 18 | 19 | import com.helger.peppol.sharedui.CSharedUI; 20 | import com.helger.peppol.sharedui.SharedUIHelper; 21 | import com.helger.photon.bootstrap4.uictrls.ext.BootstrapLoginManager; 22 | 23 | public final class PPLoginManager extends BootstrapLoginManager 24 | { 25 | public PPLoginManager () 26 | { 27 | super (SharedUIHelper.getApplicationTitle () + " Administration - Login"); 28 | setRequiredRoleIDs (CSharedUI.REQUIRED_ROLE_IDS_CONFIG); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/helger/peppol/ui/page/AppPageViewExternal.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.ui.page; 18 | 19 | import javax.annotation.Nonnull; 20 | import javax.annotation.Nullable; 21 | 22 | import com.helger.commons.annotation.Nonempty; 23 | import com.helger.commons.io.resource.IReadableResource; 24 | import com.helger.commons.type.TypedObject; 25 | import com.helger.html.EHTMLVersion; 26 | import com.helger.html.hc.IHCNode; 27 | import com.helger.html.hc.impl.HCNodeList; 28 | import com.helger.peppol.app.AppConfig; 29 | import com.helger.peppol.app.CPPApp; 30 | import com.helger.peppol.comment.ui.CommentAction; 31 | import com.helger.peppol.comment.ui.CommentFormErrors; 32 | import com.helger.peppol.comment.ui.CommentUI; 33 | import com.helger.peppol.comment.ui.ECommentAction; 34 | import com.helger.photon.bootstrap4.pages.BootstrapWebPageUIHandler; 35 | import com.helger.photon.uicore.page.WebPageExecutionContext; 36 | import com.helger.photon.uicore.page.external.BasePageViewExternal; 37 | import com.helger.photon.uicore.page.external.PageViewExternalHTMLCleanser; 38 | import com.helger.xml.microdom.IMicroContainer; 39 | import com.helger.xml.microdom.util.MicroVisitor; 40 | 41 | public class AppPageViewExternal extends BasePageViewExternal 42 | { 43 | private static void _cleanCode (@Nonnull final IMicroContainer aCont) 44 | { 45 | // Do not clean texts, because this destroys "pre" formatting! 46 | final PageViewExternalHTMLCleanser aCleanser = new PageViewExternalHTMLCleanser (EHTMLVersion.HTML5).setCleanTexts (false); 47 | MicroVisitor.visit (aCont, aCleanser); 48 | } 49 | 50 | public AppPageViewExternal (@Nonnull @Nonempty final String sID, @Nonnull final String sName, @Nonnull final IReadableResource aResource) 51 | { 52 | // Special content cleaner 53 | super (sID, sName, aResource, AppPageViewExternal::_cleanCode); 54 | } 55 | 56 | @Override 57 | @Nullable 58 | public IHCNode getHeaderNode (@Nonnull final WebPageExecutionContext aWPEC) 59 | { 60 | final String sHeaderText = getHeaderText (aWPEC); 61 | return BootstrapWebPageUIHandler.INSTANCE.createPageHeader (sHeaderText); 62 | } 63 | 64 | @Override 65 | protected final void fillContent (@Nonnull final WebPageExecutionContext aWPEC) 66 | { 67 | super.fillContent (aWPEC); 68 | 69 | if (AppConfig.isWebPageCommentingEnabled ()) 70 | { 71 | // Show comments and "add comment" 72 | final HCNodeList aNodeList = aWPEC.getNodeList (); 73 | final TypedObject aTO = TypedObject.create (CPPApp.OT_PAGE, getID ()); 74 | aNodeList.addChild (CommentUI.getCommentList (aWPEC, 75 | aTO, 76 | CommentAction.createGeneric (ECommentAction.NONE), 77 | (CommentFormErrors) null, 78 | (IHCNode) null, 79 | true)); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/jaxb/peppol-commons.episode: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/com.helger.xml.microdom.convert.IMicroTypeConverterRegistrarSPI: -------------------------------------------------------------------------------- 1 | com.helger.peppol.app.config.AppMicroTypeConverterRegistarSPI 2 | -------------------------------------------------------------------------------- /src/main/resources/NOTICE: -------------------------------------------------------------------------------- 1 | ============================================================================= 2 | = NOTICE file corresponding to section 4d of the Apache License Version 2.0 = 3 | ============================================================================= 4 | This product includes Open Source Software developed by 5 | Philip Helger - https://www.helger.com/ 6 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | # philip[at]helger[dot]com 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | # Global flags for initializer 19 | global.debug = true 20 | global.production = false 21 | 22 | # Central directory where the data should be stored 23 | webapp.datapath = generated/ 24 | 25 | # Should all files of the application checked for readability? 26 | webapp.checkfileaccess = false 27 | 28 | # Is it a test version? E.g. a separate header 29 | webapp.testversion = false 30 | 31 | # Are comments on pages enabled? 32 | webapp.pagecomments.enabled = true 33 | 34 | # Set to "false" in production 35 | rest.log.exceptions = true 36 | 37 | # Set to "false" in production 38 | rest.exceptions.payload = true 39 | 40 | # Max REST calls per second per IP 41 | rest.limit.requestspersecond=2 42 | 43 | # reCAPTCHA settings 44 | recaptcha.webkey = 45 | recaptcha.secretkey= 46 | 47 | # Maximum 2 search requests per second 48 | validation.limit.requestspersecond=2 49 | 50 | # A combination of Peppol and others 51 | smpclient.truststore.type=jks 52 | smpclient.truststore.path=truststore/full-truststore.jks 53 | smpclient.truststore.password=peppol 54 | 55 | # A combination of Peppol and others 56 | pdclient.truststore.type=${smpclient.truststore.type} 57 | pdclient.truststore.path=${smpclient.truststore.path} 58 | pdclient.truststore.password=${smpclient.truststore.password} 59 | 60 | # Peppol AS4 keystore 61 | peppol.as4.keystore.type = pkcs12 62 | peppol.as4.keystore.path = test-ap-2021.p12 63 | peppol.as4.keystore.password = peppol 64 | peppol.as4.keystore.key.alias = openpeppol aisbl id von pop000306 65 | peppol.as4.keystore.key.password = peppol 66 | 67 | peppol.as4.truststore.type=jks 68 | peppol.as4.truststore.path=truststore/2018/pilot-truststore.jks 69 | peppol.as4.truststore.password=peppol 70 | 71 | phase4.dump.path=/var/www/peppol/as4-dumps 72 | -------------------------------------------------------------------------------- /src/main/resources/html/css.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/html/js.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/html/metatags.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.prod.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/main/resources/truststore/full-truststore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/resources/truststore/full-truststore.jks -------------------------------------------------------------------------------- /src/main/resources/viewpages/en/docs_peppol_firewall.xml: -------------------------------------------------------------------------------- 1 | 19 |

20 | This article outlines the required minimum firewall openings for default Peppol components. 21 | This list does not consider application specific firewall requirements.
22 | Please also remember the "connect once, connect everywhere" principle of Peppol, meaning that every 23 | Peppol AccessPoint (AP) MUST be capable of exchanging business documents with any other Peppol AP. 24 |

25 | 26 |
27 |
28 | Table of contents 29 |
30 |
31 |
    32 |
  1. Outbound requirements
  2. 33 |
  3. Inbound requirements
  4. 34 |
35 |
36 |
37 | 38 | 39 | 40 |

Firewall requirements for outbound connections

41 | 42 |

AP

43 |
    44 |
  • Allow TCP port 443 to * (all IPs) - for sending messages to another AP
  • 45 |
  • Allow TCP port 80 to * (all IPs) - for querying any SMP and to download CRL files from http://pki-crl.symauth.com/
  • 46 |
47 | 48 |

SMP

49 |
    50 |
  • Allow TCP port 443 to Peppol Directory 51 |
      52 |
    • Production: directory.peppol.eu
    • 53 |
    • Test: test-directory.peppol.eu
    • 54 |
    55 |
  • 56 |
  • Allow TCP port 443 to SMK/SML 57 |
      58 |
    • Production: edelivery.tech.ec.europa.eu
    • 59 |
    • Test: acc.edelivery.tech.ec.europa.eu
    • 60 |
    61 |
  • 62 |
63 | 64 | 65 |

Firewall requirements for inbound connections

66 | 67 |

AP

68 |
    69 |
  • Allow TCP port 443 from * (all IPs) - for receiving messages from another AP
  • 70 |
71 | 72 |

SMP

73 |
    74 |
  • Allow TCP port 80 from * (all IPs) - for being queried from any AP
  • 75 |
76 | -------------------------------------------------------------------------------- /src/main/resources/viewpages/en/docs_peppol_mlr.xml: -------------------------------------------------------------------------------- 1 | 19 |

20 | This page contains some general thought about the Message Level Response (MLR) and eventual successors. 21 |

22 | 23 |

MLR - Message Level Response

24 | 25 |

Introduction

26 | 27 |

28 | The MLR is a message between End Users (C1 and C4) executed by Service Providers (C2 and C3). 29 | The official specification can be found at 30 | https://docs.peppol.eu/poacc/upgrade-3/profiles/36-mlr/.
31 | The MLR is a regular Peppol document like Invoice or Order and as such needs to be transmitted like any other Peppol document 32 | wrapped in an SBDH and send via AS4.
33 | The MLR is an optional document and is NOT mandatory. So not every sender of a business document supports the reception of MLRs. 34 | To check if MLR reception is supported, an SMP lookup is needed.
35 | Please note that the usage of C1, C2, C3 and C4 should be reversed to be precise but in this document, the usage of 36 | C1, C2, C3 and C4 always refers to the role for the transmission of the source document to avoid confusion.
37 | Please note, that an MLR message can be send as a response to any business document as long as its reception is supported. 38 |

39 | 40 |

Scope

41 | 42 |

43 | The scope in which the MLR MAY be used is clearly defined in the 44 | specification chapter 2.2. 45 | As the sender is obliged to only send valid (=validated) content, validation on receiver side is an optional task. 46 | And don't mix MLR with BLR (Business Level Response - e.g. Invoice Response) because they have different meanings. 47 |

48 | 49 |

Proposed technical process

50 | 51 |

52 | The following process description shows a best practice process proposal. 53 | The assumption is, that receiver side validation was performed and the response should be transmitted back to C1. 54 |

55 | 56 |
    57 |
  1. You validate synchronously (that's important) and found at least one error
  2. 58 |
  3. You synchronously check if the sender of the business document (C1) supports MLR or not via an SMP query
  4. 59 |
  5. 60 | Case 1 - Sender supports MLR: 61 |
      62 |
    1. Send back a positive AS4 Receipt
    2. 63 |
    3. Create the MLR and trigger an explicit AS4 transmission of the MLR
      64 | Note: make sure the AS4 Receipt is received by the sender BEFORE the MLR is send (asynchronous processing required)
    4. 65 |
    66 | Case 2 - Sender does not support MLR: 67 |
      68 |
    1. Send back a synchronous AS4 Error with the error details
    2. 69 |
    3. Note: do not use SOAP Faults but an AS4 SignalMessage with an Error element inside
    4. 70 |
    71 |
  6. 72 |
73 | 74 |

Open Source software

75 | 76 |

77 | My peppol-commons project received an extension 78 | to deal with MLR in the peppol-mlr module. It allows to create the MLR payload in a consistent way. 79 | For the SMP lookup the same project has a peppol-smp-client module. 80 | Wrapping the MLR in SBDH and sending the message can be done with any compliant Peppol AS4 solution like phase4. 81 |

82 | 83 |

MLS - Message Level Status

84 | 85 |

Currently in the process of specification. More when ready.

86 | 87 |

88 | The intention of the MLS is to be a message between C2 and C3 instead of a message between C1 and C4 like the MLR. 89 | This makes it easier to mandate it, because only Service Providers are forced to support it. 90 |

91 | 92 | -------------------------------------------------------------------------------- /src/main/resources/viewpages/en/docs_sml_support.xml: -------------------------------------------------------------------------------- 1 | 19 |

20 | This page explains how and when to get support for SML issues. The support is handled 21 | by DIGIT eDelivery SUPPORT. You can reach them by email 22 | (EC-EDELIVERY-SUPPORT[AT]ec.europa.eu - replace [AT] with @ - changed in September 2022!) 23 | as well as by phone 24 | (phone number was send out to TICC mailing list on June 9th 2015). 25 |

26 | 27 |

SML SLAs

28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | 55 | 58 | 61 | 62 | 63 | 64 | 68 | 72 | 75 | 78 | 79 | 80 | 81 | 85 | 89 | 92 | 95 | 96 | 97 | 98 | 102 | 106 | 109 | 112 | 113 | 114 |
Standard ServiceStandby Service
PrioritySerivce LevelTargetSerivce LevelTarget
Critical 48 |
2 working hours
49 |
4 working hours
50 |
52 |
80%
53 |
80%
54 |
56 |
4 hours
57 |
59 |
90%
60 |
Urgent 65 |
4 working hours
66 |
6 working hours
67 |
69 |
80%
70 |
80%
71 |
73 |
8 hours
74 |
76 |
80%
77 |
Normal 82 |
10 working hours
83 |
20 working hours
84 |
86 |
80%
87 |
80%
88 |
90 |
NA – will be handled the next morning/day
91 |
93 |
NA
94 |
Low 99 |
20 working hours
100 |
40 working hours
101 |
103 |
80%
104 |
80%
105 |
107 |
NA – will be handled the next morning/day
108 |
110 |
NA
111 |
115 | 116 |

Standard Service: 08:00 → 18:00 Central Europe Time/Belgium

117 |
    118 |
  1. Critical, an incident will be classified as "Critical" when the service does not work; 119 | critical functions or totally unusable IS causing a major impact (unavailability);
  2. 120 |
  3. Urgent, an incident will be classified as "Urgent" when it is possible to use the 121 | service but limited in daily work (deteriorated method): large but not critical part of 122 | IS which can have an impact for the users;
  4. 123 |
  5. Normal, an incident will be classified as "Normal" when it does not affect production or 124 | limited loss of functionality;
  6. 125 |
  7. Low, an incident will be classified as "Low" for all other calls, without priority
  8. 126 |
127 | 128 |

Standby Service: 18:00 → 08:00 Central Europe Time/Belgium

129 |
    130 |
  1. Critical, an incident will be classified as "Critical" when the service does not work; 131 | critical functions or totally unusable IS causing a major impact (unavailability);
  2. 132 |
  3. Urgent, an incident will be classified as "Urgent" when it is possible to use the service 133 | but limited in daily work (deteriorated method): large but not critical part of IS which 134 | can have an impact for the users;
  4. 135 |
136 | 137 |

138 | Note: During the Standby only calls are supported, emails will be treated the next day at 08:00 AM 139 |

140 | -------------------------------------------------------------------------------- /src/main/resources/viewpages/en/docs_software_vendors.xml: -------------------------------------------------------------------------------- 1 | 19 |

20 | This page contains a list of software and vendors that are known to support Peppol and/or eDelivery functionality.
21 | The list on this page is not complete.
22 | No guarantee on anything on this page.
23 | If you want to be included, or you are a vendor and want something changed, ping me. 24 |

25 | 26 |

Other software lists:

27 | 32 | 33 | 34 |

AS4 solutions

35 | 36 |

This chapter deals with AS4 solutions only.

37 | 38 | 45 | 46 | 47 |

SMP solutions

48 | 49 |

This chapter deals with Service Metadata Publisher (SMP) solutions only.

50 | 51 | 54 | 55 | 56 |

Validation solutions

57 | 58 |

This chapter deals with validation solutions only.

59 | 60 | 65 | 66 | 67 |

Hosted AP and/or SMP solutions

68 | 69 |

This chapter deals with hosted Peppol solutions only

70 | 71 | 76 | 77 | 78 |

ERP solutions

79 | 80 |

This chapter deals with ERP solutions only

81 | 82 |
    83 |
  • None I am aware of
  • 84 |
85 | -------------------------------------------------------------------------------- /src/main/resources/viewpages/en/index.xml: -------------------------------------------------------------------------------- 1 | 19 |

20 | This page is supposed to contain technical information for Peppol implementers. 21 | This page is brought to you by Philip Helger. 22 | I was working for the Austrian Government, being the technical lead for e-Rechnung.gv.at the eInvoicing solution of the Austrian government. 23 | Since 2019 I am a freelancer and working on Peppol and eInvoicing projects. 24 |

25 | 26 |

27 | This page is currently divided into the following sections: 28 |

29 | 63 | 64 |

65 | The following general purpose Peppol links may also be of interest for you: 66 |

67 | 75 | 76 |

77 | Note: the complete source code of this web site can be found on 78 | GitHub. 79 |

80 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/sun-jaxws.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 23 | peppol-practical 24 | peppol.helger.com 25 | 26 | 27 | 60 28 | 29 | 30 | 31 | 32 | public 33 | 34 | 35 | 38 | 44 | 45 | 46 | 47 | 48 | com.helger.peppol.servlet.AppWebAppListener 49 | 50 | 51 | 52 | SecureLoginFilter 53 | com.helger.peppol.servlet.SecureLoginFilter 54 | 55 | 56 | SecureLoginFilter 57 | /secure/* 58 | 59 | 60 | 61 | SecureApplicationServlet 62 | com.helger.peppol.servlet.SecureApplicationServlet 63 | 64 | 65 | SecureApplicationServlet 66 | /secure/* 67 | 68 | 69 | 70 | PublicApplicationServlet 71 | com.helger.peppol.servlet.PublicApplicationServlet 72 | 73 | 74 | PublicApplicationServlet 75 | /public/* 76 | 77 | 78 | 79 | AppRootServlet 80 | com.helger.peppol.servlet.AppRootServlet 81 | 82 | 83 | AppRootServlet 84 | 85 | 86 | 87 | 88 | 89 | com.sun.xml.ws.transport.http.servlet.WSServletContextListener 90 | 91 | 92 | 93 | WSServlet 94 | com.sun.xml.ws.transport.http.servlet.WSServlet 95 | 96 | 97 | WSServlet 98 | /wsdvs 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/main/webapp/css/default.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | td { 18 | vertical-align: top; 19 | } 20 | 21 | /* Remove margin from content tables */ 22 | #viewport table { 23 | margin-bottom: 0 !important; 24 | } 25 | 26 | /* no bottom margin */ 27 | .panel ul, 28 | .panel ol { 29 | margin-bottom: 0; 30 | } 31 | 32 | #footer { 33 | display: block; 34 | background-color: #F5F5F5; 35 | border-top: 1px solid #E5E5E5; 36 | margin-top: 70px; 37 | padding-top: 30px; 38 | padding-bottom: 30px; 39 | text-align: center; 40 | } 41 | 42 | .footer-links .row { 43 | margin-left: 0; 44 | margin-right: 0; 45 | } 46 | 47 | #menu { 48 | min-width: 18rem; 49 | } 50 | 51 | #menu .nav>li>a { 52 | color: #716B7A; 53 | display: block; 54 | padding: 5px 5px; 55 | } 56 | 57 | #menu .nav>.active>a, 58 | #menu .nav>.active:hover>a, 59 | #menu .nav>.active:focus>a { 60 | background-color: rgba(0, 0, 0, 0); 61 | border-right: 1px solid #428BCA; 62 | color: #428BCA; 63 | font-weight: bold; 64 | } 65 | 66 | #menu .nav .nav>li>a { 67 | font-size: 90%; 68 | padding-bottom: 3px; 69 | padding-left: 15px; 70 | padding-top: 3px; 71 | } 72 | 73 | #menu .nav .nav .nav>li>a { 74 | padding-left: 25px; 75 | } 76 | 77 | #menu li.menu-separator { 78 | border-top: solid 1px rgba(0, 0, 0, 0.125); 79 | padding-top: 6px; 80 | } 81 | 82 | .paypal input { 83 | height: auto !important; 84 | width: auto !important; 85 | } 86 | 87 | .comment-title { 88 | font-weight: bold; 89 | } 90 | 91 | .comment-toolbar { 92 | float: right !important; 93 | } 94 | 95 | .comment-last-modification { 96 | font-size: small; 97 | } 98 | 99 | .table-sla tr.main th { 100 | background-color: #eee; 101 | } 102 | 103 | .table-sla td, 104 | .table-sla th { 105 | text-align: center; 106 | } 107 | 108 | .tab-content > .tab-pane { 109 | padding-top: 0.5rem; 110 | } 111 | -------------------------------------------------------------------------------- /src/main/webapp/css/default.min.css: -------------------------------------------------------------------------------- 1 | td{vertical-align:top}#viewport table{margin-bottom:0 !important}.panel ul,.panel ol{margin-bottom:0}#footer{display:block;background-color:#F5F5F5;border-top:1px solid #E5E5E5;margin-top:70px;padding-top:30px;padding-bottom:30px;text-align:center}.footer-links .row{margin-left:0;margin-right:0}#menu{min-width:18rem}#menu .nav>li>a{color:#716B7A;display:block;padding:5px 5px}#menu .nav>.active>a,#menu .nav>.active:hover>a,#menu .nav>.active:focus>a{background-color:rgba(0,0,0,0);border-right:1px solid #428BCA;color:#428BCA;font-weight:bold}#menu .nav .nav>li>a{font-size:90%;padding-bottom:3px;padding-left:15px;padding-top:3px}#menu .nav .nav .nav>li>a{padding-left:25px}#menu li.menu-separator{border-top:solid 1px rgba(0,0,0,0.125);padding-top:6px}.paypal input{height:auto !important;width:auto !important}.comment-title{font-weight:bold}.comment-toolbar{float:right !important}.comment-last-modification{font-size:small}.table-sla tr.main th{background-color:#eee}.table-sla td,.table-sla th{text-align:center}.tab-content>.tab-pane{padding-top:0.5rem} -------------------------------------------------------------------------------- /src/main/webapp/error404.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | Copyright (C) 2014 Philip Helger (www.helger.com) 4 | philip[at]helger[dot]com 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | 18 | --%><% 19 | // In Jetty, the request attributes are already URL encoded! 20 | final String sTarget = request.getContextPath () + "/public/?httpError=true" 21 | +"&httpStatusCode=" 22 | +String.valueOf(request.getAttribute ("jakarta.servlet.error.status_code")) 23 | +"&httpStatusMessage=" 24 | +String.valueOf(request.getAttribute ("jakarta.servlet.error.message")) 25 | +"&httpRequestUri=" 26 | +String.valueOf(request.getAttribute ("jakarta.servlet.error.request_uri")) 27 | +"&httpReferrer=" 28 | +request.getHeader ("Referer"); 29 | response.sendRedirect (sTarget); 30 | %> -------------------------------------------------------------------------------- /src/main/webapp/files/peppol-ws-test-client.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/files/peppol-ws-test-client.zip -------------------------------------------------------------------------------- /src/main/webapp/files/peppol/OpenPEPPOL Newsletter 2018-04-11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/files/peppol/OpenPEPPOL Newsletter 2018-04-11.pdf -------------------------------------------------------------------------------- /src/main/webapp/files/peppol/PEPPOL-Compliance-Policy_v1.0_PUBLISHED.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/files/peppol/PEPPOL-Compliance-Policy_v1.0_PUBLISHED.pdf -------------------------------------------------------------------------------- /src/main/webapp/files/peppol/PEPPOL_Certificates_Change_V1.2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/files/peppol/PEPPOL_Certificates_Change_V1.2.pdf -------------------------------------------------------------------------------- /src/main/webapp/files/validation/BIS2.0-VA-Spring2018.20180508.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/files/validation/BIS2.0-VA-Spring2018.20180508.zip -------------------------------------------------------------------------------- /src/main/webapp/files/validation/BIS2.0-VA-V3.5.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/files/validation/BIS2.0-VA-V3.5.0.zip -------------------------------------------------------------------------------- /src/main/webapp/files/validation/BIS2.0-VA-V3.5.0_RC1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/files/validation/BIS2.0-VA-V3.5.0_RC1.zip -------------------------------------------------------------------------------- /src/main/webapp/files/validation/Release_pkg_spring2017.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/files/validation/Release_pkg_spring2017.zip -------------------------------------------------------------------------------- /src/main/webapp/google9aa227895f65ee21.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google9aa227895f65ee21.html -------------------------------------------------------------------------------- /src/main/webapp/imgs/as4-message-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/imgs/as4-message-structure.png -------------------------------------------------------------------------------- /src/main/webapp/imgs/entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/imgs/entry.png -------------------------------------------------------------------------------- /src/main/webapp/imgs/entry_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/imgs/entry_add.png -------------------------------------------------------------------------------- /src/main/webapp/imgs/entry_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/imgs/entry_delete.png -------------------------------------------------------------------------------- /src/main/webapp/imgs/entry_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/imgs/entry_edit.png -------------------------------------------------------------------------------- /src/main/webapp/imgs/pki-structure-v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/imgs/pki-structure-v3.png -------------------------------------------------------------------------------- /src/main/webapp/imgs/pki-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phax/peppol-practical/33ae47f65ca601797ba55af0340785b326b0630f/src/main/webapp/imgs/pki-structure.png -------------------------------------------------------------------------------- /src/main/webapp/js/default.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | function AppClass(){} 18 | AppClass.prototype = { 19 | }; 20 | 21 | var App = window.App = new AppClass(); 22 | -------------------------------------------------------------------------------- /src/main/webapp/js/default.min.js: -------------------------------------------------------------------------------- 1 | 'use strict';function AppClass(){}AppClass.prototype={};var App=window.App=new AppClass; 2 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/SPITest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol; 18 | 19 | import org.junit.Test; 20 | 21 | import com.helger.commons.mock.SPITestHelper; 22 | import com.helger.photon.core.mock.PhotonCoreValidator; 23 | 24 | public final class SPITest 25 | { 26 | @Test 27 | public void testBasic () throws Exception 28 | { 29 | SPITestHelper.testIfAllSPIImplementationsAreValid (); 30 | PhotonCoreValidator.validateExternalResources (); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/comment/domain/CommentTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertFalse; 21 | import static org.junit.Assert.assertNotNull; 22 | import static org.junit.Assert.assertNull; 23 | 24 | import org.junit.Rule; 25 | import org.junit.Test; 26 | import org.junit.rules.TestRule; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | import com.helger.commons.mock.CommonsTestHelper; 31 | import com.helger.photon.app.mock.PhotonAppTestRule; 32 | import com.helger.xml.microdom.convert.MicroTypeConverter; 33 | import com.helger.xml.microdom.serialize.MicroWriter; 34 | import com.helger.xml.mock.XMLTestHelper; 35 | 36 | /** 37 | * Unit test class for class {@link Comment}. 38 | * 39 | * @author Philip Helger 40 | */ 41 | public final class CommentTest 42 | { 43 | private static final Logger LOGGER = LoggerFactory.getLogger (CommentTest.class); 44 | @Rule 45 | public TestRule m_aRule = new PhotonAppTestRule (); 46 | 47 | @Test 48 | public void testBasic () 49 | { 50 | final Comment aComment = new Comment ("unittest", ECommentState.APPROVED, "userid", "creatorname", "title", "text"); 51 | assertNotNull (aComment.getCreationDateTime ()); 52 | assertNull (aComment.getLastModificationDateTime ()); 53 | assertEquals ("userid", aComment.getUserID ()); 54 | assertEquals ("creatorname", aComment.getCreatorName ()); 55 | assertFalse (aComment.isDeleted ()); 56 | assertEquals ("title", aComment.getTitle ()); 57 | assertEquals ("text", aComment.getText ()); 58 | 59 | if (false) 60 | LOGGER.info (MicroWriter.getNodeAsString (MicroTypeConverter.convertToMicroElement (aComment, "comment"))); 61 | 62 | CommonsTestHelper.testDefaultSerialization (aComment); 63 | XMLTestHelper.testMicroTypeConversion (aComment); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/comment/domain/CommentThreadObjectTypeManagerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertFalse; 21 | import static org.junit.Assert.assertNotNull; 22 | import static org.junit.Assert.assertNull; 23 | import static org.junit.Assert.fail; 24 | 25 | import org.junit.Rule; 26 | import org.junit.Test; 27 | import org.junit.rules.TestRule; 28 | 29 | import com.helger.commons.type.ObjectType; 30 | import com.helger.dao.DAOException; 31 | import com.helger.photon.app.mock.PhotonAppWebTestRule; 32 | 33 | /** 34 | * Unit test class for class {@link CommentThreadObjectTypeManager}. 35 | * 36 | * @author Philip Helger 37 | */ 38 | public final class CommentThreadObjectTypeManagerTest 39 | { 40 | @Rule 41 | public final TestRule m_aRule = new PhotonAppWebTestRule (); 42 | 43 | @Test 44 | public void testBasic () throws DAOException 45 | { 46 | final CommentThreadObjectTypeManager aMgr = new CommentThreadObjectTypeManager (new ObjectType ("mock")); 47 | 48 | final Comment aComment = new Comment ("unittest", ECommentState.APPROVED, "userid", "creatorname", "title", "text"); 49 | assertNotNull (aComment.getCreationDateTime ()); 50 | assertNull (aComment.getLastModificationDateTime ()); 51 | assertEquals ("userid", aComment.getUserID ()); 52 | assertEquals ("creatorname", aComment.getCreatorName ()); 53 | assertFalse (aComment.isDeleted ()); 54 | assertEquals ("title", aComment.getTitle ()); 55 | assertEquals ("text", aComment.getText ()); 56 | 57 | final String sOwningObjectID = "blafoofasel"; 58 | try 59 | { 60 | assertNotNull (aMgr.getAllCommentThreadsOfObject (sOwningObjectID)); 61 | assertEquals (0, aMgr.getAllCommentThreadsOfObject (sOwningObjectID).size ()); 62 | 63 | // Create new thread 64 | final String sThreadID = aMgr.createNewThread (sOwningObjectID, aComment).getID (); 65 | 66 | assertEquals (1, aMgr.getAllCommentThreadsOfObject (sOwningObjectID).size ()); 67 | 68 | // Add another comments into the thread 69 | aMgr.addCommentToThread (sOwningObjectID, 70 | sThreadID, 71 | sThreadID, 72 | new Comment ("unittest", ECommentState.APPROVED, "userid", "creatorname", "title2", "text2")); 73 | 74 | assertEquals (1, aMgr.getAllCommentThreadsOfObject (sOwningObjectID).size ()); 75 | 76 | // Adding the same should fail 77 | try 78 | { 79 | aMgr.createNewThread (sOwningObjectID, aComment); 80 | fail (); 81 | } 82 | catch (final IllegalArgumentException ex) 83 | {} 84 | 85 | // Create a second thread 86 | aMgr.createNewThread (sOwningObjectID, 87 | new Comment ("unittest", ECommentState.APPROVED, "userid2", "creatorname2", "title4", "text4")); 88 | assertEquals (2, aMgr.getAllCommentThreadsOfObject (sOwningObjectID).size ()); 89 | } 90 | finally 91 | { 92 | aMgr.removeAllCommentThreadsOfObject (sOwningObjectID); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/comment/domain/CommentThreadTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.comment.domain; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertFalse; 21 | import static org.junit.Assert.assertNotNull; 22 | import static org.junit.Assert.assertNull; 23 | import static org.junit.Assert.assertSame; 24 | 25 | import org.junit.Rule; 26 | import org.junit.Test; 27 | import org.junit.rules.TestRule; 28 | import org.slf4j.Logger; 29 | import org.slf4j.LoggerFactory; 30 | 31 | import com.helger.photon.app.mock.PhotonAppTestRule; 32 | import com.helger.xml.microdom.convert.MicroTypeConverter; 33 | import com.helger.xml.microdom.serialize.MicroWriter; 34 | import com.helger.xml.mock.XMLTestHelper; 35 | 36 | /** 37 | * Unit test class for class {@link CommentThread}. 38 | * 39 | * @author Philip Helger 40 | */ 41 | public final class CommentThreadTest 42 | { 43 | private static final Logger LOGGER = LoggerFactory.getLogger (CommentThreadTest.class); 44 | @Rule 45 | public TestRule m_aRule = new PhotonAppTestRule (); 46 | 47 | @Test 48 | public void testBasic () 49 | { 50 | final IComment aInitialComment = new Comment ("unittest", ECommentState.APPROVED, "userid", "creatorname", "title", "text"); 51 | assertNotNull (aInitialComment.getCreationDateTime ()); 52 | assertNull (aInitialComment.getLastModificationDateTime ()); 53 | assertEquals ("userid", aInitialComment.getUserID ()); 54 | assertEquals ("creatorname", aInitialComment.getCreatorName ()); 55 | assertFalse (aInitialComment.isDeleted ()); 56 | assertEquals ("title", aInitialComment.getTitle ()); 57 | assertEquals ("text", aInitialComment.getText ()); 58 | 59 | final ICommentThread aCommentThread = new CommentThread (aInitialComment); 60 | assertEquals (aInitialComment.getID (), aCommentThread.getID ()); 61 | assertEquals (1, aCommentThread.getTotalCommentCount ()); 62 | 63 | // Add another comments into the thread 64 | aCommentThread.addComment (aInitialComment, 65 | new Comment ("unittest", ECommentState.APPROVED, "userid", "creatorname", "title2", "text2")); 66 | assertEquals (2, aCommentThread.getTotalCommentCount ()); 67 | 68 | // Add another comments into the thread 69 | final IComment aComment3 = aCommentThread.addComment (aInitialComment, 70 | new Comment ("unittest", 71 | ECommentState.APPROVED, 72 | "userid", 73 | "creatorname", 74 | "title3", 75 | "text3")); 76 | assertEquals (3, aCommentThread.getTotalCommentCount ()); 77 | assertSame (aComment3, aCommentThread.getCommentOfID (aComment3.getID ())); 78 | 79 | if (false) 80 | LOGGER.info (MicroWriter.getNodeAsString (MicroTypeConverter.convertToMicroElement (aCommentThread, "commentthread"))); 81 | 82 | XMLTestHelper.testMicroTypeConversion (aCommentThread); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/crm/CRMGroupTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.crm; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertTrue; 21 | 22 | import org.junit.Rule; 23 | import org.junit.Test; 24 | import org.junit.rules.TestRule; 25 | 26 | import com.helger.commons.mock.CommonsTestHelper; 27 | import com.helger.commons.string.StringHelper; 28 | import com.helger.photon.app.mock.PhotonAppWebTestRule; 29 | import com.helger.xml.mock.XMLTestHelper; 30 | 31 | /** 32 | * Unit test class for class {@link CRMGroup}. 33 | * 34 | * @author Philip Helger 35 | */ 36 | public final class CRMGroupTest 37 | { 38 | @Rule 39 | public final TestRule m_aRule = new PhotonAppWebTestRule (); 40 | 41 | @Test 42 | public void testBasic () 43 | { 44 | final CRMGroup aGroup = new CRMGroup ("Name", "bla@foo.com"); 45 | assertTrue (StringHelper.hasText (aGroup.getID ())); 46 | assertEquals ("Name", aGroup.getDisplayName ()); 47 | assertEquals ("bla@foo.com", aGroup.getSenderEmailAddress ()); 48 | // Only ID is relevant! 49 | CommonsTestHelper.testDefaultImplementationWithDifferentContentObject (aGroup, new CRMGroup ("Name", "bla@foo.com")); 50 | XMLTestHelper.testMicroTypeConversion (aGroup); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/jetty/JettyStopPP.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.jetty; 18 | 19 | import java.io.IOException; 20 | 21 | import com.helger.photon.jetty.JettyStopper; 22 | 23 | public final class JettyStopPP 24 | { 25 | public static void main (final String [] args) throws IOException 26 | { 27 | new JettyStopper ().run (); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/jetty/RunInJettyPP.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.jetty; 18 | 19 | import javax.annotation.concurrent.Immutable; 20 | 21 | import com.helger.photon.jetty.JettyStarter; 22 | 23 | /** 24 | * Run peppol-practical as a standalone web application in Jetty on port 8080. 25 | *
26 | * http://localhost:8080/ 27 | * 28 | * @author Philip Helger 29 | */ 30 | @Immutable 31 | public final class RunInJettyPP 32 | { 33 | public static void main (final String [] args) throws Exception 34 | { 35 | new JettyStarter (RunInJettyPP.class).run (); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/phive/MainCheckDDDConsistency.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.phive; 18 | 19 | import java.util.Comparator; 20 | import java.util.Map; 21 | 22 | import javax.annotation.Nonnull; 23 | 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | import com.helger.commons.annotation.Nonempty; 28 | import com.helger.commons.collection.impl.ICommonsList; 29 | import com.helger.commons.mutable.MutableInt; 30 | import com.helger.commons.string.StringHelper; 31 | import com.helger.ddd.model.DDDValueProviderList; 32 | import com.helger.ddd.model.DDDValueProviderPerSyntax; 33 | import com.helger.ddd.model.DDDValueProviderPerSyntax.ISelectorCallback; 34 | import com.helger.ddd.model.EDDDDeterminedField; 35 | import com.helger.ddd.model.VPSourceValue; 36 | import com.helger.diver.api.coord.DVRCoordinate; 37 | import com.helger.peppol.sharedui.validate.VESRegistry; 38 | 39 | public class MainCheckDDDConsistency 40 | { 41 | private static final Logger LOGGER = LoggerFactory.getLogger (MainCheckDDDConsistency.class); 42 | 43 | public static void main (final String [] args) 44 | { 45 | final MutableInt aChecks = new MutableInt (0); 46 | 47 | // For each value provider of each syntax 48 | final DDDValueProviderList aVPL = DDDValueProviderList.getDefaultValueProviderList (); 49 | for (final Map.Entry e1 : aVPL.valueProvidersPerSyntaxes () 50 | .getSortedByKey (Comparator.naturalOrder ()) 51 | .entrySet ()) 52 | { 53 | LOGGER.info ("Syntax " + e1.getKey ()); 54 | 55 | // Check each VESID selector 56 | e1.getValue ().forEachSelector (new ISelectorCallback () 57 | { 58 | public void acceptFlag (final ICommonsList aSourceValues, final String sFlag) 59 | {} 60 | 61 | public void acceptDeterminedValue (@Nonnull @Nonempty final ICommonsList aSourceValues, 62 | @Nonnull final EDDDDeterminedField eDeterminedField, 63 | @Nonnull final String sDeterminedValue) 64 | { 65 | final String sSrcString = StringHelper.imploder () 66 | .source (aSourceValues, 67 | x -> '[' + 68 | x.getSourceField ().name () + 69 | '=' + 70 | x.getSourceValue () + 71 | ']') 72 | .separator ("; ") 73 | .build (); 74 | // We only care about the VESID 75 | if (eDeterminedField == EDDDDeterminedField.VESID) 76 | { 77 | aChecks.inc (); 78 | final String sVESID = sDeterminedValue; 79 | LOGGER.info (" " + sSrcString + " -- " + sVESID); 80 | if (VESRegistry.getFromIDOrNull (DVRCoordinate.parseOrNull (sVESID)) == null) 81 | throw new IllegalStateException ("VES ID '" + sVESID + "' is unknown"); 82 | } 83 | } 84 | }); 85 | } 86 | LOGGER.info (aChecks.intValue () + " checks done"); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/supplementary/tools/MainCreateNiceNameMappingXML.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.supplementary.tools; 18 | 19 | import java.io.File; 20 | import java.util.Comparator; 21 | import java.util.Map; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import com.helger.peppol.sharedui.domain.NiceNameEntry; 27 | import com.helger.peppol.sharedui.ui.SharedCommonUI; 28 | import com.helger.peppolid.IProcessIdentifier; 29 | import com.helger.xml.microdom.IMicroDocument; 30 | import com.helger.xml.microdom.IMicroElement; 31 | import com.helger.xml.microdom.MicroDocument; 32 | import com.helger.xml.microdom.serialize.MicroWriter; 33 | 34 | public class MainCreateNiceNameMappingXML 35 | { 36 | private static final Logger LOGGER = LoggerFactory.getLogger (MainCreateNiceNameMappingXML.class); 37 | 38 | public static void main (final String [] args) 39 | { 40 | { 41 | final IMicroDocument aDoc = new MicroDocument (); 42 | final IMicroElement eRoot = aDoc.appendElement ("root"); 43 | eRoot.setAttribute ("type", "doctypeid"); 44 | for (final Map.Entry aEntry : SharedCommonUI.getDocTypeNames () 45 | .getSortedByKey (Comparator.naturalOrder ()) 46 | .entrySet ()) 47 | { 48 | final NiceNameEntry aNNE = aEntry.getValue (); 49 | final IMicroElement eItem = eRoot.appendElement ("item") 50 | .setAttribute ("id", aEntry.getKey ()) 51 | .setAttribute ("name", aNNE.getName ()) 52 | .setAttribute ("state", aNNE.getState ().getID ()); 53 | if (aNNE.hasProcessIDs ()) 54 | for (final IProcessIdentifier aProcID : aNNE.getAllProcIDs ()) 55 | eItem.appendElement ("procid") 56 | .setAttribute ("scheme", aProcID.getScheme ()) 57 | .setAttribute ("value", aProcID.getValue ()); 58 | } 59 | MicroWriter.writeToFile (aDoc, new File ("docs/doctypeid-mapping.xml")); 60 | } 61 | 62 | { 63 | final IMicroDocument aDoc = new MicroDocument (); 64 | final IMicroElement eRoot = aDoc.appendElement ("root"); 65 | eRoot.setAttribute ("type", "processid"); 66 | for (final Map.Entry aEntry : SharedCommonUI.getProcessNames () 67 | .getSortedByKey (Comparator.naturalOrder ()) 68 | .entrySet ()) 69 | eRoot.appendElement ("item") 70 | .setAttribute ("id", aEntry.getKey ()) 71 | .setAttribute ("name", aEntry.getValue ().getName ()) 72 | .setAttribute ("state", aEntry.getValue ().getState ().getID ()); 73 | MicroWriter.writeToFile (aDoc, new File ("docs/processid-mapping.xml")); 74 | } 75 | LOGGER.info ("Done"); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/supplementary/tools/MainListVESIDs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.supplementary.tools; 18 | 19 | import java.io.File; 20 | import java.nio.charset.StandardCharsets; 21 | import java.util.Locale; 22 | 23 | import com.helger.commons.collection.impl.ICommonsList; 24 | import com.helger.commons.io.file.SimpleFileIO; 25 | import com.helger.peppol.sharedui.validate.VESRegistry; 26 | import com.helger.peppol.sharedui.validate.ui.HCVESSelect; 27 | import com.helger.phive.api.executorset.IValidationExecutorSet; 28 | import com.helger.phive.api.executorset.ValidationExecutorSetAlias; 29 | import com.helger.phive.xml.source.IValidationSourceXML; 30 | 31 | public final class MainListVESIDs 32 | { 33 | private static String _getPayload () 34 | { 35 | final ICommonsList > aAll = true ? HCVESSelect.getAllSortedCorrect (Locale.US) 36 | : VESRegistry.getAllSortedByID () 37 | .copyOfValues (); 38 | 39 | final StringBuilder aSB = new StringBuilder (); 40 | aSB.append ("\n"); 41 | aSB.append ("
    \n"); 42 | for (final IValidationExecutorSet aEntry : aAll) 43 | { 44 | final String sAliasHint; 45 | if (aEntry instanceof ValidationExecutorSetAlias ) 46 | { 47 | // final var aAlias = (ValidationExecutorSetAlias ) aEntry; 48 | // TODO read alias details (phive 10.1.1+) 49 | sAliasHint = " (alias)"; 50 | } 51 | else 52 | sAliasHint = ""; 53 | aSB.append ("
  • ") 54 | .append (aEntry.getID ().getAsSingleID ()) 55 | .append (" - ") 56 | .append (aEntry.getDisplayName ()) 57 | .append (sAliasHint) 58 | .append (aEntry.getStatus ().isDeprecated () ? " (Deprecated)" : "") 59 | .append ("
  • \n"); 60 | } 61 | return aSB.append ("
\n").toString (); 62 | } 63 | 64 | public static void main (final String [] args) 65 | { 66 | final String sNewPayload = _getPayload (); 67 | 68 | final File aFile = new File ("src/main/resources/viewpages/en/validation_dvs.xml"); 69 | if (!aFile.exists ()) 70 | throw new IllegalStateException (); 71 | 72 | final String sOld = SimpleFileIO.getFileAsString (aFile, StandardCharsets.UTF_8); 73 | 74 | final String sStart = ""; 75 | final int nStart = sOld.indexOf (sStart); 76 | if (nStart < 0) 77 | throw new IllegalStateException (); 78 | 79 | final String sEnd = ""; 80 | final int nEnd = sOld.indexOf (sEnd); 81 | if (nEnd < 0) 82 | throw new IllegalStateException (); 83 | 84 | final String sNew = new StringBuilder ().append (sOld, 0, nStart + sStart.length ()) 85 | .append ('\n') 86 | .append (sNewPayload) 87 | .append (sOld, nEnd, sOld.length ()) 88 | .toString (); 89 | SimpleFileIO.writeFile (aFile, sNew, StandardCharsets.UTF_8); 90 | System.out.println ("Finished updating " + aFile.getAbsolutePath ()); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/com/helger/peppol/ws/MainWSDVSClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2025 Philip Helger (www.helger.com) 3 | * philip[at]helger[dot]com 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package com.helger.peppol.ws; 18 | 19 | import java.nio.charset.StandardCharsets; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import com.helger.commons.io.resource.ClassPathResource; 25 | import com.helger.commons.io.resource.FileSystemResource; 26 | import com.helger.commons.io.stream.StreamHelper; 27 | import com.helger.commons.url.URLHelper; 28 | import com.helger.jaxb.GenericJAXBMarshaller; 29 | import com.helger.peppol.wsclient2.ItemType; 30 | import com.helger.peppol.wsclient2.RequestType; 31 | import com.helger.peppol.wsclient2.ResponseType; 32 | import com.helger.peppol.wsclient2.ValidateFaultError; 33 | import com.helger.peppol.wsclient2.ValidationResultType; 34 | import com.helger.peppol.wsclient2.WSDVSPort; 35 | import com.helger.peppol.wsclient2.WSDVSService; 36 | import com.helger.phive.peppol.PeppolValidation2024_11; 37 | import com.helger.wsclient.WSClientConfig; 38 | import com.helger.wsclient.WSHelper; 39 | 40 | import jakarta.xml.ws.BindingProvider; 41 | 42 | public final class MainWSDVSClient 43 | { 44 | private static final Logger LOGGER = LoggerFactory.getLogger (MainWSDVSClient.class); 45 | 46 | public static void main (final String [] args) throws ValidateFaultError 47 | { 48 | WSHelper.enableSoapLogging (true); 49 | 50 | LOGGER.info ("Starting the engines"); 51 | final String sXML = StreamHelper.getAllBytesAsString (new ClassPathResource ("ws/invoice1.xml"), 52 | StandardCharsets.UTF_8); 53 | 54 | final WSDVSService aService = new WSDVSService (new FileSystemResource ("src/main/webapp/WEB-INF/wsdl/pp-dvs.wsdl").getAsURL ()); 55 | final WSDVSPort aPort = aService.getWSDVSPort (); 56 | 57 | final WSClientConfig aWsClientConfig = new WSClientConfig (URLHelper.getAsURL (true ? "https://peppol.helger.com/wsdvs" 58 | : "http://localhost:8080/wsdvs")); 59 | aWsClientConfig.applyWSSettingsToBindingProvider ((BindingProvider) aPort); 60 | 61 | LOGGER.info ("Starting validation process"); 62 | final RequestType aRequest = new RequestType (); 63 | aRequest.setVESID (PeppolValidation2024_11.VID_OPENPEPPOL_INVOICE_UBL_V3.getAsSingleID ()); 64 | aRequest.setXML (sXML); 65 | aRequest.setDisplayLocale ("en"); 66 | final ResponseType aResponse = aPort.validate (aRequest); 67 | 68 | if (false) 69 | LOGGER.info ("Result:\n" + 70 | new GenericJAXBMarshaller <> (ResponseType.class, 71 | com.helger.peppol.wsclient2.ObjectFactory._ValidateResponseOutput_QNAME).getAsString (aResponse)); 72 | 73 | LOGGER.info ("Success: " + aResponse.isSuccess ()); 74 | LOGGER.info ("Interrupted: " + aResponse.isInterrupted ()); 75 | LOGGER.info ("Most severe error level: " + aResponse.getMostSevereErrorLevel ()); 76 | int nPos = 1; 77 | final int nMaxPos = aResponse.getResultCount (); 78 | for (final ValidationResultType aResult : aResponse.getResult ()) 79 | { 80 | LOGGER.info (" [" + 81 | nPos + 82 | "/" + 83 | nMaxPos + 84 | "] " + 85 | aResult.getArtifactType () + 86 | " - " + 87 | aResult.getArtifactPath ()); 88 | ++nPos; 89 | 90 | LOGGER.info (" Success: " + aResult.getSuccess ()); 91 | for (final ItemType aItem : aResult.getItem ()) 92 | { 93 | LOGGER.info (" Error Level: " + aItem.getErrorLevel ()); 94 | if (aItem.getErrorID () != null) 95 | LOGGER.info (" Error ID: " + aItem.getErrorID ()); 96 | if (aItem.getErrorFieldName () != null) 97 | LOGGER.info (" Error Field: " + aItem.getErrorFieldName ()); 98 | LOGGER.info (" Error Text: " + aItem.getErrorText ()); 99 | if (aItem.getErrorLocation () != null) 100 | LOGGER.info (" Location: " + aItem.getErrorLocation ()); 101 | if (aItem.getTest () != null) 102 | LOGGER.info (" Test: " + aItem.getTest ()); 103 | LOGGER.info ("--"); 104 | } 105 | } 106 | LOGGER.info ("Done"); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/resources/example-ws-response.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | --------------------------------------------------------------------------------