├── documentation ├── images │ ├── form │ │ ├── form-1.PNG │ │ ├── form-2.PNG │ │ ├── form-3.PNG │ │ ├── form-4.PNG │ │ ├── form-5.PNG │ │ ├── form-6.PNG │ │ ├── form-7.PNG │ │ └── form-8.PNG │ └── cloudservice │ │ ├── cloudservice-1.PNG │ │ ├── cloudservice-2.PNG │ │ ├── cloudservice-3.PNG │ │ ├── cloudservice-4.PNG │ │ ├── cloudservice-5.PNG │ │ ├── cloudservice-6.PNG │ │ └── cloudservice-7.PNG ├── FORM_SUBMISSION_SETUP.md └── DOCUSIGN_CLOUDSERVICE_SETUP.md ├── ui.config ├── src │ └── main │ │ └── content │ │ ├── META-INF │ │ └── vault │ │ │ └── filter.xml │ │ └── jcr_root │ │ └── apps │ │ └── docusign │ │ └── osgiconfig │ │ └── config │ │ ├── org.apache.sling.jcr.repoinit.RepositoryInitializer-docusign.config │ │ └── org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-docusign.config └── pom.xml ├── .github ├── ISSUE_TEMPLATE │ └── BUG_REPORT.md ├── PULL_REQUEST_TEMPLATE.md ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md ├── ui.apps ├── src │ └── main │ │ └── content │ │ ├── jcr_root │ │ └── apps │ │ │ ├── docusign │ │ │ ├── cloudConfig │ │ │ │ ├── components │ │ │ │ │ ├── configurations │ │ │ │ │ │ ├── clientlib │ │ │ │ │ │ │ ├── js.txt │ │ │ │ │ │ │ ├── .content.xml │ │ │ │ │ │ │ └── js │ │ │ │ │ │ │ │ └── docusign.js │ │ │ │ │ │ ├── meta │ │ │ │ │ │ │ └── meta.html │ │ │ │ │ │ └── views │ │ │ │ │ │ │ ├── row │ │ │ │ │ │ │ └── row.html │ │ │ │ │ │ │ ├── column │ │ │ │ │ │ │ └── column.html │ │ │ │ │ │ │ ├── card │ │ │ │ │ │ │ └── card.html │ │ │ │ │ │ │ └── columnpreview │ │ │ │ │ │ │ └── columnpreview.html │ │ │ │ │ └── .content.xml │ │ │ │ └── content │ │ │ │ │ ├── .content.xml │ │ │ │ │ └── docusign │ │ │ │ │ ├── createcloudconfigwizard │ │ │ │ │ ├── commons │ │ │ │ │ │ ├── .content.xml │ │ │ │ │ │ └── columnpreview │ │ │ │ │ │ │ └── .content.xml │ │ │ │ │ ├── .content.xml │ │ │ │ │ └── cloudservices │ │ │ │ │ │ └── .content.xml │ │ │ │ │ ├── properties │ │ │ │ │ └── .content.xml │ │ │ │ │ └── .content.xml │ │ │ └── submit │ │ │ │ ├── .content.xml │ │ │ │ ├── post.POST.jsp │ │ │ │ └── _cq_dialog │ │ │ │ └── .content.xml │ │ │ └── cq │ │ │ └── core │ │ │ └── content │ │ │ ├── .content.xml │ │ │ └── nav │ │ │ ├── .content.xml │ │ │ └── tools │ │ │ ├── cloudservices │ │ │ ├── .content.xml │ │ │ └── docusignlaunch │ │ │ │ └── .content.xml │ │ │ └── .content.xml │ │ └── META-INF │ │ └── vault │ │ └── filter.xml └── pom.xml ├── core ├── src │ └── main │ │ └── java │ │ └── com │ │ └── adobe │ │ └── aemforms │ │ └── samples │ │ └── forms │ │ └── integration │ │ └── docusign │ │ └── core │ │ ├── package-info.java │ │ ├── utils │ │ ├── Constants.java │ │ └── CloudConfigurationUtils.java │ │ ├── UIConfigHelper.java │ │ ├── models │ │ ├── CloudConfigSlingModel.java │ │ └── UIConfigHelperImpl.java │ │ ├── servlet │ │ └── OAuthServlet.java │ │ └── services │ │ └── DocuSignSubmitActionService.java └── pom.xml ├── all ├── src │ └── main │ │ └── content │ │ └── META-INF │ │ └── vault │ │ ├── filter.xml │ │ └── definition │ │ └── .content.xml └── pom.xml ├── .gitignore ├── README.md ├── ui.apps.structure └── pom.xml └── LICENSE /documentation/images/form/form-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/form/form-1.PNG -------------------------------------------------------------------------------- /documentation/images/form/form-2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/form/form-2.PNG -------------------------------------------------------------------------------- /documentation/images/form/form-3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/form/form-3.PNG -------------------------------------------------------------------------------- /documentation/images/form/form-4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/form/form-4.PNG -------------------------------------------------------------------------------- /documentation/images/form/form-5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/form/form-5.PNG -------------------------------------------------------------------------------- /documentation/images/form/form-6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/form/form-6.PNG -------------------------------------------------------------------------------- /documentation/images/form/form-7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/form/form-7.PNG -------------------------------------------------------------------------------- /documentation/images/form/form-8.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/form/form-8.PNG -------------------------------------------------------------------------------- /documentation/images/cloudservice/cloudservice-1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/cloudservice/cloudservice-1.PNG -------------------------------------------------------------------------------- /documentation/images/cloudservice/cloudservice-2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/cloudservice/cloudservice-2.PNG -------------------------------------------------------------------------------- /documentation/images/cloudservice/cloudservice-3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/cloudservice/cloudservice-3.PNG -------------------------------------------------------------------------------- /documentation/images/cloudservice/cloudservice-4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/cloudservice/cloudservice-4.PNG -------------------------------------------------------------------------------- /documentation/images/cloudservice/cloudservice-5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/cloudservice/cloudservice-5.PNG -------------------------------------------------------------------------------- /documentation/images/cloudservice/cloudservice-6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/cloudservice/cloudservice-6.PNG -------------------------------------------------------------------------------- /documentation/images/cloudservice/cloudservice-7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adobe/aem-forms-docusign-sample/main/documentation/images/cloudservice/cloudservice-7.PNG -------------------------------------------------------------------------------- /ui.config/src/main/content/META-INF/vault/filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Issue report 3 | about: Having an issue? Please create a report to explain what it is about. 4 | 5 | --- 6 | 7 | ### Expected Behaviour 8 | 9 | ### Actual Behaviour 10 | 11 | ### Reproduce Scenario (including but not limited to) 12 | 13 | #### Steps to Reproduce 14 | 15 | #### Platform and Version 16 | 17 | #### Sample Code that illustrates the problem 18 | 19 | #### Logs taken while reproducing problem -------------------------------------------------------------------------------- /ui.config/src/main/content/jcr_root/apps/docusign/osgiconfig/config/org.apache.sling.jcr.repoinit.RepositoryInitializer-docusign.config: -------------------------------------------------------------------------------- 1 | scripts=["create\ service\ user\ forms-docusign-sample-service-user\ with\ forced\ path\ system/cq\:services/sample/forms/docusign", 2 | "set\ principal\ ACL\ for\ forms-docusign-sample-service-user\r\nallow\ jcr\:read\ on\ /conf\ restriction(rep\:glob,/*/cloudconfigs/docusign)\r\nallow\ jcr\:read\ on\ /conf\ restriction(rep\:glob,/*/cloudconfigs/docusign/*)\r\nend"] 3 | -------------------------------------------------------------------------------- /ui.config/src/main/content/jcr_root/apps/docusign/osgiconfig/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended-docusign.config: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Adobe 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | user.mapping=["forms.integration.docusign.core\=[forms-docusign-sample-service-user]"] -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/configurations/clientlib/js.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright 2021 Adobe 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. 15 | ############################################################################### 16 | #base=js 17 | docusign.js -------------------------------------------------------------------------------- /core/src/main/java/com/adobe/aemforms/samples/forms/integration/docusign/core/package-info.java: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | 17 | @Version("1.0.0") 18 | package com.adobe.aemforms.samples.forms.integration.docusign.core; 19 | 20 | import org.osgi.annotation.versioning.Version; -------------------------------------------------------------------------------- /all/src/main/content/META-INF/vault/filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/META-INF/vault/filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/cq/core/content/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/cloudservices/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/content/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/content/docusign/createcloudconfigwizard/commons/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/configurations/clientlib/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/content/docusign/createcloudconfigwizard/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /all/src/main/content/META-INF/vault/definition/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 23 | 24 | -------------------------------------------------------------------------------- /documentation/FORM_SUBMISSION_SETUP.md: -------------------------------------------------------------------------------- 1 | # FORM SUBMISSION SETUP 2 | 3 | ## Requirements 4 | * During form creation, add the Configuration Container where DocuSign configuration is being created. 5 | * Form should generate Document of Record. 6 | 7 | ## Configure an Adaptive Form to use DocuSign submit action 8 | + Create/Edit an Adaptive Form. 9 | ![Create-Form](./images/form/form-1.PNG) 10 | ![Form-Properties](./images/form/form-2.PNG) 11 | 12 | + **Configuration Container**: Select the container in which you created DocuSign Cloud Configuration. 13 | ![Form-Properties](./images/form/form-3.PNG) 14 | 15 | + **Document of Record Template Configuration**: Document of Record generation is mandatory. 16 | ![Form-Properties](./images/form/form-4.PNG) 17 | 18 | + Navigate to **Submission** Tab in Form Container. 19 | ![Submission](./images/form/form-5.PNG) 20 | 21 | + Select DocuSign Custom Submit Action - **Submit with DocuSign electronic signatures**. 22 | ![Submit-Action](./images/form/form-6.PNG) 23 | 24 | + Add **Recipients** and **Email Subject**.. **Include Attachments** as per requirement. 25 | ![Action-Configurations](./images/form/form-7.PNG) 26 | 27 | + After Form submission, Recipients will get this **Email** to sign the Document of Record. 28 | ![Email](./images/form/form-8.PNG) -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/content/docusign/createcloudconfigwizard/commons/columnpreview/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/submit/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 23 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/configurations/meta/meta.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/cq/core/content/nav/tools/cloudservices/docusignlaunch/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 23 | 24 | -------------------------------------------------------------------------------- /documentation/DOCUSIGN_CLOUDSERVICE_SETUP.md: -------------------------------------------------------------------------------- 1 | # DocuSign CloudService Setup 2 | 3 | ## Prerequisites 4 | * AEM FORMS as a Cloud Service 5 | * DocuSign Developer Account and Application 6 | 7 | ## Steps to Configure 8 | + Navigate to **Tools -> Cloud Services -> DocuSign** 9 | ![Cloud-Config](./images/cloudservice/cloudservice-1.PNG) 10 | 11 | + Create a new Cloud Service configuration. 12 | ![Create-Config](./images/cloudservice/cloudservice-2.PNG) 13 | 14 | + Enter the required details. 15 | + **Title**: Title of your configuration e.g. Forms Integration DocuSign 16 | + **Name**: Name of your configuration same as Title,automatically populated e.g. Forms Integration DocuSign 17 | ![Config-Fields](./images/cloudservice/cloudservice-3.PNG) 18 | 19 | + **OAuth Endpoint Host**: The OAuth Endpoint - https://account-d.docusign.com/oauth/auth 20 | + **Client ID**: Your DocuSign OAuth App Client ID. 21 | + **Client Secret**: Your DocuSign OAuth App Client Secret. 22 | + Click on **Connect to DocuSign** button (will be enabled on adding client secret) - This would establish connectivity between AEM and DocuSign using provided integration credentials. 23 | ![Docusign-Connect](./images/cloudservice/cloudservice-4.PNG) 24 | 25 | + You will be directed to **DocuSign Authentication**. After providing Username and Password you will be redirected to Redirect URL provided in DocuSign Application. 26 | ![DocuSign-Authentication](./images/cloudservice/cloudservice-5.PNG) 27 | 28 | + Message will indicate the status of Connection to DocuSign. 29 | ![Connection-Status](./images/cloudservice/cloudservice-6.PNG) 30 | 31 | + Click on create the configuration. 32 | ![Save-Config](./images/cloudservice/cloudservice-7.PNG) 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/eclipse,java,maven 2 | 3 | ### Eclipse ### 4 | *.pydevproject 5 | .metadata 6 | .gradle 7 | bin/ 8 | tmp/ 9 | *.tmp 10 | *.bak 11 | *.swp 12 | *~.nib 13 | local.properties 14 | .settings/ 15 | .loadpath 16 | 17 | # Eclipse Core 18 | .project 19 | 20 | # External tool builders 21 | .externalToolBuilders/ 22 | 23 | # Locally stored "Eclipse launch configurations" 24 | *.launch 25 | 26 | # CDT-specific 27 | .cproject 28 | 29 | # JDT-specific (Eclipse Java Development Tools) 30 | .classpath 31 | 32 | # Java annotation processor (APT) 33 | .factorypath 34 | 35 | # PDT-specific 36 | .buildpath 37 | 38 | # sbteclipse plugin 39 | .target 40 | 41 | # TeXlipse plugin 42 | .texlipse 43 | 44 | 45 | ### Java ### 46 | *.class 47 | 48 | # Mobile Tools for Java (J2ME) 49 | .mtj.tmp/ 50 | 51 | # Package Files # 52 | *.jar 53 | *.war 54 | *.ear 55 | 56 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 57 | hs_err_pid* 58 | 59 | 60 | ### Maven ### 61 | target/ 62 | pom.xml.tag 63 | pom.xml.releaseBackup 64 | pom.xml.versionsBackup 65 | pom.xml.next 66 | release.properties 67 | dependency-reduced-pom.xml 68 | buildNumber.properties 69 | .mvn/timing.properties 70 | 71 | 72 | ### Vault ### 73 | .vlt 74 | 75 | 76 | ### IntelliJ ### 77 | .idea/ 78 | *.iml 79 | 80 | 81 | ### Node.js ### 82 | 83 | # Log files 84 | *.log 85 | 86 | # NPM 87 | node_modules/ 88 | yarn.lock 89 | 90 | # Webpack 91 | build/ 92 | dist/ 93 | actions/common/ 94 | 95 | # Frontend Maven Plugin 96 | node/ 97 | 98 | # Tests 99 | coverage/ 100 | reports/ 101 | 102 | # Others 103 | dispatcher/src/conf.d/variables/default.vars 104 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | 7 | ## Related Issue 8 | 9 | 10 | 11 | 12 | 13 | 14 | ## Motivation and Context 15 | 16 | 17 | 18 | ## How Has This Been Tested? 19 | 20 | 21 | 22 | 23 | 24 | ## Screenshots (if appropriate): 25 | 26 | ## Types of changes 27 | 28 | 29 | 30 | - [ ] Bug fix (non-breaking change which fixes an issue) 31 | - [ ] New feature (non-breaking change which adds functionality) 32 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 33 | 34 | ## Checklist: 35 | 36 | 37 | 38 | 39 | - [ ] I have signed the [Adobe Open Source CLA](http://opensource.adobe.com/cla.html). 40 | - [ ] My change requires a change to the documentation. 41 | - [ ] I have updated the documentation accordingly. 42 | - [ ] I have read the **CONTRIBUTING** document. 43 | -------------------------------------------------------------------------------- /core/src/main/java/com/adobe/aemforms/samples/forms/integration/docusign/core/utils/Constants.java: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | package com.adobe.aemforms.samples.forms.integration.docusign.core.utils; 17 | 18 | public class Constants { 19 | public static final String CONF_ROOT = "/conf"; 20 | public static final String CONFIG_BUCKET= "settings/"; 21 | public static final String CONF_CONTAINER_BUCKET_NAME= "settings"; 22 | public static final String CLOUD_CONFIGURATION_CONTAINER = "cloudconfigs"; 23 | public static final String CLOUDCONFIG_BUCKET_PATH = CONFIG_BUCKET + CLOUD_CONFIGURATION_CONTAINER; 24 | public static final String DOCUSIGN_CONFIGURATION_GROUP = CLOUD_CONFIGURATION_CONTAINER + "/docusign/docusign"; 25 | 26 | public static final String AUTHORIZATION_CODE = "authorization_code"; 27 | public static final String CLIENT_ID = "client_id"; 28 | public static final String CLIENT_SECRET = "client_secret"; 29 | public static final String GRANT_TYPE = "grant_type"; 30 | public static final String REDIRECT_URI = "redirect_uri"; 31 | public static final String CODE = "code"; 32 | public static final String REFRESH_TOKEN_URI = "refresh_token_uri"; 33 | 34 | public static final String ACCESS_TOKEN = "access_token"; 35 | public static final String REFRESH_TOKEN = "refresh_token"; 36 | 37 | public static final String ERROR = "error"; 38 | public static final String ERROR_DESCRIPTION = "error_description"; 39 | } 40 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/configurations/views/row/row.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | ${configuration.title} 27 | 29 | 30 | 32 | ${modified.date} 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/configurations/views/column/column.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | ${configuration.title} 29 |
30 |
31 | 32 | 33 | 34 |
35 | 36 |
-------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/submit/post.POST.jsp: -------------------------------------------------------------------------------- 1 | 16 | 17 | <%@include file="/libs/fd/af/components/guidesglobal.jsp" %> 18 | <%@page import="com.adobe.aemds.guide.model.FormSubmitInfo, 19 | com.adobe.aemds.guide.service.FormSubmitActionManagerService" %> 20 | <%@ page import="com.adobe.aemds.guide.utils.GuideSubmitUtils" %> 21 | <%@ page import="java.util.HashMap" %> 22 | <%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0" %> 23 | <%@taglib prefix="cq" uri="http://www.day.com/taglibs/cq/1.0" %> 24 | 25 | <% 26 | Map redirectParameters; 27 | redirectParameters = GuideSubmitUtils.getRedirectParameters(slingRequest); 28 | if(redirectParameters == null) { 29 | redirectParameters = new HashMap(); 30 | } 31 | 32 | FormSubmitActionManagerService submitActionServiceManager = sling.getService(FormSubmitActionManagerService.class); 33 | FormSubmitInfo submitInfo = (FormSubmitInfo) request.getAttribute(GuideConstants.FORM_SUBMIT_INFO); 34 | Map resultMap = submitActionServiceManager.submit(submitInfo, Boolean.FALSE); 35 | GuideSubmitUtils.handleValidationError(request, response, resultMap); 36 | if (response.getStatus() == response.SC_OK) { 37 | if (resultMap != null) { 38 | for (Map.Entry stringObjectEntry : resultMap.entrySet()) { 39 | if (!GuideConstants.FORM_SUBMISSION_COMPLETE.equals(stringObjectEntry.getKey())) { 40 | if(stringObjectEntry.getValue() != null) { 41 | redirectParameters.put(stringObjectEntry.getKey(), stringObjectEntry.getValue().toString()); 42 | } 43 | } 44 | } 45 | } 46 | GuideSubmitUtils.setRedirectParameters(slingRequest,redirectParameters); 47 | } 48 | %> 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AEM Forms DocuSign Sample 2 | 3 | DocuSign service allows electronic signatures and approvals. Using this sample one can integrate with DocuSign service to sign the Document of Record (DoR) generated by AEM Forms. 4 | 5 | In this Sample we are providing following capabilities: 6 | + **DOCUSIGN CLOUD CONFIGURATION**: A specific cloud configuration is provided in AEM for DocuSign OAuth 2.O Authentication with the Authorization Code Grant. 7 | + **CUSTUM SUBMIT ACTION**: New custom submit action is implemented using which one can create DocuSign Envelope using Submit Action Configurations and DoR. This Envelope is sent as Email to Recipients configured. 8 | 9 | You can do various customization in this sample using AEM Form Submit Information and DocuSign APIs as per your requirement. 10 | ## Modules 11 | 12 | The main parts of the template are: 13 | 14 | * core: Java bundle containing all core functionality like OSGi services, Utilities, as well as component-related Java code such as servlets. 15 | * ui.apps: contains the /apps parts of the project, ie JS&CSS clientlibs, components, and templates 16 | * ui.config: contains OSGi configs for the project 17 | * all: a single content package that embeds all of the compiled modules (bundles and content packages) including any vendor dependencies 18 | 19 | ## How to build 20 | 21 | To build all the modules run in the project root directory the following command with Maven 3: 22 | 23 | mvn clean install 24 | 25 | To build all the modules and deploy the `all` package to a local instance of AEM, run in the project root directory the following command: 26 | 27 | mvn clean install -PautoInstallSinglePackage 28 | 29 | Or to deploy it to a publish instance, run 30 | 31 | mvn clean install -PautoInstallSinglePackagePublish 32 | 33 | Or alternatively 34 | 35 | mvn clean install -PautoInstallSinglePackage -Daem.port=4503 36 | 37 | Or to deploy only the bundle to the author, run 38 | 39 | mvn clean install -PautoInstallBundle 40 | 41 | Or to deploy only a single content package, run in the sub-module directory (i.e `ui.apps`) 42 | 43 | mvn clean install -PautoInstallPackage 44 | 45 | 46 | The configuration provides sensible defaults for a typical local installation of 47 | AEM. If you want to point to different AEM author and publish instances, you can use the following system properties via Maven's `-D` 48 | flag. 49 | 50 | | Property | Description | Default value | 51 | | --- | --- | --- | 52 | | `aem.host` | Host name of the author instance | `localhost` | 53 | | `aem.port` | Port of the author instance | `4502` | 54 | | `aem.publish.host` | Host name of the publish instance | `localhost` | 55 | | `aem.publish.port` | Port of the publish instance | `4503` | 56 | | `vault.user` | Admin user for the author/publish instance | `admin` | 57 | | `vault.password` | Password of the admin user for the author/publish instance | `admin` | 58 | 59 | ### How to use 60 | 61 | Steps to use this sample are defined in [Documentation](documentation) 62 | 63 | ### Licensing 64 | 65 | This project is licensed under the Apache V2 License. See [LICENSE](LICENSE) for more information. 66 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/submit/_cq_dialog/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 22 | 27 | 28 | 35 | 41 | 44 | 45 | 46 | 52 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /core/src/main/java/com/adobe/aemforms/samples/forms/integration/docusign/core/UIConfigHelper.java: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | 17 | package com.adobe.aemforms.samples.forms.integration.docusign.core; 18 | 19 | import java.util.Calendar; 20 | import java.util.Set; 21 | import org.osgi.annotation.versioning.ProviderType; 22 | 23 | import javax.annotation.Nonnull; 24 | import javax.annotation.Nullable; 25 | 26 | 27 | /** 28 | * Represents helper methods for cloud services. 29 | */ 30 | @ProviderType 31 | public interface UIConfigHelper { 32 | 33 | /** 34 | * Returns if currently addressed resource is a folder. 35 | * 36 | * @return {@code true} if currently addressed resource is folder, 37 | * {@code false} otherwise 38 | */ 39 | Boolean isFolder(); 40 | 41 | /** 42 | * Returns the title of the currently addressed resource. 43 | *

44 | * If the resource does not have a {@code ./content/jcr:title} property 45 | * either the {@code ./jcr:title} property or the name of the resource is 46 | * returned. 47 | *

48 | * 49 | * @return title or name of the currently addressed resource 50 | */ 51 | String getTitle(); 52 | 53 | /** 54 | * Returns a set of action relations which apply to the currently addressed 55 | * resource. 56 | * 57 | * @return A set of relation identifiers 58 | */ 59 | Set getActionsRels(); 60 | 61 | /** 62 | * Indicates if item has children. 63 | * 64 | * @return {@code true} if item has children 65 | */ 66 | @Nonnull 67 | boolean hasChildren(); 68 | 69 | /** 70 | * Returns the last modified time stamp. 71 | * 72 | * @return Last modified time in milliseconds or {@code null} 73 | */ 74 | @Nullable 75 | Calendar getLastModifiedDate(); 76 | 77 | /** 78 | * Returns the user which last modified the item 79 | * 80 | * @return User identifier or {@code null} 81 | */ 82 | @Nullable 83 | String getLastModifiedBy(); 84 | 85 | /** 86 | * Returns a list of quickactions rel identifiers for that item. 87 | * 88 | * @return List of quickactions rel identifiers or an empty list 89 | */ 90 | @Nonnull 91 | Set getQuickactionsRels(); 92 | 93 | /** 94 | * Returns a formatted date according to the injected formats. 95 | * 96 | * @return Formatted date 97 | */ 98 | @Nonnull 99 | String getDate(); 100 | 101 | } 102 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Adobe Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at Grp-opensourceoffice@adobe.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/configurations/views/card/card.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | ${'Folder' @ i18n, locale=request.locale} 25 | ${configuration.title} 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | ${'DocuSign Cloud Configuration Setting' @ i18n, locale=request.locale} 40 | ${configuration.title} 41 | 42 | 43 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ${'Select' @ i18n, locale=request.locale} 55 | 56 | 57 | -------------------------------------------------------------------------------- /core/src/main/java/com/adobe/aemforms/samples/forms/integration/docusign/core/models/CloudConfigSlingModel.java: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | package com.adobe.aemforms.samples.forms.integration.docusign.core.models; 17 | 18 | import org.apache.sling.api.resource.Resource; 19 | import org.apache.sling.models.annotations.Model; 20 | import org.apache.sling.models.annotations.DefaultInjectionStrategy; 21 | import org.apache.sling.models.annotations.injectorspecific.Self; 22 | 23 | import javax.inject.Inject; 24 | import javax.inject.Named; 25 | 26 | /** 27 | * Sling model class for DocuSign cloud configuration. 28 | */ 29 | @Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL) 30 | public class CloudConfigSlingModel { 31 | 32 | @Self 33 | private Resource resource; 34 | 35 | @Inject @Named("base_uri") 36 | private String restBasepathUri; 37 | 38 | @Inject @Named("client_id") 39 | private String clientId; 40 | 41 | @Inject @Named("client_secret") 42 | private String clientSecret; 43 | 44 | @Inject @Named("account_id") 45 | private String accountId; 46 | 47 | @Inject @Named("access_token") 48 | private String accessToken; 49 | 50 | @Inject @Named("refresh_token") 51 | private String refreshToken; 52 | 53 | @Inject @Named("refresh_token_uri") 54 | private String refreshTokenUri; 55 | 56 | 57 | public String getRestBasepathUri() { 58 | return restBasepathUri; 59 | } 60 | 61 | public void setRestBasepathUri(String restBasepathUri) { 62 | this.restBasepathUri = restBasepathUri; 63 | } 64 | 65 | public String getClientId() { 66 | return clientId; 67 | } 68 | 69 | public void setClientId(String clientId) { 70 | this.clientId = clientId; 71 | } 72 | 73 | public String getClientSecret() { 74 | return clientSecret; 75 | } 76 | 77 | public void setClientSecret(String clientSecret) { 78 | this.clientSecret = clientSecret; 79 | } 80 | 81 | public String getAccountId() { 82 | return accountId; 83 | } 84 | 85 | public void setAccountId(String accountId) { 86 | this.accountId = accountId; 87 | } 88 | 89 | public String getAccessToken() { 90 | return accessToken; 91 | } 92 | 93 | public void setAccessToken(String accessToken) { 94 | this.accessToken = accessToken; 95 | } 96 | 97 | public String getRefreshToken() { 98 | return refreshToken; 99 | } 100 | 101 | public void setRefreshToken(String refreshToken) { 102 | this.refreshToken = refreshToken; 103 | } 104 | 105 | public String getRefreshTokenUri() { 106 | return refreshTokenUri; 107 | } 108 | 109 | public void setRefreshTokenUri(String refreshTokenUri) { 110 | this.refreshTokenUri = refreshTokenUri; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/configurations/views/columnpreview/columnpreview.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ${"Title" @ i18n, locale=request.locale} 25 | ${configuration.title}  26 | ${"Name" @ i18n, locale=request.locale} 27 | ${request.requestPathInfo.suffixResource.name}  28 | ${"Modified" @ i18n, locale=request.locale} 29 | 32 | ${modified.date}  33 | 34 | ${"Modified By" @ i18n, locale=request.locale} 35 | ${configuration.lastModifiedBy}  36 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /ui.apps.structure/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | 21 | 22 | 23 | 24 | com.adobe.aemforms.samples 25 | forms.integration.docusign 26 | 1.0.0 27 | ../pom.xml 28 | 29 | 30 | 31 | 32 | 33 | forms.integration.docusign.ui.apps.structure 34 | content-package 35 | DocuSign Integration - Repository Structure Package 36 | UI apps structure package for AEM Forms DocuSign Sample 37 | 38 | 39 | 40 | 41 | org.apache.jackrabbit 42 | filevault-package-maven-plugin 43 | 44 | 45 | none 46 | 47 | 48 | 49 | /apps 50 | /apps/docusign 51 | 52 | 53 | /apps/cq 54 | /apps/cq/core 55 | /apps/cq/core/content 56 | /apps/cq/core/content/nav 57 | /apps/cq/core/content/nav/tools 58 | /apps/cq/core/content/nav/tools/cloudservices 59 | 60 | 61 | /apps/settings 62 | 63 | 64 | /content/dam/docusign 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /core/src/main/java/com/adobe/aemforms/samples/forms/integration/docusign/core/servlet/OAuthServlet.java: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | package com.adobe.aemforms.samples.forms.integration.docusign.core.servlet; 17 | 18 | import com.adobe.aemforms.samples.forms.integration.docusign.core.utils.Constants; 19 | import com.adobe.aemforms.samples.forms.integration.docusign.core.utils.CloudConfigurationUtils; 20 | import com.google.gson.JsonObject; 21 | import org.apache.http.osgi.services.HttpClientBuilderFactory; 22 | import org.apache.sling.api.SlingHttpServletRequest; 23 | import org.apache.sling.api.SlingHttpServletResponse; 24 | import org.apache.sling.api.servlets.SlingSafeMethodsServlet; 25 | import org.osgi.service.component.annotations.Component; 26 | import org.osgi.service.component.annotations.Reference; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | import javax.servlet.Servlet; 31 | import javax.servlet.http.HttpServletResponse; 32 | import java.io.PrintWriter; 33 | 34 | @Component( 35 | service = { Servlet.class }, 36 | property = { 37 | "sling.servlet.extensions=json", 38 | "sling.servlet.resourceTypes=docusign/cloudconfig/oauthservlet", 39 | "sling.servlet.methods=GET" 40 | } 41 | ) 42 | public class OAuthServlet extends SlingSafeMethodsServlet { 43 | 44 | @Reference 45 | private HttpClientBuilderFactory httpClientBuilderFactory; 46 | 47 | private Logger logger = LoggerFactory.getLogger(OAuthServlet.class); 48 | 49 | @Override 50 | protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) { 51 | String authorization_code = request.getParameter(Constants.CODE); 52 | String clientId = request.getParameter(Constants.CLIENT_ID); 53 | String clientSecret = request.getParameter(Constants.CLIENT_SECRET); 54 | String redirectUri = request.getParameter(Constants.REDIRECT_URI); 55 | String refreshTokenUri = request.getParameter(Constants.REFRESH_TOKEN_URI); 56 | 57 | JsonObject jsonResponse = CloudConfigurationUtils.fetchRefreshToken(httpClientBuilderFactory, authorization_code, clientId, clientSecret, refreshTokenUri, redirectUri, null); 58 | 59 | try { 60 | response.setContentType("application/json"); 61 | response.setCharacterEncoding("utf-8"); 62 | PrintWriter writer = response.getWriter(); 63 | writer.write(jsonResponse.toString()); 64 | } 65 | catch (Exception e) { 66 | try { 67 | response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 68 | PrintWriter writer = response.getWriter(); 69 | JsonObject errorJson = new JsonObject(); 70 | String code = e.getMessage(); 71 | errorJson.addProperty(Constants.ERROR, code); 72 | logger.error("[OAuth] [DocuSign]" + errorJson.toString(),e); 73 | writer.write(errorJson.toString()); 74 | } catch (Exception ex) { 75 | logger.error("[OAuth] [DocuSign] Error while writing json object.", ex); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ui.config/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 4.0.0 19 | 20 | 21 | 22 | 23 | 24 | com.adobe.aemforms.samples 25 | forms.integration.docusign 26 | 1.0.0 27 | ../pom.xml 28 | 29 | 30 | 31 | 32 | 33 | forms.integration.docusign.ui.config 34 | content-package 35 | DocuSign Integration - UI config 36 | UI config package for AEM Forms DocuSign Sample 37 | 38 | 39 | 40 | 41 | 42 | src/main/content/jcr_root 43 | 44 | 45 | 46 | org.apache.jackrabbit 47 | filevault-package-maven-plugin 48 | 49 | 50 | none 51 | 52 | container 53 | false 54 | 55 | 56 | com.adobe.aemforms.samples 57 | forms.integration.docusign.ui.apps.structure 58 | 59 | 60 | 61 | 62 | 63 | com.day.jcr.vault 64 | content-package-maven-plugin 65 | 66 | 67 | 68 | 69 | 70 | 71 | com.adobe.aemforms.samples 72 | forms.integration.docusign.ui.apps.structure 73 | ${project.version} 74 | zip 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for choosing to contribute! 4 | 5 | The following are a set of guidelines to follow when contributing to this project. 6 | 7 | ## Code Of Conduct 8 | 9 | This project adheres to the Adobe [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to the team. 10 | 11 | ## Contributor License Agreement 12 | 13 | All third-party contributions to this project must be accompanied by a signed contributor license agreement. This gives Adobe permission to redistribute your contributions as part of the project. [Sign our CLA](http://opensource.adobe.com/cla.html). You only need to submit an Adobe CLA one time, so if you have submitted one previously, you are good to go! 14 | 15 | ## How to contribute 16 | 17 | New code contributions should be made primarily using GitHub pull requests. This involves creating a fork of the project in your personal space, adding your new code in a branch and triggering a pull request. 18 | 19 | See how to perform pull requests at https://help.github.com/articles/using-pull-requests. 20 | 21 | Please follow the [pull request template](PULL_REQUEST_TEMPLATE.md) when submitting a pull request! 22 | 23 | To ease the review process of pull requests, we ask you to please follow a number of guidelines and recommendations. This will speed up the review process and ensure that a pull request does not break any existing functionality. 24 | * **Keep it small!** Reviewing a large pull request is very difficult and time consuming. Try to keep your contribution small, maybe to a maximum of a dozen files with maximum a few hundred lines of code in total. Do not combine multiple new features or bug fixes into one single pull request: if one PR needs another one, simply create multiple PRs, and open "nested PRs" that depend on each other. 25 | * **Do not remove tests!** If your feature breaks a test, do NOT remove that test, unless there is a very good reason that the test is no longer needed. If there is a test for something, there is usually a good reason for that. If you break a test, make sure that you fix the test, but make sure that the original feature still does what it is expected to do! 26 | * **Add your own tests!**: We will not consider pull requests that do not include a minimum of 80% test coverage. Make sure that your tests follow the same design and format than similar tests, and be consistent with our existing tests. 27 | * **Do not "pollute" your pull request!**: Avoid unneeded changes in your pull request, for example, code formatting changes or changes not related to your feature or bug fix. Make sure that your IDE is configured to **not** reformat the entire files you are editing, but only the lines you change. This will ensure that different formatting rules will not affect code that you do not change! 28 | * **Follow master!**: Make sure that your pull request is up-to-date with respect to our `master` branch. It is your responsibility to ensure that the latest commits in our `master` branch are always merged into your code, and that merge conflicts are resolved. Please make sure that your pull request follows our recommendations, in order to speed up the review process and hopefully reduce the number of times you will have to merge our latest changes into your branch. 29 | * **Format your code!**: Our maven build can automatically format java files, make sure you do that. For other file formats like `.js`, `.xml` and `.html`, make sure that you use a 4-space indentation, do not use tabs. For `.json` files, we use a 2-space indentation. 30 | * **Use common sense!**: Use common sense to increase the quality of your contribution. Do not duplicate code, use constants instead of hard-coded strings where appropriate, add javadoc documentation, use comments (sparingly!) where the code could be difficult to understand, and keep in mind that the Forms components can be reused and extended by others so make sure the code is readable and follows the latest AEM development guidelines. 31 | 32 | 33 | ## Issues 34 | 35 | Please follow the [issue template](ISSUE_TEMPLATE/BUG_REPORT.md) to open new issues and join the conversations to provide feedback. 36 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/content/docusign/properties/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 27 | 28 | 32 | 33 | 37 | <content 38 | granite:id="docusign-properties-form" 39 | jcr:primaryType="nt:unstructured" 40 | sling:resourceType="cq/gui/components/siteadmin/admin/properties/form" 41 | foundationForm="{Boolean}true" 42 | maximized="{Boolean}true" 43 | novalidate="{Boolean}false" 44 | path="${param.item}" 45 | style="vertical"> 46 | <items jcr:primaryType="nt:unstructured"> 47 | <tabs 48 | jcr:primaryType="nt:unstructured" 49 | sling:resourceType="granite/ui/components/coral/foundation/tabs" 50 | maximized="{Boolean}true" 51 | size="L"> 52 | <items jcr:primaryType="nt:unstructured"> 53 | <general 54 | jcr:primaryType="nt:unstructured" 55 | sling:resourceType="granite/ui/components/coral/foundation/include" 56 | path="docusign/cloudConfig/content/docusign/createcloudconfigwizard/cloudservices/jcr:content/body/items/form/items/wizard/items/general" 57 | resourceType="granite/ui/components/coral/foundation/fixedcolumns"/> 58 | <servicesettings 59 | jcr:primaryType="nt:unstructured" 60 | sling:resourceType="granite/ui/components/coral/foundation/include" 61 | path="docusign/cloudConfig/content/docusign/createcloudconfigwizard/cloudservices/jcr:content/body/items/form/items/wizard/items/settings" 62 | resourceType="granite/ui/components/coral/foundation/fixedcolumns"/> 63 | </items> 64 | </tabs> 65 | <commondialog 66 | jcr:primaryType="nt:unstructured" 67 | sling:resourceType="granite/ui/components/coral/foundation/include" 68 | path="docusign/cloudConfig/content/docusign/createcloudconfigwizard/cloudservices/jcr:content/body/items/form/items/commondialog"/> 69 | </items> 70 | </content> 71 | </jcr:content> 72 | </jcr:root> 73 | -------------------------------------------------------------------------------- /core/src/main/java/com/adobe/aemforms/samples/forms/integration/docusign/core/models/UIConfigHelperImpl.java: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | 17 | package com.adobe.aemforms.samples.forms.integration.docusign.core.models; 18 | 19 | import com.adobe.aemforms.samples.forms.integration.docusign.core.UIConfigHelper; 20 | import com.adobe.aemforms.samples.forms.integration.docusign.core.utils.CloudConfigurationUtils; 21 | import com.day.cq.commons.jcr.JcrConstants; 22 | import com.day.cq.wcm.api.Page; 23 | import org.apache.sling.api.SlingHttpServletRequest; 24 | import org.apache.sling.api.resource.Resource; 25 | import org.apache.sling.api.resource.ResourceResolver; 26 | import org.apache.sling.api.resource.ValueMap; 27 | import org.apache.sling.models.annotations.DefaultInjectionStrategy; 28 | import org.apache.sling.models.annotations.Model; 29 | import org.apache.sling.models.annotations.injectorspecific.InjectionStrategy; 30 | import org.apache.sling.models.annotations.injectorspecific.RequestAttribute; 31 | import org.apache.sling.models.annotations.injectorspecific.Self; 32 | import org.apache.sling.models.annotations.injectorspecific.SlingObject; 33 | import com.adobe.aemforms.samples.forms.integration.docusign.core.utils.Constants; 34 | import javax.annotation.PostConstruct; 35 | import java.text.SimpleDateFormat; 36 | import java.util.Calendar; 37 | import java.util.LinkedHashSet; 38 | import java.util.Set; 39 | 40 | @Model( 41 | adaptables = { 42 | SlingHttpServletRequest.class 43 | }, 44 | adapters = { 45 | UIConfigHelper.class 46 | }, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL 47 | ) 48 | public class UIConfigHelperImpl implements UIConfigHelper { 49 | 50 | @Self 51 | private SlingHttpServletRequest request; 52 | 53 | @SlingObject 54 | private ResourceResolver resourceResolver; 55 | 56 | @SlingObject 57 | private Resource resource; 58 | 59 | @RequestAttribute 60 | private Resource useResource; 61 | 62 | @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) 63 | private Calendar date; 64 | 65 | @RequestAttribute(injectionStrategy = InjectionStrategy.OPTIONAL) 66 | private String dateFormat; 67 | 68 | public String dateFormattedValue = ""; 69 | 70 | @PostConstruct 71 | protected void postConstruct() { 72 | if (date != null) { 73 | SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); 74 | try { 75 | sdf = new SimpleDateFormat(dateFormat, request.getLocale()); 76 | dateFormattedValue = sdf.format(date.getTime()); 77 | } catch (Exception e) { 78 | dateFormattedValue = sdf.format(date.getTime()); 79 | } 80 | } 81 | } 82 | 83 | public Boolean isFolder() { 84 | return CloudConfigurationUtils.isResourceType(getResource(), "nt:folder", "sling:Folder", "sling:OrderedFolder"); 85 | } 86 | 87 | public String getTitle() { 88 | return getResource().getValueMap().get("jcr:content/jcr:title", getResource().getValueMap().get("jcr:title", getResource().getName())); 89 | } 90 | 91 | public Set<String> getActionsRels() { 92 | Set<String> actions = new LinkedHashSet<String>(); 93 | 94 | boolean isRoot = Constants.CONF_ROOT.equals(getResource().getPath()); 95 | boolean hasCapability = getResource().getChild(Constants.CLOUDCONFIG_BUCKET_PATH) != null; 96 | 97 | // allow setting 98 | // - if parent is not root 99 | // - if has Cloud Services capability 100 | // - if setting does not exist yet 101 | // - if permissions allow adding child nodes 102 | if (getResource() != null && 103 | !isRoot && hasCapability) { 104 | actions.add("cq-confadmin-actions-createconfig-activator"); 105 | } 106 | 107 | return actions; 108 | } 109 | 110 | public boolean hasChildren() { 111 | if (getResource().hasChildren()) { 112 | for (Resource child : getResource().getChildren()) { 113 | boolean isContainer = CloudConfigurationUtils.isConfigurationContainer(child); 114 | boolean hasSetting = CloudConfigurationUtils.hasConfigBucket(child, Constants.CLOUD_CONFIGURATION_CONTAINER); 115 | if (isContainer || hasSetting) { 116 | return true; 117 | } 118 | } 119 | } 120 | return false; 121 | } 122 | 123 | public Calendar getLastModifiedDate() { 124 | Page page = getResource().adaptTo(Page.class); 125 | if (page != null) { 126 | return page.getLastModified(); 127 | } 128 | ValueMap props = getResource().adaptTo(ValueMap.class); 129 | if (props != null) { 130 | return props.get(JcrConstants.JCR_LASTMODIFIED, Calendar.class); 131 | } 132 | return null; 133 | } 134 | 135 | public String getLastModifiedBy() { 136 | Page page = getResource().adaptTo(Page.class); 137 | if (page != null) { 138 | return page.getLastModifiedBy(); 139 | } 140 | ValueMap props = getResource().adaptTo(ValueMap.class); 141 | if (props != null) { 142 | return props.get(JcrConstants.JCR_LAST_MODIFIED_BY, String.class); 143 | } 144 | return null; 145 | } 146 | 147 | public Set<String> getQuickactionsRels() { 148 | Set<String> quickactions = new LinkedHashSet<String>(); 149 | 150 | if (CloudConfigurationUtils.isCloudConfiguration(getResource())) { 151 | if (CloudConfigurationUtils.hasPermission(resourceResolver, getResource().getPath(), "crx:replicate")) { 152 | quickactions.add("cq-confadmin-actions-publish-activator"); 153 | quickactions.add("cq-confadmin-actions-unpublish-activator"); 154 | } 155 | quickactions.add("cq-confadmin-actions-properties-activator"); 156 | } 157 | 158 | return quickactions; 159 | } 160 | 161 | @Override 162 | public String getDate() { 163 | return dateFormattedValue; 164 | } 165 | 166 | private Resource getResource() { 167 | if (useResource != null) { 168 | return useResource; 169 | } 170 | return resource; 171 | } 172 | 173 | } 174 | -------------------------------------------------------------------------------- /ui.apps/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | ~ Copyright 2021 Adobe 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 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 18 | <modelVersion>4.0.0</modelVersion> 19 | 20 | <!-- ====================================================================== --> 21 | <!-- P A R E N T P R O J E C T D E S C R I P T I O N --> 22 | <!-- ====================================================================== --> 23 | <parent> 24 | <groupId>com.adobe.aemforms.samples</groupId> 25 | <artifactId>forms.integration.docusign</artifactId> 26 | <version>1.0.0</version> 27 | <relativePath>../pom.xml</relativePath> 28 | </parent> 29 | 30 | <!-- ====================================================================== --> 31 | <!-- P R O J E C T D E S C R I P T I O N --> 32 | <!-- ====================================================================== --> 33 | <artifactId>forms.integration.docusign.ui.apps</artifactId> 34 | <packaging>content-package</packaging> 35 | <name>DocuSign Integration - UI apps</name> 36 | <description>UI apps package for AEM Forms DocuSign Sample</description> 37 | 38 | <!-- ====================================================================== --> 39 | <!-- B U I L D D E F I N I T I O N --> 40 | <!-- ====================================================================== --> 41 | <build> 42 | <sourceDirectory>src/main/content/jcr_root</sourceDirectory> 43 | <plugins> 44 | <!-- ====================================================================== --> 45 | <!-- V A U L T P A C K A G E P L U G I N S --> 46 | <!-- ====================================================================== --> 47 | <plugin> 48 | <groupId>org.apache.jackrabbit</groupId> 49 | <artifactId>filevault-package-maven-plugin</artifactId> 50 | <configuration> 51 | <properties> 52 | <cloudManagerTarget>none</cloudManagerTarget> 53 | </properties> 54 | <group>com.adobe.aemforms.samples</group> 55 | <name>forms.integration.docusign.ui.apps</name> 56 | <packageType>application</packageType> 57 | <repositoryStructurePackages> 58 | <repositoryStructurePackage> 59 | <groupId>com.adobe.aemforms.samples</groupId> 60 | <artifactId>forms.integration.docusign.ui.apps.structure</artifactId> 61 | </repositoryStructurePackage> 62 | </repositoryStructurePackages> 63 | </configuration> 64 | </plugin> 65 | <plugin> 66 | <groupId>com.day.jcr.vault</groupId> 67 | <artifactId>content-package-maven-plugin</artifactId> 68 | <extensions>true</extensions> 69 | <configuration> 70 | <verbose>true</verbose> 71 | <failOnError>true</failOnError> 72 | </configuration> 73 | </plugin> 74 | 75 | <plugin> 76 | <groupId>org.apache.sling</groupId> 77 | <artifactId>htl-maven-plugin</artifactId> 78 | <executions> 79 | <execution> 80 | <id>validate-htl-scripts</id> 81 | <goals> 82 | <goal>validate</goal> 83 | </goals> 84 | <phase>generate-sources</phase> 85 | <configuration> 86 | <generateJavaClasses>true</generateJavaClasses> 87 | <generatedJavaClassesPrefix>org.apache.sling.scripting.sightly</generatedJavaClassesPrefix> 88 | <sourceDirectory>${project.build.sourceDirectory}</sourceDirectory> 89 | <allowedExpressionOptions> 90 | <allowedExpressionOption>cssClassName</allowedExpressionOption> 91 | <allowedExpressionOption>decoration</allowedExpressionOption> 92 | <allowedExpressionOption>decorationTagName</allowedExpressionOption> 93 | <allowedExpressionOption>wcmmode</allowedExpressionOption> 94 | </allowedExpressionOptions> 95 | </configuration> 96 | </execution> 97 | </executions> 98 | </plugin> 99 | </plugins> 100 | </build> 101 | 102 | <!-- ====================================================================== --> 103 | <!-- D E P E N D E N C I E S --> 104 | <!-- ====================================================================== --> 105 | <dependencies> 106 | <dependency> 107 | <groupId>com.adobe.aemforms.samples</groupId> 108 | <artifactId>forms.integration.docusign.core</artifactId> 109 | <version>${project.version}</version> 110 | </dependency> 111 | <dependency> 112 | <groupId>com.adobe.aemforms.samples</groupId> 113 | <artifactId>forms.integration.docusign.ui.apps.structure</artifactId> 114 | <version>${project.version}</version> 115 | <type>zip</type> 116 | </dependency> 117 | 118 | <dependency> 119 | <groupId>com.adobe.aem</groupId> 120 | <artifactId>aem-sdk-api</artifactId> 121 | </dependency> 122 | 123 | <!-- HTL dependencies needed for the HTL Maven Plugin source code generation --> 124 | <dependency> 125 | <groupId>org.apache.sling</groupId> 126 | <artifactId>org.apache.sling.scripting.sightly.runtime</artifactId> 127 | <version>1.2.4-1.4.0</version> 128 | <scope>provided</scope> 129 | </dependency> 130 | </dependencies> 131 | </project> 132 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | ~ Copyright 2021 Adobe 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 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 18 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 19 | <modelVersion>4.0.0</modelVersion> 20 | <parent> 21 | <groupId>com.adobe.aemforms.samples</groupId> 22 | <artifactId>forms.integration.docusign</artifactId> 23 | <version>1.0.0</version> 24 | <relativePath>../pom.xml</relativePath> 25 | </parent> 26 | <artifactId>forms.integration.docusign.core</artifactId> 27 | <name>DocuSign Integration - Core</name> 28 | <description>Core bundle for AEM Forms DocuSign Sample</description> 29 | <build> 30 | <plugins> 31 | <plugin> 32 | <groupId>org.apache.felix</groupId> 33 | <artifactId>maven-bundle-plugin</artifactId> 34 | <extensions>true</extensions> 35 | <executions> 36 | <execution> 37 | <id>scr-metadata</id> 38 | <goals> 39 | <goal>manifest</goal> 40 | </goals> 41 | <configuration> 42 | <supportIncrementalBuild>true</supportIncrementalBuild> 43 | </configuration> 44 | </execution> 45 | </executions> 46 | <configuration> 47 | <exportScr>true</exportScr> 48 | <instructions> 49 | <Bundle-SymbolicName>forms.integration.docusign.core</Bundle-SymbolicName> 50 | <!-- Enable registration of Sling Models classes via bnd plugin --> 51 | <_plugin>org.apache.sling.bnd.models.ModelsScannerPlugin</_plugin> 52 | <Import-Package> 53 | javax.annotation;version=0.0.0, 54 | javax.inject;version="[1.0.0,10.0.0)", 55 | * 56 | </Import-Package> 57 | <Export-Package> 58 | com.adobe.aemforms.samples.forms.integration.docusign.core 59 | </Export-Package> 60 | </instructions> 61 | </configuration> 62 | <dependencies> 63 | <dependency> 64 | <groupId>org.apache.sling</groupId> 65 | <artifactId>org.apache.sling.bnd.models</artifactId> 66 | <version>1.0.0</version> 67 | </dependency> 68 | </dependencies> 69 | </plugin> 70 | <plugin> 71 | <groupId>org.apache.sling</groupId> 72 | <artifactId>sling-maven-plugin</artifactId> 73 | </plugin> 74 | <plugin> 75 | <groupId>biz.aQute.bnd</groupId> 76 | <artifactId>bnd-maven-plugin</artifactId> 77 | <executions> 78 | <execution> 79 | <id>bnd-process</id> 80 | <goals> 81 | <goal>bnd-process</goal> 82 | </goals> 83 | <configuration> 84 | <bnd><![CDATA[ 85 | Import-Package: javax.annotation;version=0.0.0,* 86 | ]]></bnd> 87 | </configuration> 88 | </execution> 89 | </executions> 90 | </plugin> 91 | <plugin> 92 | <groupId>biz.aQute.bnd</groupId> 93 | <artifactId>bnd-baseline-maven-plugin</artifactId> 94 | <configuration> 95 | <failOnMissing>false</failOnMissing> 96 | </configuration> 97 | <executions> 98 | <execution> 99 | <id>baseline</id> 100 | <goals> 101 | <goal>baseline</goal> 102 | </goals> 103 | </execution> 104 | </executions> 105 | </plugin> 106 | <plugin> 107 | <groupId>org.apache.maven.plugins</groupId> 108 | <artifactId>maven-surefire-plugin</artifactId> 109 | </plugin> 110 | <plugin> 111 | <groupId>org.apache.maven.plugins</groupId> 112 | <artifactId>maven-jar-plugin</artifactId> 113 | <configuration> 114 | <archive> 115 | <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> 116 | </archive> 117 | </configuration> 118 | </plugin> 119 | </plugins> 120 | </build> 121 | 122 | <dependencies> 123 | <dependency> 124 | <groupId>org.osgi</groupId> 125 | <artifactId>org.osgi.service.component.annotations</artifactId> 126 | <version>1.4.0</version> 127 | </dependency> 128 | <dependency> 129 | <groupId>com.adobe.aem</groupId> 130 | <artifactId>aem-forms-sdk-api</artifactId> 131 | </dependency> 132 | <dependency> 133 | <groupId>com.adobe.aem</groupId> 134 | <artifactId>aem-sdk-api</artifactId> 135 | </dependency> 136 | <dependency> 137 | <groupId>org.apache.httpcomponents</groupId> 138 | <artifactId>httpclient-osgi</artifactId> 139 | <version>4.3.6</version> 140 | </dependency> 141 | <dependency> 142 | <groupId>org.apache.commons</groupId> 143 | <artifactId>commons-imaging</artifactId> 144 | <version>1.0-alpha2</version> 145 | </dependency> 146 | <dependency> 147 | <groupId>org.apache.sling</groupId> 148 | <artifactId>org.apache.sling.api</artifactId> 149 | <version>2.23.6</version> 150 | <scope>provided</scope> 151 | </dependency> 152 | <dependency> 153 | <groupId>org.slf4j</groupId> 154 | <artifactId>slf4j-api</artifactId> 155 | <version>1.7.6</version> 156 | </dependency> 157 | <dependency> 158 | <groupId>javax.servlet</groupId> 159 | <artifactId>servlet-api</artifactId> 160 | <version>2.5</version> 161 | <scope>provided</scope> 162 | </dependency> 163 | <dependency> 164 | <groupId>org.apache.commons</groupId> 165 | <artifactId>commons-io</artifactId> 166 | <version>1.3.2</version> 167 | </dependency> 168 | <dependency> 169 | <groupId>org.apache.commons</groupId> 170 | <artifactId>commons-lang3</artifactId> 171 | <version>3.12.0</version> 172 | </dependency> 173 | <dependency> 174 | <groupId>org.json</groupId> 175 | <artifactId>json</artifactId> 176 | <version>20090211</version> 177 | </dependency> 178 | <!-- https://mvnrepository.com/artifact/org.apache.sling/org.apache.sling.models.api --> 179 | <dependency> 180 | <groupId>org.apache.sling</groupId> 181 | <artifactId>org.apache.sling.models.api</artifactId> 182 | <version>1.3.8</version> 183 | <scope>provided</scope> 184 | </dependency> 185 | <!-- https://mvnrepository.com/artifact/javax.inject/javax.inject --> 186 | <dependency> 187 | <groupId>javax.inject</groupId> 188 | <artifactId>javax.inject</artifactId> 189 | <version>1</version> 190 | </dependency> 191 | <!-- https://mvnrepository.com/artifact/org.apache.sling/org.apache.sling.caconfig.api --> 192 | <dependency> 193 | <groupId>org.apache.sling</groupId> 194 | <artifactId>org.apache.sling.caconfig.api</artifactId> 195 | <version>1.2.0</version> 196 | </dependency> 197 | <!-- https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305 --> 198 | <dependency> 199 | <groupId>com.google.code.findbugs</groupId> 200 | <artifactId>jsr305</artifactId> 201 | <version>3.0.2</version> 202 | </dependency> 203 | </dependencies> 204 | </project> 205 | -------------------------------------------------------------------------------- /all/pom.xml: -------------------------------------------------------------------------------- 1 | <!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> 16 | <project xmlns="http://maven.apache.org/POM/4.0.0" 17 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 18 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 19 | <modelVersion>4.0.0</modelVersion> 20 | 21 | <!-- ====================================================================== --> 22 | <!-- P A R E N T P R O J E C T D E S C R I P T I O N --> 23 | <!-- ====================================================================== --> 24 | <parent> 25 | <groupId>com.adobe.aemforms.samples</groupId> 26 | <artifactId>forms.integration.docusign</artifactId> 27 | <version>1.0.0</version> 28 | <relativePath>../pom.xml</relativePath> 29 | </parent> 30 | 31 | <!-- ====================================================================== --> 32 | <!-- P R O J E C T D E S C R I P T I O N --> 33 | <!-- ====================================================================== --> 34 | <artifactId>forms.integration.docusign.all</artifactId> 35 | <packaging>content-package</packaging> 36 | <name>DocuSign Integration - All</name> 37 | <description>All content package for AEM Forms DocuSign Sample</description> 38 | 39 | <!-- ====================================================================== --> 40 | <!-- B U I L D D E F I N I T I O N --> 41 | <!-- ====================================================================== --> 42 | <build> 43 | <plugins> 44 | <!-- ====================================================================== --> 45 | <!-- V A U L T P A C K A G E P L U G I N S --> 46 | <!-- ====================================================================== --> 47 | <plugin> 48 | <groupId>org.apache.jackrabbit</groupId> 49 | <artifactId>filevault-package-maven-plugin</artifactId> 50 | <extensions>true</extensions> 51 | <configuration> 52 | <group>com.adobe.aemforms.samples</group> 53 | <packageType>container</packageType> 54 | <!-- skip sub package validation for now as some vendor packages like CIF apps will not pass --> 55 | <skipSubPackageValidation>true</skipSubPackageValidation> 56 | <embeddeds> 57 | <embedded> 58 | <groupId>com.adobe.aemforms.samples</groupId> 59 | <artifactId>forms.integration.docusign.ui.apps</artifactId> 60 | <type>zip</type> 61 | <target>/apps/forms.integration.docusign-packages/application/install</target> 62 | </embedded> 63 | <embedded> 64 | <groupId>com.adobe.aemforms.samples</groupId> 65 | <artifactId>forms.integration.docusign.core</artifactId> 66 | <target>/apps/forms.integration.docusign-packages/application/install</target> 67 | </embedded> 68 | <embedded> 69 | <groupId>com.adobe.aemforms.samples</groupId> 70 | <artifactId>forms.integration.docusign.ui.config</artifactId> 71 | <target>/apps/forms.integration.docusign-packages/application/install</target> 72 | </embedded> 73 | </embeddeds> 74 | </configuration> 75 | </plugin> 76 | <plugin> 77 | <groupId>com.day.jcr.vault</groupId> 78 | <artifactId>content-package-maven-plugin</artifactId> 79 | <extensions>true</extensions> 80 | <configuration> 81 | <verbose>true</verbose> 82 | <failOnError>true</failOnError> 83 | </configuration> 84 | </plugin> 85 | <plugin> 86 | <artifactId>maven-clean-plugin</artifactId> 87 | <executions> 88 | <execution> 89 | <id>auto-clean</id> 90 | <phase>initialize</phase> 91 | <goals> 92 | <goal>clean</goal> 93 | </goals> 94 | </execution> 95 | </executions> 96 | </plugin> 97 | 98 | <!-- Usage: mvn clean install -DinstallDir="<absolute path to your cloud manager project>/maven_repository" --> 99 | <!-- Ex: mvn clean install -Dinstall.dir="/Users/user/Desktop/program-name/maven_repository" --> 100 | <plugin> 101 | <groupId>org.apache.maven.plugins</groupId> 102 | <artifactId>maven-install-plugin</artifactId> 103 | <executions> 104 | <execution> 105 | <id>local-install</id> 106 | <phase>install</phase> 107 | <goals> 108 | <goal>install-file</goal> 109 | </goals> 110 | <configuration> 111 | <file>${project.build.directory}/${project.artifactId}-${project.version}.zip</file> 112 | <groupId>${project.groupId}</groupId> 113 | <artifactId>${project.artifactId}</artifactId> 114 | <version>${project.version}</version> 115 | <packaging>zip</packaging> 116 | <localRepositoryPath>${install.dir}</localRepositoryPath> 117 | </configuration> 118 | </execution> 119 | </executions> 120 | </plugin> 121 | </plugins> 122 | </build> 123 | 124 | <!-- ====================================================================== --> 125 | <!-- P R O F I L E S --> 126 | <!-- ====================================================================== --> 127 | <profiles> 128 | <profile> 129 | <id>autoInstallSinglePackage</id> 130 | <activation> 131 | <activeByDefault>false</activeByDefault> 132 | </activation> 133 | <build> 134 | <plugins> 135 | <plugin> 136 | <groupId>com.day.jcr.vault</groupId> 137 | <artifactId>content-package-maven-plugin</artifactId> 138 | <executions> 139 | <execution> 140 | <id>install-package</id> 141 | <goals> 142 | <goal>install</goal> 143 | </goals> 144 | <configuration> 145 | <targetURL>http://${aem.host}:${aem.port}/crx/packmgr/service.jsp</targetURL> 146 | <failOnError>true</failOnError> 147 | </configuration> 148 | </execution> 149 | </executions> 150 | </plugin> 151 | </plugins> 152 | </build> 153 | </profile> 154 | <profile> 155 | <id>autoInstallSinglePackagePublish</id> 156 | <activation> 157 | <activeByDefault>false</activeByDefault> 158 | </activation> 159 | <build> 160 | <plugins> 161 | <plugin> 162 | <groupId>com.day.jcr.vault</groupId> 163 | <artifactId>content-package-maven-plugin</artifactId> 164 | <executions> 165 | <execution> 166 | <id>install-package-publish</id> 167 | <goals> 168 | <goal>install</goal> 169 | </goals> 170 | <configuration> 171 | <targetURL>http://${aem.publish.host}:${aem.publish.port}/crx/packmgr/service.jsp</targetURL> 172 | <failOnError>true</failOnError> 173 | </configuration> 174 | </execution> 175 | </executions> 176 | </plugin> 177 | </plugins> 178 | </build> 179 | </profile> 180 | </profiles> 181 | 182 | <!-- ====================================================================== --> 183 | <!-- D E P E N D E N C I E S --> 184 | <!-- ====================================================================== --> 185 | <dependencies> 186 | <dependency> 187 | <groupId>com.adobe.aemforms.samples</groupId> 188 | <artifactId>forms.integration.docusign.ui.apps</artifactId> 189 | <version>${project.version}</version> 190 | <type>zip</type> 191 | </dependency> 192 | <dependency> 193 | <groupId>com.adobe.aemforms.samples</groupId> 194 | <artifactId>forms.integration.docusign.ui.config</artifactId> 195 | <version>${project.version}</version> 196 | <type>zip</type> 197 | </dependency> 198 | </dependencies> 199 | </project> 200 | -------------------------------------------------------------------------------- /core/src/main/java/com/adobe/aemforms/samples/forms/integration/docusign/core/utils/CloudConfigurationUtils.java: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | package com.adobe.aemforms.samples.forms.integration.docusign.core.utils; 17 | 18 | import com.day.cq.commons.jcr.JcrConstants; 19 | import com.google.gson.JsonObject; 20 | import com.google.gson.JsonParser; 21 | import org.apache.commons.lang3.StringUtils; 22 | import org.apache.http.*; 23 | import org.apache.http.client.entity.UrlEncodedFormEntity; 24 | import org.apache.http.client.methods.HttpPost; 25 | import org.apache.http.impl.client.CloseableHttpClient; 26 | import org.apache.http.message.BasicNameValuePair; 27 | import org.apache.http.osgi.services.HttpClientBuilderFactory; 28 | import org.apache.http.protocol.HTTP; 29 | import org.apache.http.util.EntityUtils; 30 | import org.apache.sling.api.resource.Resource; 31 | import org.apache.sling.api.resource.ResourceResolver; 32 | import org.apache.sling.api.resource.ResourceResolverFactory; 33 | import org.slf4j.Logger; 34 | import org.slf4j.LoggerFactory; 35 | 36 | import javax.jcr.RepositoryException; 37 | import javax.jcr.Session; 38 | import javax.jcr.security.AccessControlManager; 39 | import javax.jcr.security.Privilege; 40 | import java.util.*; 41 | 42 | public class CloudConfigurationUtils { 43 | 44 | static Logger logger = LoggerFactory.getLogger(CloudConfigurationUtils.class); 45 | 46 | /** 47 | * Read DocuSign cloud configuration resource from /conf 48 | */ 49 | public static Resource getConfigResource(String cqConfPath, ResourceResolverFactory resourceResolverFactory) { 50 | Resource configurationResource = null; 51 | try { 52 | ResourceResolver resolver = resourceResolverFactory.getServiceResourceResolver(null); 53 | configurationResource = resolver.getResource(cqConfPath + "/" + Constants.CONFIG_BUCKET + Constants.DOCUSIGN_CONFIGURATION_GROUP); 54 | } catch (Exception e) { 55 | logger.error("Exception occurred when reading config ", e); 56 | } 57 | return configurationResource != null ?configurationResource.getChild("jcr:content"): null; 58 | } 59 | 60 | /** 61 | * Get required tokens by invoking DocuSign Rest API call 62 | */ 63 | public static JsonObject fetchRefreshToken (HttpClientBuilderFactory httpClientBuilderFactory, String authorizationCode, String clientId, String clientSecret, String refreshTokenUri, String redirectUri, String refreshToken) { 64 | JsonObject jsonResponse = new JsonObject(); 65 | try (CloseableHttpClient httpclient = httpClientBuilderFactory.newBuilder().build()){ 66 | HttpPost httppost = new HttpPost(refreshTokenUri); 67 | httppost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded"); 68 | List<NameValuePair> params = new ArrayList<NameValuePair>(); 69 | if (authorizationCode != null) { 70 | params.add(new BasicNameValuePair(Constants.GRANT_TYPE, Constants.AUTHORIZATION_CODE)); 71 | params.add(new BasicNameValuePair(Constants.CODE, authorizationCode)); 72 | params.add(new BasicNameValuePair(Constants.REDIRECT_URI, redirectUri)); 73 | } else if (refreshToken != null) { 74 | params.add(new BasicNameValuePair(Constants.GRANT_TYPE, Constants.REFRESH_TOKEN)); 75 | params.add(new BasicNameValuePair(Constants.REFRESH_TOKEN, refreshToken)); 76 | } 77 | params.add(new BasicNameValuePair(Constants.CLIENT_ID, clientId)); 78 | if (StringUtils.isNotEmpty(clientSecret)) { 79 | params.add(new BasicNameValuePair(Constants.CLIENT_SECRET, clientSecret)); 80 | } 81 | httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); 82 | 83 | HttpResponse response = httpclient.execute(httppost); 84 | StatusLine statusLine = response.getStatusLine(); 85 | int statusCode = statusLine.getStatusCode(); 86 | HttpEntity responseEntity = response.getEntity(); 87 | if (responseEntity != null) { 88 | String result = EntityUtils.toString(responseEntity); 89 | JsonObject resultJson = new JsonParser().parse(result).getAsJsonObject(); 90 | 91 | if (statusCode == HttpStatus.SC_OK) { 92 | logger.debug("[OAuth] [DocuSign] Received following keys from OAuth server: " + resultJson.keySet().toString()); 93 | jsonResponse.addProperty(Constants.ACCESS_TOKEN, resultJson.get(Constants.ACCESS_TOKEN).getAsString()); 94 | jsonResponse.addProperty(Constants.REFRESH_TOKEN, resultJson.get(Constants.REFRESH_TOKEN).getAsString()); 95 | } else if (resultJson.has(Constants.ERROR)) { 96 | logger.error("[OAuth] [DocuSign] Error while fetching the Refresh Token: "+ resultJson.get(Constants.ERROR_DESCRIPTION).getAsString()); 97 | jsonResponse.addProperty(Constants.ERROR, resultJson.get(Constants.ERROR).getAsString()); 98 | jsonResponse.addProperty(Constants.ERROR_DESCRIPTION, resultJson.get(Constants.ERROR_DESCRIPTION).getAsString()); 99 | } else { 100 | logger.error("[OAuth] [DocuSign] Error while fetching the Refresh Token: " + statusLine.getReasonPhrase()); 101 | jsonResponse.addProperty(Constants.ERROR, Integer.toString(statusCode)); 102 | jsonResponse.addProperty(Constants.ERROR_DESCRIPTION, statusLine.getReasonPhrase()); 103 | } 104 | } else { 105 | logger.error("[OAuth] [DocuSign] Error in getting Oauth response." + statusLine.getReasonPhrase()); 106 | jsonResponse.addProperty(Constants.ERROR, Integer.toString(statusCode)); 107 | jsonResponse.addProperty(Constants.ERROR_DESCRIPTION, statusLine.getReasonPhrase()); 108 | } 109 | } 110 | catch (Exception exception) { 111 | // UnsupportedEncodingException, IOException, JSONException 112 | logger.error("[OAuth] [DocuSign] Error while fetching the Refresh Token.", exception); 113 | } 114 | return jsonResponse; 115 | } 116 | 117 | /** 118 | * Checks if the user bound to the request has the specified {@code privilege} 119 | * for the {@code path}. 120 | * 121 | * @param path Resource path to check privilege 122 | * @param privilege Privilege name 123 | * @return {@code true} if user has the privilege, {@code false} otherwise 124 | */ 125 | public static boolean hasPermission(ResourceResolver resourceResolver, String path, String privilege) { 126 | try { 127 | Session session = resourceResolver.adaptTo(Session.class); 128 | AccessControlManager acm = session != null ? session.getAccessControlManager() : null; 129 | if (acm != null && StringUtils.isNotEmpty(path) && StringUtils.isNotEmpty(privilege)) { 130 | Privilege p = acm.privilegeFromName(privilege); 131 | return acm.hasPrivileges(path, new Privilege[]{p}); 132 | } 133 | } catch (RepositoryException e) { 134 | logger.error("[Permission] Unable to verify privilege " + privilege + " for path " + path, e); 135 | } 136 | return false; 137 | } 138 | 139 | /** 140 | * Returns {@code true} if specified {@code resource} matches one of the 141 | * specified {@code resourceTypes}. 142 | * 143 | * @param resource Resource to verify 144 | * @param resourceTypes Resource types 145 | * @return {@code true} if the resource matches a resource type, 146 | * {@code false} otherwise 147 | */ 148 | public static boolean isResourceType(Resource resource, String... resourceTypes) { 149 | if (resource != null && resourceTypes != null) { 150 | for (String resourceType : resourceTypes) { 151 | Resource child = resource.getChild(JcrConstants.JCR_CONTENT); 152 | if (child != null) { 153 | resource = child; 154 | } 155 | if (resource.isResourceType(resourceType)) { 156 | return true; 157 | } 158 | } 159 | } 160 | return false; 161 | } 162 | 163 | /** 164 | * Returns {@code true} if specified {@code resource} is a configuration 165 | * container. 166 | * 167 | * @param resource Resource to verify 168 | * @return {@code true} if the resource represents a configuration 169 | * container, {@code false} otherwise 170 | */ 171 | public static boolean isConfigurationContainer(Resource resource) { 172 | return (resource != null && resource.isResourceType("sling:Folder") 173 | && !Constants.CONF_CONTAINER_BUCKET_NAME.equals(resource.getName())); 174 | } 175 | 176 | /** 177 | * Returns {@code true} if specified {@code resource} has the configuration 178 | * setting {@code settingPath}. 179 | * 180 | * @param resource Resource to verify 181 | * @param settingPath Path of the setting to check for existence 182 | * @return {@code true} if the resource has the specified setting, 183 | * {@code false} otherwise 184 | */ 185 | public static boolean hasConfigBucket(Resource resource, String settingPath) { 186 | return (resource != null && resource.getChild(settingPath) != null); 187 | } 188 | 189 | /** 190 | * Returns {@code true} if specified {@code resource} is a cloud configuration. 191 | * <p> 192 | * A resource is considered a configuration if a parent node with the bucket 193 | * name {@link Constants#CLOUD_CONFIGURATION_CONTAINER} can be found. 194 | * </p> 195 | * 196 | * @param resource Resource to verify 197 | * @return {@code true} if the resource represents a configuration, 198 | * {@code false} otherwise 199 | */ 200 | public static boolean isCloudConfiguration(Resource resource) { 201 | if (resource != null) { 202 | Resource parent = resource; 203 | 204 | do { 205 | if (Constants.CLOUD_CONFIGURATION_CONTAINER.equals(parent.getName())) { 206 | return true; 207 | } 208 | parent = parent.getParent(); 209 | } while (parent != null); 210 | } 211 | return false; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/content/docusign/.content.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | ~ Copyright 2021 Adobe 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 | <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" 18 | jcr:primaryType="cq:Page"> 19 | <properties/> 20 | <createcloudconfigwizard/> 21 | <jcr:content 22 | jcr:primaryType="nt:unstructured" 23 | jcr:title="AEM | DocuSign Cloud Configurations" 24 | sling:resourceType="granite/ui/components/shell/collectionpage" 25 | consoleId="cq-docusign-cloud-configurations" 26 | contentPath="${requestPathInfo.suffix}" 27 | currentView="${state["docusign-cloudconfig.shell.collectionpage.layoutId"].string}" 28 | modeGroup="cq-confadmin-admin-childpages" 29 | pageURITemplate="/apps/docusign/cloudConfig/content/docusign.html{+id}" 30 | targetCollection=".cq-confadmin-admin-childpages"> 31 | <redirector 32 | jcr:primaryType="nt:unstructured" 33 | sling:resourceType="granite/ui/components/coral/foundation/admin/contentchecker" 34 | allowed="^(/conf|/conf/(.*))$" 35 | path="${requestPathInfo.suffix}" 36 | redirectWhenEmpty="/apps/docusign/cloudConfig/content/docusign.html/conf"/> 37 | <head jcr:primaryType="nt:unstructured"> 38 | <clientlibs 39 | jcr:primaryType="nt:unstructured" 40 | sling:resourceType="granite/ui/components/foundation/includeclientlibs" 41 | categories="[cq.common.wcm]"/> 42 | </head> 43 | <views jcr:primaryType="nt:unstructured"> 44 | <column 45 | granite:rel="cq-confadmin-admin-childpages" 46 | jcr:primaryType="nt:unstructured" 47 | jcr:title="Column View" 48 | sling:resourceType="granite/ui/components/coral/foundation/columnview" 49 | icon="viewColumn" 50 | limit="{Long}40" 51 | loadAncestors="{Boolean}true" 52 | metaResourceType="/apps/docusign/cloudConfig/components/configurations/meta" 53 | modeGroup="cq-confadmin-admin-childpages" 54 | path="${empty requestPathInfo.suffix ? "/conf" : requestPathInfo.suffix}" 55 | previewSrc="/mnt/overlay/docusign/cloudConfig/content/docusign/createcloudconfigwizard/commons/columnpreview.html{+id}" 56 | rootPath="/conf" 57 | selectionCount="single" 58 | size="${empty requestPathInfo.selectors[1] ? "40" : requestPathInfo.selectors[1]}" 59 | src="/mnt/overlay/docusign/cloudConfig/content/docusign/jcr:content/views/column{.offset,limit}.html{+id}"> 60 | <granite:data 61 | jcr:primaryType="nt:unstructured" 62 | allowedResourceTypes="[docusign/cloudConfig/content/docusign/page]" 63 | group="docusign"/> 64 | <datasource 65 | jcr:primaryType="nt:unstructured" 66 | sling:resourceType="cq/cloudconfig/components/admin/datasources/configurations" 67 | itemResourceType="docusign/cloudConfig/components/configurations/views/column" 68 | limit="${empty requestPathInfo.selectors[1] ? "41" : requestPathInfo.selectors[1] + 1}" 69 | offset="${requestPathInfo.selectors[0]}" 70 | path="${requestPathInfo.suffix}"/> 71 | </column> 72 | <card 73 | granite:rel="cq-confadmin-admin-childpages" 74 | jcr:primaryType="nt:unstructured" 75 | jcr:title="Card View" 76 | sling:resourceType="granite/ui/components/coral/foundation/masonry" 77 | icon="viewCard" 78 | layoutId="card" 79 | limit="{Long}20" 80 | metaResourceType="/apps/docusign/cloudConfig/components/configurations/meta" 81 | modeGroup="cq-confadmin-admin-childpages" 82 | path="${requestPathInfo.suffix}" 83 | selectionCount="single" 84 | selectionMode="${state["docusign-cloudconfig.shell.collectionpage.selectionMode"].boolean}" 85 | size="${empty requestPathInfo.selectors[1] ? "20" : requestPathInfo.selectors[1]}" 86 | src="/mnt/overlay/docusign/cloudConfig/content/docusign/jcr:content/views/card{.offset,limit}.html{+id}" 87 | stateId="docusign-cloudconfig.shell.collectionpage"> 88 | <datasource 89 | jcr:primaryType="nt:unstructured" 90 | sling:resourceType="cq/cloudconfig/components/admin/datasources/configurations" 91 | itemResourceType="docusign/cloudConfig/components/configurations/views/card"/> 92 | <granite:data 93 | jcr:primaryType="nt:unstructured" 94 | allowedResourceTypes="[docusign/cloudConfig/content/docusign/page]" 95 | group="docusign"/> 96 | </card> 97 | <list 98 | granite:rel="cq-confadmin-admin-childpages" 99 | jcr:primaryType="nt:unstructured" 100 | jcr:title="List View" 101 | sling:resourceType="granite/ui/components/coral/foundation/table" 102 | icon="viewList" 103 | layoutId="list" 104 | limit="{Long}40" 105 | metaResourceType="/apps/docusign/cloudConfig/components/configurations/meta" 106 | modeGroup="cq-confadmin-admin-childpages" 107 | path="${requestPathInfo.suffix}" 108 | selectionCount="single" 109 | selectionMode="row" 110 | size="${empty requestPathInfo.selectors[1] ? "40" : requestPathInfo.selectors[1]}" 111 | sortMode="remote" 112 | src="/mnt/overlay/docusign/cloudConfig/content/docusign/jcr:content/views/list{.offset,limit}.html{+id}{?sortName,sortDir}" 113 | stateId="docusign-cloudconfig.shell.collectionpage"> 114 | <columns jcr:primaryType="nt:unstructured"> 115 | <select 116 | jcr:primaryType="nt:unstructured" 117 | select="{Boolean}true"/> 118 | <title 119 | jcr:primaryType="nt:unstructured" 120 | jcr:title="Title" 121 | sortable="{Boolean}true"/> 122 | <modified 123 | jcr:primaryType="nt:unstructured" 124 | jcr:title="Modified" 125 | sortable="{Boolean}true" 126 | sortType="date"/> 127 | </columns> 128 | <datasource 129 | jcr:primaryType="nt:unstructured" 130 | sling:resourceType="cq/cloudconfig/components/admin/datasources/configurations" 131 | itemResourceType="docusign/cloudConfig/components/configurations/views/row"/> 132 | <granite:data 133 | jcr:primaryType="nt:unstructured" 134 | allowedResourceTypes="[docusign/cloudConfig/content/docusign/page]" 135 | group="docusign"/> 136 | </list> 137 | </views> 138 | <breadcrumbs 139 | jcr:primaryType="nt:unstructured" 140 | sling:resourceType="cq/cloudconfig/components/admin/datasources/breadcrumbs" 141 | rootPath="/conf" 142 | rootTitle="Configurations"/> 143 | <actions jcr:primaryType="nt:unstructured"> 144 | <secondary jcr:primaryType="nt:unstructured"> 145 | <create 146 | granite:class="cq-confadmin-actions-createconfig-activator" 147 | jcr:primaryType="nt:unstructured" 148 | sling:resourceType="granite/ui/components/coral/foundation/collection/action" 149 | action="foundation.link" 150 | relScope="collection" 151 | target=".cq-confadmin-admin-childpages" 152 | text="Create" 153 | variant="primary"> 154 | <data 155 | jcr:primaryType="nt:unstructured" 156 | href.uritemplate="/apps/docusign/cloudConfig/content/docusign/createcloudconfigwizard/cloudservices.html{+id}"/> 157 | </create> 158 | </secondary> 159 | <selection jcr:primaryType="nt:unstructured"> 160 | <viewproperties 161 | granite:class="cq-confadmin-actions-properties-activator" 162 | jcr:primaryType="nt:unstructured" 163 | sling:resourceType="granite/ui/components/coral/foundation/collection/action" 164 | action="foundation.link" 165 | icon="infoCircle" 166 | target=".cq-confadmin-admin-childpages" 167 | text="Properties" 168 | variant="actionBar"> 169 | <data 170 | jcr:primaryType="nt:unstructured" 171 | href.uritemplate="/mnt/overlay/docusign/cloudConfig/content/docusign/properties.html{?item*}"/> 172 | </viewproperties> 173 | <publish 174 | granite:rel="cq-confadmin-actions-publish-activator" 175 | jcr:primaryType="nt:unstructured" 176 | sling:resourceType="granite/ui/components/coral/foundation/collection/action" 177 | action="cq.wcm.publish" 178 | activeSelectionCount="multiple" 179 | icon="globe" 180 | target=".cq-confadmin-admin-childpages" 181 | text="Publish" 182 | variant="actionBar"> 183 | <granite:data 184 | jcr:primaryType="nt:unstructured" 185 | foundation-mode-group="cq-confadmin-admin-childpages" 186 | foundation-mode-value="default"/> 187 | <data 188 | jcr:primaryType="nt:unstructured" 189 | referenceSrc.url="/libs/wcm/core/content/reference.json?_charset_=utf-8{&path*}" 190 | wizardSrc.uritemplate="/mnt/overlay/wcm/core/content/sites/publishpagewizard.html?_charset_=utf-8{&item*}"/> 191 | </publish> 192 | <unpublish 193 | granite:class="foundation-collection-action" 194 | granite:rel="cq-confadmin-actions-unpublish-activator" 195 | jcr:primaryType="nt:unstructured" 196 | sling:resourceType="granite/ui/components/coral/foundation/collection/action" 197 | action="cq.wcm.unpublish" 198 | icon="globeStrike" 199 | target=".cq-confadmin-admin-childpages" 200 | text="Unpublish" 201 | variant="actionBar"> 202 | <data 203 | jcr:primaryType="nt:unstructured" 204 | referenceSrc.url="/bin/wcm/references.json?_charset_=utf-8{&path*}"/> 205 | </unpublish> 206 | </selection> 207 | </actions> 208 | </jcr:content> 209 | </jcr:root> 210 | -------------------------------------------------------------------------------- /core/src/main/java/com/adobe/aemforms/samples/forms/integration/docusign/core/services/DocuSignSubmitActionService.java: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | package com.adobe.aemforms.samples.forms.integration.docusign.core.services; 17 | 18 | import com.adobe.aemforms.samples.forms.integration.docusign.core.models.CloudConfigSlingModel; 19 | import com.adobe.aemforms.samples.forms.integration.docusign.core.utils.Constants; 20 | import com.adobe.aemforms.samples.forms.integration.docusign.core.utils.CloudConfigurationUtils; 21 | import com.adobe.aemds.guide.common.GuideValidationResult; 22 | import com.adobe.aemds.guide.model.FormSubmitInfo; 23 | import com.adobe.aemds.guide.service.FormSubmitActionService; 24 | import com.adobe.aemds.guide.utils.GuideConstants; 25 | import com.adobe.aemds.guide.utils.GuideSubmitErrorCause; 26 | import com.adobe.aemds.guide.utils.GuideSubmitUtils; 27 | import com.adobe.forms.common.service.FileAttachmentWrapper; 28 | import com.adobe.granite.crypto.CryptoException; 29 | import com.adobe.granite.crypto.CryptoSupport; 30 | import com.google.gson.JsonObject; 31 | import org.apache.commons.io.IOUtils; 32 | import org.apache.commons.lang3.StringUtils; 33 | import org.apache.http.HttpResponse; 34 | import org.apache.http.HttpStatus; 35 | import org.apache.http.client.methods.HttpPost; 36 | import org.apache.http.client.utils.URIBuilder; 37 | import org.apache.http.entity.ContentType; 38 | import org.apache.http.entity.StringEntity; 39 | import org.apache.http.impl.client.CloseableHttpClient; 40 | import org.apache.http.osgi.services.HttpClientBuilderFactory; 41 | import org.apache.http.util.EntityUtils; 42 | import org.apache.sling.api.resource.*; 43 | import org.apache.sling.api.resource.ResourceResolverFactory; 44 | import org.json.JSONArray; 45 | import org.json.JSONException; 46 | import org.json.JSONObject; 47 | import org.osgi.service.component.annotations.Component; 48 | import org.osgi.service.component.annotations.Reference; 49 | import org.slf4j.Logger; 50 | import org.slf4j.LoggerFactory; 51 | 52 | import javax.servlet.http.HttpServletResponse; 53 | import java.util.*; 54 | 55 | @Component( 56 | service=FormSubmitActionService.class, 57 | immediate = true 58 | ) 59 | public class DocuSignSubmitActionService implements FormSubmitActionService { 60 | 61 | @Reference 62 | private HttpClientBuilderFactory httpClientBuilderFactory; 63 | 64 | @Reference 65 | private ResourceResolverFactory resourceResolverFactory; 66 | 67 | @Reference 68 | private CryptoSupport cryptoSupport; 69 | 70 | private static final String serviceName = "DocuSign"; 71 | 72 | private String[] to; 73 | 74 | private String subject; 75 | 76 | private HashMap<String, String> newTokens = new HashMap<>(); 77 | 78 | private static final String CONF = "cq:conf"; 79 | 80 | private static final String LOG_TEMPLATE = "[AF] [Submit] [DocuSign] {} for form {}"; 81 | 82 | protected Logger logger = LoggerFactory.getLogger(DocuSignSubmitActionService.class); 83 | 84 | @Override 85 | public String getServiceName() { 86 | return serviceName; 87 | } 88 | 89 | @Override 90 | public Map<String, Object> submit(FormSubmitInfo formSubmitInfo) { 91 | Map<String, Object> result = new HashMap<>(); 92 | result.put(GuideConstants.FORM_SUBMISSION_COMPLETE, Boolean.FALSE); 93 | Resource formContainerResource = formSubmitInfo.getFormContainerResource(); 94 | String formContainerResourcePath = formContainerResource != null ? formContainerResource.getPath() : null; 95 | logger.info(LOG_TEMPLATE, "DocuSign Service Invoked", formContainerResourcePath); 96 | 97 | /* read cloud configuration */ 98 | Resource configResource = null ; 99 | CloudConfigSlingModel configProperties = null; 100 | if (formContainerResource.getParent() != null) { 101 | ValueMap properties = formContainerResource.getParent().getValueMap(); 102 | configResource = CloudConfigurationUtils.getConfigResource(properties.get(CONF, new String()), resourceResolverFactory); 103 | configProperties = configResource != null? configResource.adaptTo(CloudConfigSlingModel.class) : null; 104 | logger.info(LOG_TEMPLATE, "DocuSign Cloud Configuration Read", configResource); 105 | } 106 | /* get new Refresh and Access token */ 107 | try { 108 | getNewTokens(configProperties); 109 | logger.info("[AF] [Submit] [DocuSign] recieved new tokens"); 110 | } 111 | catch (Exception e) { 112 | logger.error("[AF] [Submit] [DocuSign] [OAuth] Error while fetching Access token for "+ configResource + " Config Resource", e); 113 | GuideSubmitUtils.addValidationErrorToResult(result, GuideSubmitErrorCause.FORM_SUBMISSION, 114 | "Error while fetching Access token", 115 | Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); 116 | } 117 | 118 | /* Extract Required Form Data */ 119 | FileAttachmentWrapper pdfFile = formSubmitInfo.getDocumentOfRecord(); 120 | List<FileAttachmentWrapper> attachmentWrapperList = formSubmitInfo.getFileAttachments(); 121 | 122 | try (CloseableHttpClient httpclient = httpClientBuilderFactory.newBuilder().build()){ 123 | /* action configurations */ 124 | final ValueMap properties = ResourceUtil.getValueMap(formContainerResource); 125 | if (properties.containsKey("mailto")) { 126 | to = properties.get("mailto", new String[0]); 127 | } 128 | if (properties.containsKey("subject")) { 129 | subject = properties.get("subject", ""); 130 | } 131 | /* Proccess Document of Record */ 132 | byte[] pdfFileBytes = null; 133 | if (pdfFile != null) { 134 | pdfFileBytes = IOUtils.toByteArray(pdfFile.getInputStream()); 135 | } else { 136 | logger.error("[AF] [Submit] [DocuSign] Document of Record is null for form {}", formContainerResourcePath); 137 | GuideSubmitUtils.addValidationErrorToResult(result, GuideSubmitErrorCause.FORM_SUBMISSION, 138 | "Document of Record missing in submit information", 139 | Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); 140 | } 141 | 142 | /* Information required to create envelope */ 143 | JSONObject postJson = new JSONObject(); 144 | postJson.put("emailSubject",subject); 145 | postJson.put("status","sent"); 146 | postJson.put("documents", createDocument(pdfFileBytes)); 147 | postJson.put("recipients", recipientList(to)); 148 | postJson.put("attachments",attachmentList(attachmentWrapperList)); 149 | 150 | /* Request URL */ 151 | URIBuilder uriBuilder = new URIBuilder(configProperties.getRestBasepathUri()) 152 | .setPath("restapi/v2.1/accounts/"+configProperties.getAccountId()+"/envelopes"); 153 | 154 | /* Request Parameters */ 155 | StringEntity entity = new StringEntity(postJson.toString(), ContentType.APPLICATION_FORM_URLENCODED); 156 | HttpPost request = new HttpPost(uriBuilder.build()); 157 | request.setEntity(entity); 158 | request.addHeader("Content-Type", "application/json"); 159 | request.addHeader("Authorization" , "Bearer "+ newTokens.get(Constants.ACCESS_TOKEN)); 160 | 161 | /* Response Paramters */ 162 | HttpResponse response = httpclient.execute(request); 163 | int status = response.getStatusLine().getStatusCode(); 164 | if (status == HttpStatus.SC_CREATED) { 165 | result.put(GuideConstants.FORM_SUBMISSION_COMPLETE, Boolean.TRUE); 166 | if (response.getFirstHeader("Content-Type") != null && 167 | response.getFirstHeader("Content-Type").getValue().contains("application/json")) { 168 | String responseString = EntityUtils.toString(response.getEntity()); 169 | logger.info(LOG_TEMPLATE, "Http Response",responseString); 170 | } 171 | } else { 172 | /* if response is not successful, return the status code of rest URL invoked */ 173 | String errorMessage = response.getStatusLine().getReasonPhrase(); 174 | GuideValidationResult guideValidationResult = null; 175 | if ((response.getEntity() != null) && (response.getEntity().getContent() != null)) { 176 | errorMessage = IOUtils.toString(response.getEntity().getContent(), "UTF-8"); 177 | guideValidationResult = GuideSubmitUtils.getGuideValidationResultFromString(errorMessage, Integer.toString(status)); 178 | } 179 | 180 | result.put(GuideConstants.FORM_SUBMISSION_ERROR, guideValidationResult); 181 | logger.error("[AF] [Submit] [DocuSign] Couldn't post data to {} for form {}", uriBuilder, formContainerResourcePath); 182 | logger.error("[AF] [Submit] [DocuSign] HTTP Status code: {}, reason phrase is :{} for form {}", status, response.getStatusLine().getReasonPhrase(), formContainerResourcePath); 183 | logger.error("[AF] [Submit] [DocuSign] The content received from RestEndPoint is : {} for form {}", errorMessage, formContainerResourcePath); 184 | } 185 | } 186 | catch (Exception e) { 187 | logger.error(LOG_TEMPLATE,"Error in Http request",e.getMessage()); 188 | GuideSubmitUtils.addValidationErrorToResult(result, GuideSubmitErrorCause.FORM_SUBMISSION, 189 | StringUtils.isEmpty(e.getMessage()) ?"Failed to make REST call to docusign" : e.getMessage(), 190 | Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); 191 | logger.error("[AF] [Submit] [DocuSign] Failed to make REST call to DocuSign in form {}", formContainerResourcePath, e); 192 | } 193 | 194 | return result; 195 | } 196 | /* 197 | Get Access token in configuration 198 | */ 199 | private void getNewTokens(CloudConfigSlingModel configProperties) throws CryptoException, PersistenceException { 200 | JsonObject jsonResponse = null; 201 | if (configProperties != null) { 202 | jsonResponse = CloudConfigurationUtils.fetchRefreshToken(httpClientBuilderFactory, null, configProperties.getClientId(), cryptoSupport.unprotect(configProperties.getClientSecret()), configProperties.getRefreshTokenUri(),null, configProperties.getRefreshToken()); 203 | } 204 | 205 | newTokens.put(Constants.REFRESH_TOKEN, jsonResponse.get(Constants.REFRESH_TOKEN).getAsString()); 206 | newTokens.put(Constants.ACCESS_TOKEN, jsonResponse.get(Constants.ACCESS_TOKEN).getAsString()); 207 | } 208 | 209 | /* 210 | Create json representation of Form. 211 | */ 212 | private JSONArray createDocument(byte[] pdfFileBytes) { 213 | try { 214 | JSONObject documentObject = new JSONObject(); 215 | documentObject.put("documentBase64",Base64.getEncoder().encodeToString(pdfFileBytes)); 216 | documentObject.put("fileExtension", "pdf"); 217 | documentObject.put("name", "Submitted Form"); 218 | documentObject.put("documentId", "1"); 219 | 220 | return new JSONArray().put(documentObject); 221 | } 222 | catch (JSONException e) { 223 | logger.info("[AF] [Submit] [DocuSign] Form Json creation failed"); 224 | } 225 | return null; 226 | } 227 | 228 | /* 229 | Create json representation of recipient list. 230 | */ 231 | private JSONObject recipientList(String[] recipients) { 232 | try { 233 | JSONArray signersArray = new JSONArray(); 234 | for (int i = 0; i < recipients.length; i++) { 235 | JSONObject signerObject = new JSONObject(); 236 | signerObject.put("email", recipients[i]); 237 | signerObject.put("recipientId", Integer.toString(i+100)); 238 | signerObject.put("name", recipients[i].split("@")[0]); 239 | signersArray.put(signerObject); 240 | } 241 | return new JSONObject().put("signers", signersArray); 242 | } 243 | catch (JSONException e) { 244 | logger.info("[AF] [Submit] [DocuSign] Recipient Json creation failed"); 245 | } 246 | return null; 247 | } 248 | 249 | /* 250 | Create json representation of attachment list. 251 | */ 252 | private JSONArray attachmentList( List<FileAttachmentWrapper> attachmentWrapperList) { 253 | if (attachmentWrapperList != null) { 254 | try { 255 | JSONArray attachmentArray = new JSONArray(); 256 | for (int i=0; i<attachmentWrapperList.size(); i++) { 257 | byte[] fileAttachmentBytes = IOUtils.toByteArray(attachmentWrapperList.get(i).getInputStream()); 258 | JSONObject attachmentObject = new JSONObject(); 259 | attachmentObject.put("label", attachmentWrapperList.get(i).getFileNameV2()); 260 | attachmentObject.put("attachmentId", Integer.toString(i+100)); 261 | attachmentObject.put("data", Base64.getEncoder().encodeToString(fileAttachmentBytes)); 262 | attachmentArray.put(attachmentObject); 263 | } 264 | return attachmentArray; 265 | } 266 | catch (Exception e) { 267 | logger.info("[AF] [Submit] [DocuSign] Recipient Json creation failed"); 268 | } 269 | } 270 | return null; 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/components/configurations/clientlib/js/docusign.js: -------------------------------------------------------------------------------- 1 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright 2021 Adobe 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. 15 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 16 | 17 | (function (document, window, $) { 18 | "use strict"; 19 | 20 | var contentLoaded = false, 21 | errors = ['invalid_request', 'unauthorized_client', 'invalid_scope', 'access_denied', 'server_error'], 22 | errorStrorageID = "com.adobe.aemforms.docusign.error"; 23 | $(document).on("foundation-contentloaded", function (e) { 24 | if (contentLoaded) { 25 | return; 26 | } 27 | 28 | contentLoaded = true; 29 | 30 | var getParameterByName = function (name, url) { 31 | if (!url) { 32 | url = window.location.href; 33 | } 34 | name = name.replace(/[\[\]]/g, "\\$&"); 35 | 36 | var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), 37 | result = regex.exec(url); 38 | 39 | if (!result) { 40 | return null; 41 | } 42 | 43 | if (!result[2]) { 44 | return ''; 45 | } 46 | 47 | return decodeURIComponent(result[2].replace(/\+/g, " ")); 48 | }; 49 | 50 | var state = getParameterByName('state', window.location.href), 51 | code = getParameterByName('code', window.location.href), 52 | api_access_point = getParameterByName('api_access_point', window.location.href), 53 | error = getParameterByName('error', window.location.href), 54 | error_description = getParameterByName('error_description', window.location.href), 55 | otherWindow, 56 | wait = new Coral.Wait(); 57 | 58 | if (state != null && errors.indexOf(error) === -1) { 59 | window.localStorage.setItem(state, JSON.stringify({ 60 | 'code' : code, 61 | 'api_access_point' : api_access_point 62 | })); 63 | window.localStorage.removeItem(errorStrorageID); 64 | return; 65 | } else if (errors.indexOf(error) !== -1) { 66 | window.localStorage.setItem(errorStrorageID, JSON.stringify({ 67 | 'error' : error, 68 | 'error_description' : error_description 69 | })); 70 | return; 71 | } 72 | 73 | var docusignSuffix = '/settings/cloudconfigs/docusign/', 74 | $wizardForm = $('#docusign-cloudconfig-form'), 75 | $propertiesForm = $('#docusign-properties-form'); 76 | 77 | if ($propertiesForm.length !== 0) { 78 | $('#docusign-cloudconfiguration-name').prop('disabled', true); 79 | } 80 | 81 | var pollOtherWindow = function (otherWindow, state, wait) { 82 | var response = window.localStorage.getItem(state) || "{}", 83 | errorResponse = window.localStorage.getItem(errorStrorageID) || "{}", 84 | responseParams = JSON.parse(response) || {}, 85 | errorResponseParams = JSON.parse(errorResponse) || {}, 86 | code = responseParams['code'], 87 | api_access_point = "https://account-d.docusign.com/", 88 | error = errorResponseParams['error'], 89 | error_description = errorResponseParams['error_description']; 90 | 91 | if (code != null) { 92 | $("#docusign-cloudconfiguration-refresh-token-uri").val(api_access_point + "oauth/token") 93 | $('#docusign-cloudconfiguration-api-access-point').val(api_access_point); 94 | window.localStorage.removeItem(state); 95 | if (otherWindow != null) { 96 | otherWindow.close(); 97 | } 98 | window.localStorage.removeItem(errorStrorageID); 99 | 100 | // get refresh token 101 | var refreshToken = getRefreshToken(code); 102 | // if successfully got refresh token 103 | if (refreshToken != null && getAccountId() != null) { 104 | $('#docusign-cloudconfiguration-refresh-token').val(refreshToken); 105 | 106 | // display success 107 | $("#docusign-cloudconfiguration-connect-button").attr('disabled', 'disabled'); 108 | $(document.body).overlayMask('hide', wait); 109 | wait.hide(); 110 | displayAlert({ 111 | id : "docusign-cloudconfiguration-alert", 112 | variant : Coral.Alert.variant.SUCCESS, 113 | header : Granite.I18n.get("Success"), 114 | content : Granite.I18n.get("DocuSign is successfully connected") 115 | }); 116 | } else { 117 | $("#docusign-cloudconfiguration-connect-button").removeAttr('disabled'); 118 | // display error 119 | $(document.body).overlayMask('hide', wait); 120 | wait.hide(); 121 | displayAlert({ 122 | id : "docusign-cloudconfiguration-alert", 123 | variant : Coral.Alert.variant.ERROR, 124 | header : Granite.I18n.get("ERROR"), 125 | content : Granite.I18n.get("Failed to get required data") 126 | }); 127 | } 128 | } else if (errors.indexOf(error) !== -1){ 129 | window.localStorage.removeItem(errorStrorageID); 130 | otherWindow.close(); 131 | $("#docusign-cloudconfiguration-connect-button").removeAttr('disabled'); 132 | // display error 133 | $(document.body).overlayMask('hide', wait); 134 | wait.hide(); 135 | displayAlert({ 136 | id : "docusign-cloudconfiguration-alert", 137 | variant : Coral.Alert.variant.ERROR, 138 | header : Granite.I18n.get("ERROR"), 139 | content : error_description 140 | }); 141 | } else if (otherWindow.closed) { 142 | window.localStorage.removeItem(errorStrorageID); 143 | $("#docusign-cloudconfiguration-connect-button").removeAttr('disabled'); 144 | $(document.body).overlayMask('hide', wait); 145 | wait.hide(); 146 | } else { 147 | setTimeout( 148 | function () { 149 | pollOtherWindow(otherWindow, state, wait); 150 | }, 100); 151 | } 152 | }, 153 | 154 | getRefreshToken = function (code) { 155 | var refreshToken = null, 156 | client_id = $("#docusign-cloudconfiguration-client-id").val(), 157 | client_secret = $("#docusign-cloudconfiguration-client-secret").val(), 158 | redirect_uri = $('#docusign-cloudconfiguration-redirect-uri').val(), 159 | refreshTokenUrl = $("#docusign-cloudconfiguration-refresh-token-uri").val(); 160 | $.ajax({ 161 | type : "GET", 162 | url : Granite.HTTP.externalize("/apps/docusign/cloudConfig/content/docusign/createcloudconfigwizard/cloudservices/oauthcloudconfigservlet.json"), 163 | async : false, 164 | data : { 165 | "client_id" : client_id, 166 | "client_secret" : client_secret, 167 | "redirect_uri" : redirect_uri, 168 | "refresh_token_uri" : refreshTokenUrl, 169 | "code" : code 170 | }, 171 | cache : false 172 | }).done(function (data, textStatus, jqXHR) { 173 | if (data && data.refresh_token) { 174 | refreshToken = data.refresh_token; 175 | $('#docusign-cloudconfiguration-access-token').val(data.access_token); 176 | } 177 | }).fail(function (jqXHR, textStatus, errorThrown) { 178 | 179 | }); 180 | 181 | return refreshToken; 182 | }, 183 | 184 | // get account id in the DocuSign userInfo api by using access token 185 | getAccountId = function () { 186 | var accounts = null, 187 | accessToken = $('#docusign-cloudconfiguration-access-token').val(), 188 | apiAccessPoint = $('#docusign-cloudconfiguration-api-access-point').val(); 189 | 190 | $.ajax({ 191 | type : "GET", 192 | url : apiAccessPoint + "oauth/userinfo", 193 | async : false, 194 | headers : { 195 | "Authorization" : "Bearer " + accessToken 196 | }, 197 | cache : false 198 | }).done(function (data, textStatus, jqXHR) { 199 | if (data && (data.accounts.length != 0) ) { 200 | accounts = data.accounts; 201 | for (var i=0; i< accounts.length; i++) { 202 | if (accounts[i].hasOwnProperty("is_default")) { 203 | if (accounts[i].is_default === true) { 204 | $("#docusign-cloudconfiguration-account-id").val(accounts[i].account_id); 205 | $("#docusign-cloudconfiguration-base-uri").val(accounts[i].base_uri); 206 | } 207 | } 208 | } 209 | } 210 | }).fail(function (jqXHR, textStatus, errorThrown) { 211 | return null; 212 | }); 213 | 214 | return accounts; 215 | 216 | }, 217 | 218 | /* Returns true if a config is already present 219 | (one can create only single cloud configuration per configuration container) */ 220 | configAlreadyExists = function (configName, configContainer) { 221 | var result = $.ajax({ 222 | type : 'GET', 223 | async : false, 224 | url : Granite.HTTP.externalize(encodeURI(configContainer) + ".1.json"), 225 | cache : false 226 | }); 227 | 228 | if (result.status != 200) { 229 | return false; 230 | } 231 | 232 | if (result.responseText != null && result.responseText != "") { 233 | var nodeList = JSON.parse(result.responseText); 234 | for (var i in nodeList) { 235 | if (configName === i) { 236 | return true; 237 | } 238 | } 239 | } 240 | 241 | return false; 242 | }, 243 | 244 | displayAlert = function (options) { 245 | // remove existing alert if any 246 | $('#' + options.id).remove(); 247 | 248 | // create new alert and append it to alert-container 249 | var $alert = new Coral.Alert(); 250 | $('#docusign-cloudconfiguration-alert-container').append($alert); 251 | $alert.set({ 252 | id : options.id, 253 | variant : options.variant, 254 | header : { 255 | innerHTML : options.header 256 | }, 257 | content : { 258 | innerHTML : options.content 259 | } 260 | }); 261 | 262 | // show alert 263 | $alert.show(); 264 | }, 265 | 266 | displayError = function (errorMessage) { 267 | var $errorElement = $('#docusign-cloudconfiguration-error-message'); 268 | $errorElement.text(errorMessage); 269 | 270 | $('#docusign-common-dialog').adaptTo('foundation-toggleable').show(); 271 | $errorElement.removeAttr('hidden'); 272 | $('#docusign-cloudconfiguration-already-exist-message').attr('hidden'); 273 | }, 274 | 275 | submitForm = function ($form, url) { 276 | $.ajax({ 277 | type : $form.prop("method"), 278 | url : url, 279 | data : $form.serialize(), 280 | cache : false, 281 | contentType : $form.prop("enctype") 282 | }).done(function (data, textStatus, jqXHR) { 283 | var configurationContainer = url.substring(url.indexOf("/conf/"), url.indexOf("/settings/")); 284 | window.location.href = Granite.HTTP.externalize("/apps/docusign/cloudConfig/content/docusign.html" + configurationContainer); 285 | }).fail(function (jqXHR, textStatus, errorThrown) { 286 | displayError(errorThrown); 287 | }); 288 | }, 289 | 290 | isRestricted = function (charCode, keyCode) { 291 | if (charCode == 0 && (keyCode == 8 || keyCode == 9 || keyCode > 36 && keyCode < 47)) { //37-46 insert/delete/arrow keys 292 | return false; 293 | } 294 | if ((charCode > 47 && charCode < 58) // 0-9 digits 295 | || (charCode > 64 && charCode < 91) // A-Z 296 | || (charCode > 96 && charCode < 123) // a-z 297 | || (charCode == 45) || (charCode == 95)) { // '-' and '_' 298 | return false; 299 | } else { 300 | return true; 301 | } 302 | }, 303 | 304 | replaceRestrictedCodes = function (value) { 305 | if (value) { 306 | return value.replace(/[^0-9a-z-_]/ig, "-"); 307 | } 308 | }; 309 | 310 | // for IE9 case special handling of del key and backspace key as IE9 doesn't 311 | // trigger input event on pressing these keys. 312 | $(document).on("keyup", "#docusign-cloudconfiguration-name" + "," + "#docusign-cloudconfiguration-title", function (e) { 313 | var specialKeys = [8, 46]; // 8 - backspace & 46 - delete 314 | if (e.keyCode) { 315 | for (var i = 0; i < specialKeys.length; i++) { 316 | if (specialKeys[i] === e.keyCode) { 317 | $(this).trigger("input"); 318 | } 319 | } 320 | } 321 | }); 322 | 323 | $(document).on("keypress", "#docusign-cloudconfiguration-name", function (e) { 324 | if (isRestricted(e.charCode, e.keyCode)) { 325 | e.preventDefault(); 326 | } 327 | }); 328 | 329 | $(document).on('input change', '#docusign-cloudconfiguration-title', function(event) { 330 | var configName = $('#docusign-cloudconfiguration-name'), 331 | altered = configName.data('altered'), 332 | title = replaceRestrictedCodes($(this).val()).toLowerCase(); 333 | 334 | configName.data('title-value', title); 335 | 336 | if (!altered && !configName.attr('disabled')) { 337 | configName.val(title); 338 | configName.trigger('change'); 339 | } 340 | }); 341 | 342 | $(document).on('input', '#docusign-cloudconfiguration-name', function(event) { 343 | var value = $(this).val(), 344 | title = $(this).data('title-value'); 345 | 346 | $(this).val(replaceRestrictedCodes(value)); 347 | 348 | $(this).data('altered', title != value); 349 | }); 350 | 351 | $('#docusign-cloudconfiguration-connect-button').on('click', function (e) { 352 | e.preventDefault(); 353 | e.stopPropagation(); 354 | 355 | var redirectURL = window.location.protocol + "//" + window.location.host + window.location.pathname, 356 | clientId = $('#docusign-cloudconfiguration-client-id').val(), 357 | scope = $("#docusign-cloudconfiguration-authorization-scope").val(), 358 | $refreshToken = $('#docusign-cloudconfiguration-refresh-token'), 359 | redirectUri = $('#docusign-cloudconfiguration-redirect-uri').val() || redirectURL, 360 | oAuthUrl = $('#docusign-cloudconfiguration-oauth-url').val(), 361 | state = Math.random(); 362 | 363 | oAuthUrl = oAuthUrl + "?response_type=code" + 364 | "&client_id=" + encodeURI(clientId) + 365 | "&redirect_uri=" + encodeURI(redirectUri) + 366 | "&scope=" + encodeURI(scope) + 367 | "&state=" + encodeURI(state); 368 | 369 | $("#docusign-cloudconfiguration-connect-button").attr('disabled', 'disabled'); 370 | 371 | // clear Refresh Token before reconnecting 372 | $refreshToken.val(""); 373 | 374 | // set redirect uri, it may be empty 375 | $('#docusign-cloudconfiguration-redirect-uri').val(redirectUri); 376 | 377 | otherWindow = window.open(oAuthUrl, '_blank'); 378 | $(document.body).overlayMask('show', wait); 379 | wait.centered = true; 380 | wait.size = "L"; 381 | pollOtherWindow(otherWindow, state, wait); 382 | setTimeout(function () { 383 | $("#docusign-cloudconfiguration-connect-button").removeAttr('disabled'); 384 | $(document.body).overlayMask('hide', wait); 385 | wait.hide(); 386 | }, 300000); 387 | }); 388 | 389 | $('#docusign-cloudconfig-form-create-button').on('click', function (e) { 390 | e.preventDefault(); 391 | e.stopPropagation(); 392 | 393 | var configName = "docusign"; 394 | if (configAlreadyExists(configName, $wizardForm.prop('action') + docusignSuffix)) { 395 | $('#docusign-common-dialog').adaptTo('foundation-toggleable').show(); 396 | $('#docusign-cloudconfiguration-already-exist-message').removeAttr('hidden'); 397 | $('#docusign-cloudconfiguration-error-message').attr('hidden'); 398 | return; 399 | } 400 | 401 | // ajax request to save the Site Key and Secret Key. 402 | var submitUrl = Granite.HTTP.externalize($wizardForm.prop('action') + docusignSuffix + configName + '/jcr:content'); 403 | submitForm($wizardForm, submitUrl); 404 | }); 405 | 406 | $('.granite-form-saveactivator').on('click', function (e) { 407 | e.preventDefault(); 408 | e.stopPropagation(); 409 | 410 | var helper = $propertiesForm.adaptTo("foundation-validation-helper"); 411 | if (helper.isValid()) { 412 | var submitUrl = Granite.HTTP.externalize($propertiesForm.prop('action')); 413 | submitForm($propertiesForm, submitUrl); 414 | } else { 415 | helper.getSubmittables().forEach(function (field) { 416 | $(field).adaptTo("foundation-validation").updateUI(); 417 | }); 418 | displayError(Granite.I18n.get("There are errors on the form")); 419 | } 420 | }); 421 | 422 | $(window).adaptTo("foundation-registry").register("foundation.validation.validator", { 423 | selector : "[data-foundation-validation~='docusign.cloud.config'],[data-validation~='docusign.cloud.config']", 424 | validate : function (element) { 425 | var length = element.value.length; 426 | 427 | if (length === 0) { 428 | return Granite.I18n.get("The field is mandatory"); 429 | } else { 430 | return; 431 | } 432 | } 433 | }); 434 | }); 435 | })(document, window, Granite.$); 436 | -------------------------------------------------------------------------------- /ui.apps/src/main/content/jcr_root/apps/docusign/cloudConfig/content/docusign/createcloudconfigwizard/cloudservices/.content.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | ~ Copyright 2021 Adobe 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 | <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" 18 | jcr:primaryType="cq:Page"> 19 | <jcr:content 20 | jcr:primaryType="nt:unstructured" 21 | jcr:title="Create DocuSign Configuration" 22 | sling:resourceType="cq/gui/components/siteadmin/admin/createpagewizard/page"> 23 | <head jcr:primaryType="nt:unstructured"> 24 | <viewport 25 | jcr:primaryType="nt:unstructured" 26 | sling:resourceType="granite/ui/components/coral/foundation/admin/page/viewport"/> 27 | <favicon 28 | jcr:primaryType="nt:unstructured" 29 | sling:resourceType="granite/ui/components/coral/foundation/page/favicon"/> 30 | <clientlibs 31 | jcr:primaryType="nt:unstructured" 32 | sling:resourceType="granite/ui/components/coral/foundation/includeclientlibs" 33 | categories="[coralui3,cq.siteadmin.common,granite.ui.coral.foundation,cq.widgets,form.integration.docusign]"/> 34 | </head> 35 | <body 36 | jcr:primaryType="nt:unstructured" 37 | sling:resourceType="granite/ui/components/coral/foundation/page/body"> 38 | <items jcr:primaryType="nt:unstructured"> 39 | <form 40 | granite:class="cq-confadmin-create-docusign-config-item" 41 | granite:comment="We set "novalidate" = true as the wizard is doing validation already, to avoid double validation" 42 | granite:id="docusign-cloudconfig-form" 43 | jcr:primaryType="nt:unstructured" 44 | sling:resourceType="granite/ui/components/coral/foundation/form" 45 | action="${requestPathInfo.suffix}" 46 | autosubmitForm="{Boolean}false" 47 | foundationForm="{Boolean}true" 48 | maximized="{Boolean}true" 49 | method="post" 50 | novalidate="{Boolean}false" 51 | style="vertical"> 52 | <items jcr:primaryType="nt:unstructured"> 53 | <charset 54 | jcr:primaryType="nt:unstructured" 55 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 56 | name="_charset_" 57 | value="utf-8"/> 58 | <resourceType 59 | jcr:primaryType="nt:unstructured" 60 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 61 | name="./sling:resourceType" 62 | value="docusign/cloudConfig/content/docusign/page"/> 63 | <jcrcontent 64 | jcr:primaryType="nt:unstructured" 65 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 66 | name="./jcr:primaryType" 67 | value="cq:PageContent"/> 68 | <nodetype 69 | jcr:primaryType="nt:unstructured" 70 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 71 | ignoreData="{Boolean}true" 72 | name="../jcr:primaryType" 73 | value="cq:Page"/> 74 | <wizard 75 | jcr:primaryType="nt:unstructured" 76 | jcr:title="Create DocuSign Configuration" 77 | sling:resourceType="granite/ui/components/coral/foundation/wizard" 78 | cancelHref="${empty header.Referer ? granite:url(granite:concat("/apps/docusign/cloudConfig/content/docusign.html", granite:encodeURIPath(requestPathInfo.suffix))) : header.Referer}"> 79 | <items jcr:primaryType="nt:unstructured"> 80 | <general 81 | granite:class="general" 82 | jcr:primaryType="nt:unstructured" 83 | jcr:title="General" 84 | sling:resourceType="granite/ui/components/coral/foundation/container" 85 | maximized="{Boolean}true"> 86 | <items jcr:primaryType="nt:unstructured"> 87 | <fixedcolumns 88 | jcr:primaryType="nt:unstructured" 89 | sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns" 90 | maximized="{Boolean}true"> 91 | <items jcr:primaryType="nt:unstructured"> 92 | <container 93 | granite:class="properties" 94 | jcr:primaryType="nt:unstructured" 95 | sling:resourceType="granite/ui/components/coral/foundation/container"> 96 | <items jcr:primaryType="nt:unstructured"> 97 | <general 98 | jcr:primaryType="nt:unstructured" 99 | sling:resourceType="granite/ui/components/coral/foundation/form/fieldset"> 100 | <items jcr:primaryType="nt:unstructured"> 101 | <title 102 | granite:id="docusign-cloudconfiguration-title" 103 | jcr:primaryType="nt:unstructured" 104 | sling:resourceType="granite/ui/components/coral/foundation/form/textfield" 105 | fieldLabel="Title" 106 | name="./jcr:title"/> 107 | <name 108 | granite:id="docusign-cloudconfiguration-name" 109 | jcr:primaryType="nt:unstructured" 110 | sling:resourceType="granite/ui/components/coral/foundation/form/textfield" 111 | fieldLabel="Name" 112 | name="./name" 113 | required="{Boolean}true" 114 | validation="[foundation.jcr.name,docusign.cloud.config]"/> 115 | </items> 116 | </general> 117 | </items> 118 | </container> 119 | </items> 120 | </fixedcolumns> 121 | </items> 122 | <parentConfig jcr:primaryType="nt:unstructured"> 123 | <next 124 | granite:class="foundation-wizard-control" 125 | jcr:primaryType="nt:unstructured" 126 | sling:resourceType="granite/ui/components/coral/foundation/button" 127 | disabled="{Boolean}true" 128 | text="Next" 129 | variant="primary"> 130 | <granite:data 131 | jcr:primaryType="nt:unstructured" 132 | foundation-wizard-control-action="next"/> 133 | </next> 134 | </parentConfig> 135 | </general> 136 | <settings 137 | jcr:primaryType="nt:unstructured" 138 | jcr:title="Settings" 139 | sling:resourceType="granite/ui/components/coral/foundation/container" 140 | maximized="{Boolean}true"> 141 | <items jcr:primaryType="nt:unstructured"> 142 | <fixedcolumns 143 | jcr:primaryType="nt:unstructured" 144 | sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns" 145 | maximized="{Boolean}true"> 146 | <items jcr:primaryType="nt:unstructured"> 147 | <container 148 | granite:class="properties" 149 | jcr:primaryType="nt:unstructured" 150 | sling:resourceType="granite/ui/components/coral/foundation/container"> 151 | <items jcr:primaryType="nt:unstructured"> 152 | <oAuthUrl 153 | granite:id="docusign-cloudconfiguration-oauth-url" 154 | jcr:primaryType="nt:unstructured" 155 | sling:resourceType="granite/ui/components/coral/foundation/form/textfield" 156 | fieldLabel="OAuth URL" 157 | name="./oAuthUrl" 158 | required="{Boolean}true" 159 | validation="docusign.cloud.config" 160 | value="https://account-d.docusign.com/oauth/auth"/> 161 | <clientId 162 | granite:id="docusign-cloudconfiguration-client-id" 163 | jcr:primaryType="nt:unstructured" 164 | sling:resourceType="granite/ui/components/coral/foundation/form/textfield" 165 | fieldLabel="Client Id" 166 | name="./client_id" 167 | required="{Boolean}true" 168 | validation="docusign.cloud.config"/> 169 | <clientSecret 170 | granite:id="docusign-cloudconfiguration-client-secret" 171 | jcr:primaryType="nt:unstructured" 172 | sling:resourceType="granite/ui/components/coral/foundation/form/password" 173 | autocomplete="off" 174 | fieldLabel="Client Secret" 175 | ignoreData="{Boolean}true" 176 | name="./client_secret" 177 | required="{Boolean}true" 178 | validation="docusign.cloud.config"/> 179 | <encryptedClientSecret 180 | granite:id="docusign-cloudconfiguration-client-secret-encrypted" 181 | jcr:primaryType="nt:unstructured" 182 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 183 | ignoreData="{Boolean}false" 184 | name="./client_secret@Encrypted"/> 185 | <connectButton 186 | granite:class="foundation-validation-bind" 187 | granite:id="docusign-cloudconfiguration-connect-button" 188 | jcr:primaryType="nt:unstructured" 189 | sling:resourceType="granite/ui/components/coral/foundation/button" 190 | disabled="{Boolean}true" 191 | name="connectButton" 192 | text="Connect to DocuSign" 193 | type="button" 194 | variant="secondary"/> 195 | <defaultValuesContainer 196 | jcr:primaryType="nt:unstructured" 197 | sling:resourceType="granite/ui/components/coral/foundation/container"> 198 | <items jcr:primaryType="nt:unstructured"> 199 | <refreshtokenuri 200 | granite:id="docusign-cloudconfiguration-refresh-token-uri" 201 | jcr:primaryType="nt:unstructured" 202 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 203 | fieldLabel="Refresh token URL" 204 | name="./refresh_token_uri"/> 205 | <accesstoken 206 | granite:id="docusign-cloudconfiguration-access-token" 207 | jcr:primaryType="nt:unstructured" 208 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 209 | ignoreData="{Boolean}true" 210 | name="./access_token"/> 211 | <apiaccesspoint 212 | granite:id="docusign-cloudconfiguration-api-access-point" 213 | jcr:primaryType="nt:unstructured" 214 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 215 | fieldLabel="API Access Point" 216 | name="./api_access_point"/> 217 | <redirecturi 218 | granite:id="docusign-cloudconfiguration-redirect-uri" 219 | jcr:primaryType="nt:unstructured" 220 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 221 | fieldLabel="Redirect URI (same as configuration URL)" 222 | name="./redirect_uri"/> 223 | <refreshtoken 224 | granite:id="docusign-cloudconfiguration-refresh-token" 225 | jcr:primaryType="nt:unstructured" 226 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 227 | ignoreData="{Boolean}true" 228 | name="./refresh_token"/> 229 | <authorizationscope 230 | granite:id="docusign-cloudconfiguration-authorization-scope" 231 | jcr:primaryType="nt:unstructured" 232 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 233 | fieldLabel="Authorization Scope" 234 | name="./authorization_scope" 235 | value="signature"/> 236 | <accountid 237 | granite:id="docusign-cloudconfiguration-account-id" 238 | jcr:primaryType="nt:unstructured" 239 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 240 | ignoreData="{Boolean}true" 241 | name="./account_id"/> 242 | <baseuri 243 | granite:id="docusign-cloudconfiguration-base-uri" 244 | jcr:primaryType="nt:unstructured" 245 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 246 | ignoreData="{Boolean}true" 247 | name="./base_uri"/> 248 | </items> 249 | </defaultValuesContainer> 250 | <alert 251 | granite:id="docusign-cloudconfiguration-alert-container" 252 | jcr:primaryType="nt:unstructured" 253 | sling:resourceType="granite/ui/components/coral/foundation/container"/> 254 | </items> 255 | </container> 256 | </items> 257 | </fixedcolumns> 258 | </items> 259 | <parentConfig jcr:primaryType="nt:unstructured"> 260 | <prev 261 | granite:class="foundation-wizard-control" 262 | jcr:primaryType="nt:unstructured" 263 | sling:resourceType="granite/ui/components/coral/foundation/button" 264 | text="Back"> 265 | <granite:data 266 | jcr:primaryType="nt:unstructured" 267 | foundation-wizard-control-action="prev"/> 268 | </prev> 269 | <next 270 | granite:class="foundation-wizard-control" 271 | granite:id="docusign-cloudconfig-form-create-button" 272 | jcr:primaryType="nt:unstructured" 273 | sling:resourceType="granite/ui/components/coral/foundation/button" 274 | disabled="{Boolean}true" 275 | text="Create" 276 | type="submit" 277 | variant="primary"> 278 | <granite:data 279 | jcr:primaryType="nt:unstructured" 280 | foundation-wizard-control-action="next" 281 | foundation-wizard-step-validation="{Boolean}true"/> 282 | </next> 283 | </parentConfig> 284 | </settings> 285 | </items> 286 | </wizard> 287 | <commondialog 288 | granite:id="docusign-common-dialog" 289 | jcr:primaryType="nt:unstructured" 290 | jcr:title="Error" 291 | sling:resourceType="granite/ui/components/coral/foundation/dialog" 292 | closable="{Boolean}true" 293 | variant="error"> 294 | <items jcr:primaryType="nt:unstructured"> 295 | <existmessage 296 | granite:hidden="{Boolean}true" 297 | granite:id="docusign-cloudconfiguration-already-exist-message" 298 | jcr:primaryType="nt:unstructured" 299 | sling:resourceType="granite/ui/components/coral/foundation/text" 300 | text="Configuration already exist."/> 301 | <errormessage 302 | granite:hidden="{Boolean}true" 303 | granite:id="docusign-cloudconfiguration-error-message" 304 | jcr:primaryType="nt:unstructured" 305 | sling:resourceType="granite/ui/components/coral/foundation/text" 306 | text=""/> 307 | </items> 308 | <footer jcr:primaryType="nt:unstructured"> 309 | <ok 310 | jcr:primaryType="nt:unstructured" 311 | sling:resourceType="granite/ui/components/coral/foundation/button" 312 | text="Ok"> 313 | <parentConfig 314 | jcr:primaryType="nt:unstructured" 315 | close="{Boolean}true"/> 316 | </ok> 317 | </footer> 318 | </commondialog> 319 | <lastmodified 320 | jcr:primaryType="nt:unstructured" 321 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 322 | name="./jcr:lastModified"/> 323 | <lastmodifiedby 324 | jcr:primaryType="nt:unstructured" 325 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 326 | name="./jcr:lastModifiedBy"/> 327 | <groupnametype 328 | jcr:primaryType="nt:unstructured" 329 | sling:resourceType="granite/ui/components/coral/foundation/form/hidden" 330 | name="../../jcr:primaryType" 331 | value="sling:Folder"/> 332 | </items> 333 | </form> 334 | </items> 335 | </body> 336 | </jcr:content> 337 | <oauthcloudconfigservlet 338 | jcr:primaryType="nt:unstructured" 339 | sling:resourceType="docusign/cloudconfig/oauthservlet"/> 340 | </jcr:root> 341 | --------------------------------------------------------------------------------